ディスクの暗号化

TMP(Trusted Platform Module)はパソコンやスマートフォンに組み込まれているセキュリティ専用チップ
TMPはTCGが定めていて、TMP2.0は標準規格になっている
XTS-AESはブロック暗号AESを使った暗号方法の一つで、WindowsのBitLocker, macOSのFileVault2, Linuzのdm-cryptなどディスク暗号化ソフトウェアで利用される

安全に暗号通信するには平文の情報を漏らさないだけでなく暗号文の改竄攻撃も想定しなければならない

確率的アルゴリズムと暗号化モード(ECBとCBC)

確率的アルゴリズムは安全な暗号文を作るために必要
暗号を繰り返し使って安全であるためには、同じ平文を暗号化して毎回異なる暗号文にならないといけない
EBCモードで暗号化すると、16バイトずつ暗号化しているので同じパターンが現れると同じ暗号データになってしまう
-> CBCモードでの暗号化が開発された
-> 同じ値を出力するのを決定的アルゴリズムという。一方、毎回異なる出力をするアルゴリズムを確率的アルゴリズム(CBCモード)という

### ECB(Electronic CodeBook)モード
平文をブロックに分割し、それぞれを暗号化して暗号文を作る方式

### CBC(Cipher Block Chaining)モード
CBCモードは平文をそのまま暗号化するのではなく、一つ前の暗号文ブロックと排他的論理和をとってから暗号化する
先頭の平文ブロックには一つ前の暗号文が無いので初期化ベクトルを用いる

### CTR(CounTeR)モード
ブロック暗号を使って擬似乱数を生成し、ストリーム暗号として利用するモード

CBCモードは大きな平文があった時にそれを分割して複数CPUを使って暗号化を並列処理することはできない
CTRモードは各暗号文が独立なので複数CPUを使って並列処理できる

CBCモードは以前はよく使われていたが最近は避けられる傾向にある
サーバは暗号に関するエラー情報を不用意に返さないようにする

ブロック暗号(AES)

平文をある決まったサイズに分割し、その分割した固まりごとに暗号化する方法
端数があれば、パディングと呼ばれる方法で一つのブロックを作って処理する
ブロックごとに暗号化モードに応じた処理を行う

1970年にDESと呼ばれるブロック暗号が使われていた(64ビット、鍵長は56ビット)
DESに変わる標準的暗号としてAES(Advanced Encryption Standard)が選出された

### AES概要
AESブロックは128ビットで鍵長は128, 192, 256ビットを選べる
AESの暗号化は、秘密鍵の初期設定後(AddRoundKey)、ラウンド関数と呼ばれる処理を一定回数繰り返す 
最後に最終ラウンド関数と呼ばれる処理をして暗号化が完了する
ラウンド関数は鍵長に応じて9、11、13回行う。鍵長が大きいほど処理に時間がかかる
AESが理想的なブロック暗号なら全数探索のO(2^128)の計算コストがかかる

1. RoundKeyを作成する
2. 128ビットである1ブロックを8ビットずつの16個のデータX0からX15に分割する
3. 4×4のマス目の正方形に入れる
4. Roudkeyとマス目のデータの排他的論理和を取る

### ラウンド関数
ラウンド関数はSubBytes, ShiftRows, MixColumnsとAddRoundKeyを順番に処理する
L SubBytesはS -Boxという換字表による換字式暗号を行う
ShiftRows: 横の列ごとデータを左にずらす
MixColumns: 縦の列ごとにある決められた行列Aを掛ける演算をする(行列の成分)
最終ラウンド関数: MixColumnsを除いたSubByte, ShiftRows, AddRoundKeyの処理をする
AES-NI: IntelやAMDのCPUに搭載されているAESを高速処理するための専用命令 ARMアーキテクチャでも同様の専用命令を搭載していることがある

// 鍵
$key = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
// 初期ベクトル
$iv = 'bbbbbbbbbbbbbbbb';
$str = 'hello world';

// 暗号化
$str = openssl_encrypt($str, 'AES-256-CBC', $key, 0, $iv);
echo "${str}\n";

// 複合する
$str = openssl_decrypt($str, 'AES-256-CBC', $key, 0, $iv);
echo "${str}\n";

$ php index.php
9due8hN1Y3j3t6sx/WnryA==
hello world

PHP Extension ChaCha20 Encryption

include("chilkat_9_5_0.php");

$crypt = new CkCrypt2();

$crypt->put_CryptAlgorithm('chacha20');
$crypt->put_KeyLength(256);

$crypt->put_EncodingMode('hex');

$ivHex = '000000000000000000000002';
$crypt->SetEncodedIV($ivHex, 'hex');

$crypt->put_InitialCount(42);
$keyHex = '1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0';
$crypt->SetEncodedKey($keyHex, 'hex');

$plainText = ''Twas brillig, and the slithy toves\nDid gyre and gimble in the wabe:\nAll mimsy were the borogoves,\nAnd the mome raths outgrabe.'';

$encStr = $crypt->ecnryptStringENC($plainText);
print $encStr . "\n";

$decStr = $crypt->decryptStringENC($encStr);
print $decStr . "\n";

PHPのワンタイムパッド

// 暗号化したい文字列
$str = "保つのに時があり,捨てるのに時がある。";

