共通鍵暗号 (intf.js)
オブジェクト: intf
必要なライブラリ:
std ※<body> より後に配置します

Advanced Encryption Standard (AES)
最初に、次の API を使用して 256 ビットの共通鍵から
暗号化または復号に適用するラウンド鍵を導出します。
intf.aes256i(  Key_schedule_, K_) intf.aes256inv_i(  Inv_key_schedule_, K_)

Key_schedule_Inv_key_schedule_ は 4 バイト
毎にラウンド鍵を要素として受け取る配列です。K_
32 バイト (256 ビット) の共通鍵を Uint8Array 形式
で代入します。

暗号化または復号の API は次の通りです。
intf.aes256a(C_,  M_, O_, Key_schedule_) intf.aes256inv_a(M_,  C_, O_, Inv_key_schedule_)

暗号化または復号済みブロックは、第 1 引数より 16 バ
イトの Uint8Array で取得します。第 2 引数にメッセ
ージを 16 バイト以上の Uint8Array で入力し、第 3
引数 O_ に先頭の要素の位置を指定します。第 4 引数に
はラウンド鍵の配列を代入します

AES の利用
AES の共通鍵には、パスワードや Diffie-Hellman によ
る共通の値などを使用しますが、値の範囲やビット分布
の改善、鍵の再利用を防ぐ観点から、乱数 (ソルト) を
追加してハッシュ関数を通したものを使用します。P_
は、パスワードや Diffie-Hellman による共通の値など
Uint8Array です。
S_ = new Uint8Array(32); crypto.getRandomValues(S_); K_ = new Uint8Array(192); intf.pbkdf2( K_, P_, S_, 20000, intf.sha512i, intf.sha512a, 64, 128); Key_schedule_ = []; intf.aes256i( Key_schedule_, new Uint8Array( K_.buffer, K_.byteOffset, 32));

この例では 32 バイトのソルト S_ と SHA-512 (出力長
64 バイト、ブロック長 128 バイト) を使用しています。
ハッシュ操作は PBKDF2 によって 20000 回実行されま
す。PBKDF2 は鍵導出関数であり、長い出力を得られる
ほか、総当たり攻撃に対する耐性を向上させることがで
きます。K_ は PBKDF2 の出力です。

AES は、CTR モードで利用して任意の長さのメッセージ
を暗号化できます。メッセージに対しては XOR が適用さ
れているため、復号も同じ処理となり実装が容易です。
u = new Uint8Array(16); N_ = new Uint8Array( K_.buffer, K_.byteOffset + 64, 8); C_ = new Uint8Array(16); for (s = 0 , t = 8; t < 16; ++ s , ++ t) { C_[t] = N_[s]; } for (s = 0 , r = 16; s < M_.length; ++ s , ++ r) { if (r === 16) { r = 0; for (t = 0; t < 8 && (++ C_[t] , C_[t] === 0); ++ t) { } intf.aes256a(u, C_, 0, Key_schedule_); } M_[s] ^= u[r]; }

ノンス N_ は PBKDF2 で導出した K_ から得ています。
C_ はカウンタ、M_ はメッセージです。暗号化後の M_
について HMAC は次の通りに計算します。
A_ = new Uint8Array(64); v = new Uint8Array(128); w = new Uint8Array(128); intf.hmac_i( A_, v, w, new Uint8Array( K_.buffer, K_.byteOffset + 128, 64), intf.sha512i, intf.sha512a, 128); w = intf.hmac_a0( A_, w, intf.sha512i, intf.sha512a); intf.hmac_a( A_, w, M_, 128 + M_.length, v, true, intf.sha512i, intf.sha512a, 128);

HMAC の値 A_M_ に付加して、共通鍵を知る場合に
メッセージを認証できるようにします。例では、K_
一部より HMAC の鍵を得ています。S_ は平文で付加し
ますが、A_C_ の続きを利用して暗号化できます。
for (s = 0 , r = 16; s < 64; ++ s , ++ r) { if (r === 16) { r = 0; for (t = 0; t < 8 && (++ C_[t] , C_[t] === 0); ++ t) { } intf.aes256a(u, C_, 0, Key_schedule_); } A_[s] ^= u[r]; }

