说明:以下章节写为第6章是为了和标准GB/T 36624-2018的章节对应
6. 机制1——Key Wrap
密钥封装是为了对密钥进行保护,比如密钥存储在不太安全的存储设备中,或者密钥需要在网络中传输。
- 2001年,NIST发布了AES Key Wrap Specification。
- 2002年,IETF在RFC 3394中也描述了密钥封装算法AES-KeyWrap Algorithm,电信行业协会发布了使用TDES的密钥封装算法。
- 2008年,美国标准认可委员会(Accredited Standards Committee X9, Inc.)发布了金融服务业的密钥封装算法。
- 2009年,ISO/IEC 发布了ISO/IEC 19772-2009,其中描述了密钥封装算法。
- 2009年,RFC 5649 描述了带填充的密钥封装算法。
- 2012年,NIST SP 800-38F描述了AES KW、AES KWP(带填充的密钥封装算法)和TDES的TKW。
- 2018年,我国发布GB/T 36624-2018,修改后采用ISO/IEC 19772-2009。
参考文献
- Key Wrap - Wikipedia, the free encyclopedia, http://en.wikipedia.org/wiki/Key_Wrap
- NIST Special Publication 800-38F: Recommendation for Block Cipher Modes of Operation Methods for Key Wrapping, December 2012.
- J. Schaad and R. Housley, Advanced Encryption Standard (AES) Key Wrap Algorithm, RFC 3394, September, 2002.
- R. Housley and M. Dworkin, Advanced Encryption Standard (AES) Key Wrap with Padding Algorithm, RFC 5649, August, 2009.
- ANSI/TIA-102.AACA-1-2002: Project 25 – Digital Radio Over-the-Air-Rekeying (OTAR) Protocol: Addendum 1 – Key Management Security Requirements for Type 3 Block Encryption Algorithms, Telecommunications Industry Association, November, 2002.
- ANS X9.102-2008, Symmetric Key Cryptography For the Financial Services Industry—Wrapping of Keys and Associated Data, Accredited Standards Committee X9, Inc., June, 2008.
6.1 密钥封装概况
按NIST SP800-38F,密钥封装有三种
表 6.1 三种密钥封装方案
方案 |
KW |
KWP |
TKW |
方案说明 |
基于AES等算法 不使用填充 |
基于AES等算法 使用填充 |
基于TDES算法 不使用填充 |
NIST SP800-38F |
采用 |
采用 |
采用 |
ISO/IEC 19772-2009 |
采用 |
× |
× |
GB/T 36624-2018 |
采用 |
× |
× |
下面描述了所有的三个方案。如果只涉及GB/T 36624-2018,可只参见KW方案。
6.2 KW方案——AES/SM4密钥封装,不填充
KW的加密KW-AE(P)和解密KW-AD(C)。
6.2.1 加密算法KW-AE(P)
加密C = KW-AE(P)
输入:明文P
输出:密文C
1. ICV1 = 0xA6A6A6A6A6A6A6A6.
2. S = ICV1 || P.
3. Return C = W(S).
6.2.2 解密算法KW-AD(C)
解密P = KW-AD(C)
输入:密文C
输出:明文P或者失败
1. ICV1 = 0xA6A6A6A6A6A6A6A6.
2. S = W-1(C).
3. If MSB64(S) ≠ICV1, return FAIL and stop.
4. Return P = LSB64(n-1)(S).
6.2.3 RFC 3394对KW的描述
RFC 3394对KW采用一种便于软件实现的描述方式。
输入:
- 明文 P = P1||P2||...||Pn,n个64-bit
- 密钥 K (KEK).
输出:
- 密文 C = C0||C1||...||Cn,(n+1)个64-bit
步骤
1) A = IV, IV = 0xA6A6A6A6A6A6A6A6
For i = 1 to n, R[i] = P[i]
2) For j = 0 to 5 {
For i=1 to n {
B = AES(K, A || R[i])
A = MSB(64, B) ? t,其中t = (n*j)+i
R[i] = LSB(64, B)
}//i
}//j
3) C[0] = A
For i = 1 to n, C[i] = R[i]
Return C = C[0] || C[1] || ... || C[n]
6.3 KWP方案——AES/SM4密钥封装,带填充
带填充的加密KWP-AE(P)和带填充的解密KWP-AD(C)。
6.3.1 加密算法KWP-AE(P)
加密C = KWP-AE(P)
输入:明文P
输出:密文C
1. ICV2 = 0xA65959A6.
2.
3. PAD = 08×padlen
4. S = ICV2 || [len(P)/8]32 || P || PAD
5. If len(P) ≤ 64, return C = CIPHK(S);
else, return C = W(S).
这里的padlen是指将明文P填充为64bit的整数倍时需要填充(填充数据为全零字节)的最短字节数,可以为0。消息S表示在填充后消息的前面再加64比特的特殊消息,以保证S长度最少为一个分组大小(128bit)。如果S长度只有一个分组大小,则直接执行AES。
6.3.2 解密算法KWP-AD(C)
解密P = KWP-AD(C)
输入:密文C,C = C1||C2||...||Cn, n个64-bit
输出:明文P或者失败
1. ICV2 = 0xA65959A6.
2. If n = 2, S = CIPH-1K(C); if n > 2, S = W-1(C).
3. If MSB32(S) ≠ ICV2, return FAIL and stop.
4. Plen = int(LSB32(MSB64(S))).
5. padlen = 8(n-1)-Plen.
6. If padlen < 0 or padlen > 7, return FAIL and stop.
7. If LSB8×padlen(S) ≠ 08×padlen, return FAIL and stop.
8. Return P = MSB8×Plen(LSB64×(n-1)(S)).
6.4 TKW方案——TDES密钥封装,不填充
这个和KW其实是一样的,只有一下几个地方有区别:
- 使用的密码算法不一样:KW采用AES;TKW采用TDES
- 分组大小不一样导致半分组大小不一样:KW半分组大小64bit;TKW半分组大小32bit。
详细流程可辅助参见KW。
注意:TKW没有加填充的所谓TKWP算法。
6.5 模块W
C = W(S)模块
准备:
- K(即KEK)
- 128-bit 分组密码CIPH.
输入:
- S,长度为n×64bit,n ≥ 3.
输出
- C,与S等长(长度为n×64bit,n ≥ 3)。
步骤
1. 初始化
s = 6(n-1).
S=S1 || S2 ||… || Sn . Si都是64it
A0 = S1.
For i = 2, …, n: R0i = Si.
2. 迭代
For t = 1, …, s
(2.1) At = MSB64(CIPHK(At-1 || R2t-1)) ? [t]64;
(2.2) For i = 2, …, n-1: Rit = Ri+1t-1;
(2.3) Rnt = LSB64(CIPHK (At-1 || R2t-1)).
3. 输出结果
C1 = As.
For i = 2, …, n : Ci = Ris.
Return C1 || C2 || … || Cn.
图 6.2 W的示意图
(W的第2步需要执行6(n-1)次,在图中为绿色部分执行6次。)
其中迭代器的示意图如下:
图 6.3 W的迭代器的示意图
6.6 模块W-1
S = W-1(C)模块
准备:
- K(即KEK)
- 128-bit 分组密码CIPH的逆函数CIPH-1
输入:
- C,长度为n×64bit,n ≥ 3.
输出
- S,与c等长(长度为n×64bit,n ≥ 3)。
步骤
1. 初始化
s = 6(n-1).
C = C1 || C2 ||… || Cn . Ci都是64bit
As = C1.
For i = 2, …, n
Rsi = Ci.
2. 迭代
For t = s, …, 1
At-1 = MSB64((CIPH-1K(At ?[t]64)) || Rnt);
R2t-1 = LSB64(CIPH-1K ((At ?[t]64) || Rnt).
For i = 2, …, n-1: Ri+1t-1 = Rit
3. 输出结果
S1 = A0.
For i = 2, …, n:Si = Ri0.
Return S1 || S2 || … || Sn.
6.7 测试数据
- AES Key Wrap测试数据
- NIST SP 800-38F里面没有测试数据。
- 可以在RFC 3394和RFC 5649里面查。
- SM4 Key Wrap测试数据
- GB/T 36624-2018 附录C.2。