AES-256のEncrypter/Decripterを作る必要が出てきたので調べてみた。暗号素人が調べたところでその本質を理解できる訳ないのだが、本質の理解は難解な1次情報を読むことが必須だし、一般人のレベルにおいては、素人の理解のプロセスを文書化することは割と価値があると思うので。
AESとは
AESとは、Advanced Encryption Standard の略。LTE, Long Term Evolution のように相対的な定義である。
暗号と一口にいっても特色がある多種多様なアルゴリズムが存在する。その切り口として暗号的強度だけでなく、ハードウェア、ソフトウェアでの実装のしやすさ、実行に必要なリソース(簡単な装置で実行可能か、速いか、など)、鍵長、ブロック長をスケールできるか、知的財産権に問題はないか、など様々。その中からAESコンセプトを満たす暗号方式が採用された。
ブロック長=128bitブロック暗号の一つ。
アルゴリズム
AESの実体は「Rijndael(ラインダール)」である。AESの1次情報はこれ。図にすると以下のようになるらしい。入力(平文)を分割せず一括して処理し、その処理結果を次の処理の入力とする。各処理を段関数といい段関数の数は、鍵長128bitでは10段、256bitでは14段である。
Pascalチックにアルゴリズムを書いてみる。Nrは段数であり鍵長から決まる。鍵長=128bitの場合Nr=10,192bitの場合Nr=12,256bitの場合Nr=14。全体として段数分だけ段関数を繰り返す。段関数において基本処理(SubBytes,ShiftRows,MixColumns,AddRoundKey)を実行する。それぞれ変換と逆変換が対になっており、各処理を逆順で実行することで復号を行う。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function Cyper(in:array[0..4*Nb] of byte, out:array[0..4*Nb] of byte, word:array[0..Nb*(Nr+1)) begin state = in; AddRoundKey(state, w[0,NB-1]); for (round:=1 to Nr-1) do begin SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, w[round*Nb, (round+1)*Nb-1]); end; SubBytes(state); ShiftRows(state); AddRoundKey(state,w[Nr*Nb, (Nr+1)*Nb-1]); end; |
割とシンプルに見える(見えなければならないw)。AESの凄いところは、SubBytes,ShiftRows,MixColumns それぞれの処理をビット演算だけで実現できることにある。当然速いしハードウェアでの実装も楽。