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 しかも秘密鍵は暗号文と同じサイズでなければならない

暗号における乱数

予想不可能性、再現不可能性が大事
Linuxの/dev/randomはCPUのハードウェアだけでなく様々な情報を組み合わせて、仮にどれか一つに問題があったとしても最終出力には影響が出ないように設計されている(ストリーム暗号(sec.12)を用いた疑似乱数生成器)
疑似乱数…他人が推測できてはいけない
疑似ランダム関数(PseudoRandom Function)は、シードsを与えたときに任意の値に対して疑似乱数を生成する関する
L HAMCを繰り返して適用して実装する方法がある

共通鍵暗号と排他的論理和

暗号化する時と複合するときに同じ鍵を使う。秘密鍵暗号、対称鍵暗号ともいう。
s(secret), m(message), c(ciphertext)
c = Enc(s, m)
c = Enc(m)
m = Dec(c)

Chosen Plaintext Attack, Choosen Ciphertext Attackなどがあります

### 共通鍵暗号の種類
ブロック暗号とストリーム暗号に分類される
– ブロック暗号: 一定のブロックごとに平文をかき混ぜて暗号化
– ストリーム暗号: ノイズ(乱数)を生成し、それと平文を混ぜ合わせて暗号化

### ビットと排他的論理和
真理値表に従い恒等変換という
論理積: 両方の入力が1の時のみ1
論理和: どちらか一方が1なら1
排他的論理和: aとbどちらか片方が1の時1、それ以外が0
交換法則: aとbを交換しても同じ値になる
結合法則: 3この1ビットa, b, cがあったときに、どちらから先に計算しても同じになる

排他的論理和で考えると、aを平文、bを鍵とすると a^bは暗号文、(a^b)^b = a が暗号文を復号して元の平文aを取り出す操作

アルゴリズムと安全性

アルゴリズムの性能を分類するのはO記法を使用する
O記法はパラメータnに関する関数f(n)のnが大きくなった時の振る舞いを表現
f(n)のオーダーはO(n^d)
入力パラメータによる計算式に応じて、定数時間アルゴリズム、線形時間アルゴリズム、多項式アルゴリズムという
e.g. y=2^x, y=x^2, y=x, y=log(x)
メモリの消費量もO(n), O(n log(n))など色々なものがある
ビットと表現可能な範囲

### セキュリティパラメータ
暗号を破るのに必要な計算コスト
暗号技術の危殆化とは、計算機の性能向上や暗号解読・攻撃手法の進展に伴って暗号の安全性が低下すること

現在安全とされる128ビットセキュリティ
– 共通鍵暗号:128
– ハッシュ関数: 256
– RSA暗号: 約3000
– 楕円曲線暗号: 256 (2024ビットRSAより安全と考えられている)

古典暗号

1970年代後半からを現代暗号とした場合、それ以前の暗号を古典暗号という

### シフト暗号
数字を決めておき、その数だけ文字をずらして暗号文を作成する
シーザー暗号とも言われる

function str_rot($s, $n = 13) {

	static $letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
	$n = (int)$n % 26;
	if(!$n) return $s;
	if($n == 13) return str_rot13($s);
	for($i = 0, $l = strlen($s); $i < $l; $i++){
		$c = $s[$i];
		if($c >= 'a' && $c <= 'z'){
			$s[$i] = $letters[(ord($c) - 71 + $n)% 26];
		} else if($c >= 'A' && $c <= 'Z'){
			$s[$i] = $letters[(ord($c) - 39 + $n)%26 + 26];
		}
	}
	return $s;
}

### 換字式暗号
換字表を作り、それに従って暗号化する
-> e, a, tの順番に出現頻度が高い。文字の偏りが出てしまう。

### 符号化
文章やデータをコンピュータで扱える形にすることを符号化という。
最もポピュラーなのは、アルファベットや数字、多少の記号だけに限定したASCIIと呼ばれる文字コード。ASCIIコードは16進数で表記することが多い。
上位(2~7)、下位(0~9a~f)の16進数でアルファベットを表現する
上位0、1に対応するのは特殊文字
helloは「68 65 6c 6c 6f」と表現できる

認証の基礎

その人だけが知っている知識を利用した認証を知識認証という
指紋や静脈など生体情報を利用した生体認証
ワンタイムパスワード生成器などを利用した所有物認証がある
ユーザごとに発行するクライアント証明書を発行する方法もある
L パスワード認証が成功したら、次に登録したスマートフォンに認証コードが送られてきてそのコードを入力して初めてログインできるシステムが増えている
  L PHPでSMS送信するにはTwillioやClickatellが提供しているものを使うのが簡単
   L フレームワークで公開されているものがある
https://github.com/fotografde/cakephp-sms

### 認可
ユーザの属性に応じてシステムのアクセス権限を決める

### OAuth
YがXのAPIを利用できるよう認可する その標準的な枠組みがRFC6749で定義されたOAuth2.0
パスワードの代わりにアクセストークンと呼ばれるデータを用いてYがXのリソースにアクセスする

ブルートフォース(Brute-force)攻撃

$http->post('username', '****')
	->post('password', '****')
	->post('action', 'login2')
	->fetch('https://www.value-domain.com/login.php');

CSRF対策トークンがないと簡単に攻撃されてしまう

### hydraでBrute-force
$ crunch 4 4 -o password.txt
$ hydra -l test -P password.txt 127.0.0.1 http-post-form ‘/login_sql.php:name=^USER^&password=^PASS^:ログイン失敗です’

hydra github
https://github.com/vanhauser-thc/thc-hydra

### Pythonで4桁のパスワードのBrute-force攻撃

import zipfile
import pandas as pd

file_path = 'energy.zip'
size = 4
chars = '0123456789'
count = 0
numbers = []

with zipfile.ZipFile(file_path . 'r') as zf:
	for i in range(100000):
		pwd = bytes(''.join(random.choices(chars, k=size)), 'UTF-8')
		numbers.append(pwd)
		try:
			zf.extractall(path='.'. pwd=pwd)
			print('このPDFファイルのパスワードは、[]です'.format(pwd))
			break
		except Exception as e:
			count += 1

print('総当たり攻撃で解凍を試した回数は:' . count . '回です')
df = pd.DataFrame(numbers)

暗号化

平文を暗号化することをencrypt、復号することをdecrypt
暗号化に使う鍵を暗号鍵
複合に使う鍵を複合鍵(秘密鍵)
L 暗号化ライブラリは広く使われている方が安全性が高いとされる

# 認証
### パスワードの攻撃方法
– 全パターンのパスワードを順次試すブルートフォース(Brute-force)攻撃
– 「12345678」「password」などよく使われるパスワードを入手しておき順次試す辞書攻撃
L 複数回間違えたらロックしたり、弱いパスワードを登録しようとしたら警告を出す
– パスワードを固定してIDを準に試すのをリバースブルート攻撃という
– 多数のユーザIDのリストを持ち、各IDに対して同じパスワードを順次試す方法

なるほど、触りでもかなり奥の深いトピックやな