// ワンタイムパッド
$pad = [
  12,20,148,22,87,91,239,187,206,215,103,207,192,46,75,243,
  204,61,121,210,145,167,108,78,166,129,109,239,138,134,150,196,
  217,63,158,201,204,66,181,198,54,0,0,130,163,212,57,167,
  169,115,170,50,109,116,173,177,252,242,233,3,33,28,139,73,
];

function convert($str, $pad){
	$res = "";
	for($i=0; $i<strlen($str); $i++) {
		$c = ord(substr($str, $i, 1));
		$cx = $c ^ $pad[$i];

		$res .= chr($cx);
	}
	return $res;
}

$enc = convert($str, $pad);
echo "暗号化した文字列:{$enc}\n";

$dec = convert($enc, $pad);
echo "復号化した文字列:{$dec}\n";

PHPの乱数

for ($i = 0; $i < 10; $i++){
	print(mt_rand().'<br>');
}

for ($i = 0; $i < 10; $i++){
	print(mt_rand(1, 6).'<br>');
}

1772070118
2025234455
909739598
265570849
205762700
1249037110
503159177
1157558449
1270711055
1797668593
5
3
1
4
3
2
4
3
2
6

PHPの論理和、論理積、排他的論理和

論理積 and
論理和 or
排他的論理和 xor
否定 !
論理積 &&
論理和 ||

if(TRUE and TRUE) echo "結果はTRUEです。<br>\n"; else echo "結果はFALSEです。<br>\n";

$a = 1;
$b = 2;
if(($a === 1) and ($b === 2)) echo "結果はTRUEです。<br>\n"; else echo "結果はFALSEです。<br>\n";


if(TRUE and FALSE) echo "結果はTRUEです。<br>\n"; else echo "結果はFALSEです。<br>\n";

$a = 1;
$b = 2;
if(($a === 1) and ($b === -2)) echo  "結果はTRUEです。<br>\n"; else echo "結果はFALSEです。<br>\n";


if(TRUE or FALSE) echo "結果はTRUEです。<br>\n"; else echo "結果はFALSEです。<br>\n";

$a = 1;
$b = 2;
if(($a === 1) or ($b === -2)) echo "結果はTRUEです。<br>\n"; else echo "結果はFALSEです。<br>\n";

// 片方TRUEで両方TRUEではない
if(TRUE xor FALSE) echo  "結果はTRUEです。<br>\n"; else echo "結果はFALSEです。<br>\n";

$a = 1;
$b = 2;
if(($a  + $b === 3) xor ($b - $a === -1)) echo "結果はTRUEです。<br>\n"; else echo "結果はFALSEです。<br>\n";


// 否定
if(!FALSE) echo "結果はTRUEです。<br>\n"; else echo "結果はFALSEです。<br>\n";

$a = 1;
$b = 2;
if(!($a + $b === -3)) echo "結果はTRUEです。<br>\n"; else echo "結果はFALSEです。<br>\n";

PHPで共通鍵暗号を使った暗号化・復号化

$data = 'あいうえおかきくけこさしすせそ';

$ciphers = openssl_get_cipher_methods();
print_r($ciphers);

$method = 'AES-256-CBC';

$iv_length = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($iv_length);

$option = 0;

$encrypted = openssl_encrypt($data, $method, $password, $options, $iv);
echo "暗号文": .$encrypted . "\n";

$decrypted = openssl_decrypt($ecnrypted, $method, $password, $options, $iv);
echo "平文" . $decrypted . "\n";

ストリーム暗号

ストリーム暗号は擬似乱数生成器を使うことでワンタイムパッドの問題を解決した共通鍵暗号
事前に共有すべき秘密鍵はシードだけで済む。そのような共通鍵暗号をストリーム暗号という
ただし、擬似乱数生成器では生成できない値が存在する
計算量的安全性を持つ
1987年にRC4が設計されたが平文解読攻撃が提案された。2008年にバーンスタインがChaCha20と呼ばれるストリーム暗号を開発
Intel CPUやARMの一部CPUでAES専用のハードウェア支援機構があり高速に処理されるがモバイルや組み込み環境ではChaCha20のほうがAESより高速
秘密鍵と一緒にnonceと呼ばれる値を擬似ランダム関数に入力することで繰り返し利用できる

ChaCha20
ChaCha20は256ビットの秘密鍵と96ビットのナンスを元に512ビットずつの擬似乱数を生成する
  生成した乱数と平文の排他的論理和をとって暗号文にするストリーム暗号
  k, n, b, c(初期定数) 8×10回繰り返す

ワンタイムパッド

共通鍵暗号の一つであるワンタイムパッドは情報が絶対もれないという意味でも最も安全な暗号
OTP(One-Time Pad)とはnビットの平文mを暗号化するためにnビットの秘密鍵sを使う暗号方式。秘密鍵は1度しか使ってはいけないのでワンタイム
平文mと秘密鍵sの各ビットごとに排他的論理和+をとって暗号文を作る
平文mを秘密鍵sで暗号化することをEnc(s, m)と書く
暗号文cを秘密鍵sで複合することをDec(s, c)と書く

ワンタイムパッドは秘密鍵に真の乱数を使うと絶対に破られない暗号(情報理論的安全性がある)
 L 暗号文を作るたびに毎回新しく乱数で秘密鍵を用意して相手と共有しなければならない
 L しかも秘密鍵は暗号文と同じサイズでなければならない