復号の場合は先に HMAC を検証します。HMAC の復号
に必要な C_ は、M_ の長さを使用して復元できます。
for (s = 0 , t = 8; t < 16; ++ s , ++ t) { C_[t] = N_[s]; } s = Math.ceil(M_.length / 16); t = Math.floor(s / 0x100000000); C_[0] = s; C_[1] = s >>> 8; C_[2] = s >>> 16; C_[3] = s >>> 24; C_[4] = t; C_[5] = t >>> 8; C_[6] = t >>> 16; C_[7] = t >>> 24;

AES 実装の詳細
256 ビットの共通鍵による AES の暗号化と復号は、実
装において次の通りに構成されています。
AddRoundKey | ShiftRows x SubBytes / InvSubBytes 13 MixColumns / InvMixColumns | AddRoundKey ShiftRows SubBytes / InvSubBytes AddRoundKey

暗号化と復号は、16 バイトのブロックに対して実行さ
れます。表記は以下の 2 種類を使用します。
[ 0][ 4][ 8][12] [00][01][02][03] [ 1][ 5][ 9][13] [10][11][12][13] [ 2][ 6][10][14] [20][21][22][23] [ 3][ 7][11][15] [30][31][32][33]

AddRoundKey はブロックに対し、縦の列にラウンド鍵
を排他的論理和 (XOR) で適用します。XOR を再度適用
すると元に戻るため、正しいラウンド鍵を知る場合に復
元できます。

ShiftRows は、MixColumns に入力する列の要素を入
れ替え、ブロック全体へビットを拡散します。
[ 0][ 4][ 8][12] [00][01][02][03] [ 5][ 9][13][ 1] [11][12][13][10] [10][14][ 2][ 6] [22][23][20][21] [15][ 3][ 7][11] [33][30][31][32]

SubBytes は、1 バイトを位数 28 の有限体 GF(28)
と考え、ブロックの各要素を置き換えます。これにより
入出力の近似式の構成を困難にします。置き換えに使用
する表は S-box と呼ばれます。

GF(28):
AES では、係数が GF(2) の多項式とし、既約な多項式
p(x) = x8 + x4 + x3 + x + 1 を用いて、mod p(x)
を適用します。各要素は 7 次以下となります。加減算は
XOR、x の乗算は左ビットシフトに対応します

S-box は、GF(28) における逆数とアフィン変換によっ
て作成することが可能であり、実装では次に対応します。
_SBOX[ a-1(x) ] = A(x)
_INV_SBOX[ A(x) ] = a-1(x)

0-1 = 0 と定義して、
a(x)  x2 + 1
a-1(x)  x6 + x4 + x
の累乗で生成される巡回群を使用し、256 個の要素から
なる表を作成します。a(x) および A(x) のビットを an
An (n は下位より 0 以上 7 以下) として、アフィン変
換は次の通りとなります。
A0 A1 A2 A3 A4 A5 A6 A7 = 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 1 a0 a1 a2 a3 a4 a5 a6 a7 + 1 1 0 0 0 1 1 0

上式の正方行列は、左巡回ビットシフトのシフト量が 0
から 4 であるビット表現の総和を表します。この式は、
A(x) = (x7 + x6 + x5 + x4 + 1)a(x)
 + (x7 + x6 + x2 + x) mod x8 + 1

の係数および定数項である多項式について、ビットの方
向を反転したものとなります。x8 + 1 は、左巡回ビッ
トシフトが容易となるように選択されており、係数の多
項式 x7 + x6 + x5 + x4 + 1 と互いに素です。定数項
x7 + x6 + x2 + x は、S-box による置き換えの前後で
同一または補数にならないよう選択されています。

互いに素:
mod x8 + 1 において逆数が存在することを表します。
x7 + x6 + x5 + x4 + 1 の逆数は x7 + x5 + x2 であ
り、対応する正方行列は逆変換を構成できます

MixColumns は、ブロックの縦の列に対して次の行列
演算を行い、ビットを混合します。S-box を適用した 1
バイトの要素を sn (n0 以上 3 以下)、Sn を演算後
の要素とします。行列の要素は、GF(28) の多項式です。
n [00][01][02][03] : 0 [11][12][13][10] : 1 [22][23][20][21] : 2 [33][30][31][32] : 3

