共通鍵暗号 (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
(n
は
0
以上
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 の場合は、SubBytes
が
ShiftRows
より先に実行されるように記述されています。
AddRoundKey AddRoundKey
InvSubBytes
| ShiftRows InvShiftRows
x InvSubBytes
13 InvMixColumns | AddRoundKey
| AddRoundKey x InvMixColumns
13 InvSubBytes
ShiftRows | InvShiftRows
InvSubBytes
AddRoundKey AddRoundKey
ラウンド鍵は、14 + 1 ラウンドの計 60 列について適
用されます。最初の 8 列は共通鍵と等しくなります。
ラウンド鍵の列
rn
の
n
が
8
以上
60
未満の範囲では、
次の式に従って導出します。+
は XOR を表します。
n
= 0 mod 8
の場合
rn
=
f(g(rn
-
1))
+
rn
-
8
+
c(n8)
n
≠ 0 mod 8、n
= 0 mod 4
の場合
rn
=
f(rn
-
1)
+
rn
-
8
n
≠ 0 mod 8、n
≠ 0 mod 4
の場合
rn
=
rn
-
1
+
rn
-
8
f
は S-box の適用、g
は 3 バイトの巡回シフトを表しま
す。また、ラウンド鍵の列においてブロックの行番号 0
と共通する要素に
c(n)
=
xn
- 1
mod
p(x)
を加算し
ています (_RCON)。これらの処理は、ラウンド鍵の間の
関連を弱くするために行われます
COPYRIGHT © 2019 mScroll