S0 S1 S2 S3 = 2 3 1 1 1 2 3 1 1 1 2 3 3 1 1 2 s0 s1 s2 s3

1 から 2 バイトまで巡回シフトした列の総和と、x を乗
算した列、x + 1 の乗算と 3 バイトの巡回シフトを適
用した列の加算を実行します。
S(X) = (3X3 + X2 + X + 2)s(X) mod X4 + 1
係数 3X3 + X2 + X + 2 は、高いビット拡散特性をも
つ正方行列となるように選択されています。実装では、
正方行列の縦の列が 1 つの S-box 要素と対応すること
から、定数 _SUB_MIX を事前に計算しています。
_INV_SUB_MIX では、3X3 + X2 + X + 2 の逆数
11X3 + 13X2 + 9X + 14 に対応する逆行列を、逆方
向の S-box と組み合わせます。
s0 s1 s2 s3 = 14 11 13 9 9 14 11 13 13 9 14 11 11 13 9 14 S0 S1 S2 S3

復号は、暗号化の逆順を実行します。
AddRoundKey InvSubBytes InvShiftRows | AddRoundKey x InvMixColumns 13 InvSubBytes | InvShiftRows AddRoundKey

SubBytes (S-box) は 1 バイト単位の操作であり、
InvShiftRows に対して独立しているため、順序を入
れ替えることができます。したがって、ラウンドのルー
プも変更可能です。また、InvMixColumns はラウンド
鍵を加算したブロックに対する操作となるため、行列の
分配法則により、InvMixColumns をブロックとラウン
ド鍵へ個別に適用できます。あらかじめ
InvMixColumns を該当のラウンド鍵に適用しておくこ
とで、AddRoundKey に対する順序も変更できます。
S-box を除いた InvMixColumns_INV_SUB_MIX
のインデックスに _SBOX を適用することで得られます。
InvShiftRows は、事前に入力ブロックの列を交換し、
ShiftRows へ置き換えることができます。すべてのラ
ウンドの後に再度ブロックの列を交換して、平文ブロッ
クを得ます。ラウンド鍵についても位置を入れ替えます。
ブロックの列における要素の並び方は同一であり、列の
位置のみが異なります。
[00](03)[02](01) | [11](10)[13](12) | [22](21)[20](23) | [33](32)[31](30) | ShiftRows x 14 [00](03)[02](01) | (10)[13](12)[11] | [20](23)[22](21) | (30)[33](32)[31] | ---------------- [00]{01}[02]{03} (10){11}(12){13} [20]{21}[22]{23} (30){31}(32){33}

以上の内容から、暗号化の実装を再利用できます。
FIPS PUB 197 の場合は、SubBytesShiftRows
より先に実行されるように記述されています。
AddRoundKey AddRoundKey InvSubBytes | ShiftRows InvShiftRows x InvSubBytes 13 InvMixColumns | AddRoundKey | AddRoundKey x InvMixColumns 13 InvSubBytes ShiftRows | InvShiftRows InvSubBytes AddRoundKey AddRoundKey

ラウンド鍵は、14 + 1 ラウンドの計 60 列について適
用されます。最初の 8 列は共通鍵と等しくなります。
ラウンド鍵の列 rnn8 以上 60 未満の範囲では、
次の式に従って導出します。+ は XOR を表します。
n = 0 mod 8 の場合
 rn = f(g(rn - 1)) + rn - 8 + c(n8)
n ≠ 0 mod 8n = 0 mod 4 の場合
 rn = f(rn - 1) + rn - 8
n ≠ 0 mod 8n ≠ 0 mod 4 の場合
 rn = rn - 1 + rn - 8

f は S-box の適用、g は 3 バイトの巡回シフトを表しま
す。また、ラウンド鍵の列においてブロックの行番号 0
と共通する要素に c(n) = xn - 1 mod p(x) を加算し
ています (_RCON)。これらの処理は、ラウンド鍵の間の
関連を弱くするために行われます
関連項目:

ダウンロード (GitHub リポジトリ)

ハッシュ関数
[広告]



ライブラリへ戻ります

トップページへ戻ります
COPYRIGHT © 2019 mScroll