← 首页 1对称算法

1对称算法

用于加密、认证、加密认证的加密算法

DES

DES是分组加密算法,以64位为分组对数据进行加解密,密钥64位(实际参与运算56位)

特点:分组短、密钥短、运算速度慢

IP置换

将输入的64位数据块按位重新组合,并把输出分为L0、R0两部分,各32位。
IP置换遵循下表规则(8*8)

密钥置换

不考虑每个字节的第8位,DES密钥由64位减至56位,每个字节的第8位为奇偶校验位。
产生56位密钥,遵循下表规则(4*14),注意没有(8/16/24/32/40/48/56/64)

E拓展置换

S盒代替

P盒置换

IP^-1末置换

DES与TDES

算法 分组长度(字节) 密钥 加密 解密 速度(相对)
DES 8 64 E D 1
TDES_128 8 128 EDE DED 1/3
TDES_192 8 192 EDE DED
TDES_EEE_128 8 128 EEE DDD
TDES_EEE_192 8 192 EEE DDD

注:
1、TDES_EEE表示的是非标准3DES,即其加密是连续三次加密,其解密实连续三次解密
2、TDES_192的加解密密钥使用顺序:k1、k2、k3
3、TDES_128的加解密密钥使用顺序:k1、k2、k1

TDES128计算CFB流程示例

//TDES128-CFB_block-ENC
//plain
81709944E0CB2E1DB5B0A477D1A8539B
//key
E07099F1BFAFFD7F
240CD790CA4FE134
//iv
C72B6591A0D7DE8F
//cipher
DE658657CEC1D13A4C416ED7E83CAB85


//step
//C1, key=E07099F1BFAFFD7F,crypto=enc
DD5F07CEFABC934E52D7417C07F8EF30
//C2,key=240CD790CA4FE134,cipher=DD5F07CEFABC934E52D7417C07F8EF30,crypto=dec
56D029BFEE32C886DB98EBFDFC35476D
//C3,key=E07099F1BFAFFD7F,plain=56D029BFEE32C886DB98EBFDFC35476D,crypto=enc
00E7549663AB000094840B2FE6190DCC



//TDES128-CFB-ENC
//plain
81709944E0CB2E1D
//key
E07099F1BFAFFD7F
240CD790CA4FE134
//iv
C72B6591A0D7DE8F
//cipher
B3F76EB9504F5B5D

//step
//C1, key=E07099F1BFAFFD7F,crypto=enc
DD5F07CEFABC934E
//C2,key=240CD790CA4FE134,cipher=DD5F07CEFABC934E,crypto=dec
56D029BFEE32C886
//C3,key=E07099F1BFAFFD7F,plain=56D029BFEE32C886,crypto=enc
00E7549663AB0000




//TDES128-CFB-ENC
//plain
81709944E0CB2E1D
//key
E07099F1BFAFFD7F
240CD790CA4FE134
//cipher
C00727761EC27282

//step
//C1, key=E07099F1BFAFFD7F,crypto=enc
60DFC6E3581378FB
//C2,key=240CD790CA4FE134,cipher=60DFC6E3581378FB,crypto=dec
6380CA29F4F4BAB0
//C3,key=E07099F1BFAFFD7F,plain=6380CA29F4F4BAB0,crypto=enc
C00727761EC27282

AES

高级加密标准,AES区块长度固定为128bit,密钥可以是128、192、256bits。
《RFC3394》定义密钥封装算法

AES128 AES192 AES256
key_byte 16 24 32
block_byte 16 16 16
Number of round 10 12 14
round key size (words/bytes) 4/16 4/16 4/16
expanded key size (words/bytes) 44/176 52/208 60/240

特点:运算速度快、安全性高、资源消耗小

SM4

2006年发布,同年8月成为国家标准,该算法公开。
key长度16字节。
原名SMS4

《GB/T 36624-2018》定义密钥封装算法

ZUC

序列密码,密钥长度128bit,由128bit种子密钥和128bit IV共同生成32bit密钥流

GCM

参考文档:《NIST-SP800-38D》

GCM计算流程

1)加密流程:

Input:aad、payload、iv、mac_byte(不影响,取最高位Nbytes)
output:cipher、mac(长度为mac_bytes)

image-20240718143758752

Step:
1.Let H = CIPHk(128位全0)
2.define a block J0 :
if byte_len(IV) == 12 then J0= IV||00..00||1
else J0 = GHASHh(IV || 0->(s+64)bit || len(IV)->64bit )
其中s=128 * upper_integer(len(IV)/128) - len(IV) //upper_integer向上取整,不小于实数X的整数
3.Let C = GCTRk(inc32(J0), P)
4.Let u = 128 * upper_integer(len(C)/128) - len(C)
5.Let v = 128 * upper_integer(len(A)/128) - len(A)
6.define a block S = GHASHh(A || 0->vbit || C || 0->ubit || len(A)->64bit || len(C)->64bit)
7.let T = MSB(GCTRk(J0, S))
8.return (C, T)

注:注意第3步,密文的计算还是CTR模式,不过参与计算的IV起始是00...002(对于iV长度为96bit来说)

//---------------------Input---------------------//
//key-16byte
FEFFE9928665731C6D6A8F9467308308
//plain-64byte
d9313225f88406e5a55909c5aff5269a
86a7a9531534f7da2e4c303d8a318a72
1c3c0c95956809532fcf0e2449a6b525
b16aedf5aa0de657ba637b391aafd255
//iv-12byte
cafebabefacedbaddecaf888
//aad-20bytes
feedfacedeadbeeffeedfacedeadbeef
abaddad2000000000000000000000000

//---------------------Output---------------------//
//cipher-64byte
//iv长度12byte,J0=CAFEBABEFACEDBADDECAF88800000001
//ctr-iv(即J1):CAFEBABEFACEDBADDECAF88800000002
42831ec2217774244b7221b784d0d49c
e3aa212f2c02a4e035c17e2329aca12e
21d514b25466931c7d8f6a5aac84aa05
1ba30b396a0aac973d58e091473f5985
//mac
DA80CE830CFDA02DA2A218A1744F4C76

//构造IV-16byte
cafebabefacedbaddecaf88800000000

构造blocks

blocks=aad||padding(aad)||payload||padding(payload)
注:如果aad或payload实际长度已经分组整数倍,则不需要padding

GHASH计算实现

prerequisites:
block H
hash subkey

Input:
比特串X,比特长度128对齐

Output:
block GHASHh(X)

Steps:
1.Let X1, X2, ..., Xm-1, Xm denote the unique sequence of blocks such that X = X1 || X2 || ... || Xm-1 || Xm
2.Let Y0 be the "zero block", 0128
3.For i=1,...,m, let Yi = (Yi-1 xor Xi) * H
4.return Ym

Output:


chacha20_poly1305

标准文档《RFC8349》

chacha20_poly1305,已完成两版本,一个是自写实现,调用openssl大数计算,另外一版本是从openssl抽出chacha20、poly1305源码,其余自写,已发布在公众号。

chacha理论上可以做到任意输入,同时任意输出,这取决于算法的特性。首先硬件update以分组为单位,从算法层面分析,不同于AES/DES/SM4对原始消息操作(分组内的不同字节值变化影响整体加解密结果),CHACHA是先生成密钥流,最后与原始消息异或得到密文,不受原始消息字节值排布影响,只跟IV和分组counter有关。设计需要明确知道当前输入消息处于的counter,以及偏移即可支持任意输入输出,改造CPU模式支持该方式

对加密全0的原始消息,会不会存在泄露密钥风险

在chacha20轮函数中,a += b存在回绕
Qround:
  a += b; d ^= a; d <<<= 16;
  c += d; b ^= c; b <<<= 12;
  a += b; d ^= a; d <<<= 8;
  c += d; b ^= c; b <<<= 7;
the constant prime "P" be 2^130-5=0x3fffffffffffffffffffffffffffffffb

参考自写公众号链接:https://mp.weixin.qq.com/s/ojxEvq9sPkBKbLgqbNWrzQ?token=1386669807&lang=zh_CN

工作模式

PIPS:联邦信息处理标准

Counter Mode(CTR)
用密钥对输入的计数器加密,然后跟明文异或得到密文。优点是可以并行,避免误差传递问题。缺点是可以针对单个数据块进行攻击。

Counter with CBC-MAC Mode(CCM)
CCM是在CBC和CTR的基础上增加CMAC算法校验,主要是通过MAC校验来解决CTR容易被攻击的问题。

Galois/Counter Mode(GCM)
GCM是在CCM的基础上改用GMAC算法代替CMAC算法,增加了并行化设计,可以提高加密性能,降低时延。

CBC-MAC:密码块链接-身份消息认证
CCM: 计数器与密码块-身份消息认证

CCM*

标准链接:https://mentor.ieee.org/802.15/dcn/04/15-04-0537-02-004b-formal-specification-ccm-star-mode-operation.pdf

该标准指定了L和M的范围:
L:2,3,4,5,6,7,8
M:0,4,6,8,10,12,14,16
ByteLen(msg):[0, 28L)
ByteLen(aad):[0, 264)

CCM*是标准CCM的一些特例,外加新增一个扩展(即只加密,无认证)。

可以不修改算法库,分三种情况。

  1. 同时要加密和认证,当前已经满足。

  2. 只要认证,可以把消息作为AAD,而明文参数设置为NULL,做CCM加密就可以。

  3. 只要加密,当前库的CCM接口不满足,但此时CCM退化为CTR模式,用户只要丢弃AAD,自己构造下初始IV(即初始counter),调用CTR接口就可以。

初始IV构造很简单,即 0x01 || 13字节的nonce || 0x00 || 0x01。

CCM(Counter with CBC-MAC)

Application: 802.11协议族
在CBC和CTR基础上增加CMAC,主要通过MAC校验来解决CTR容易被攻击的问题。

《nist sp800-38c》为对称密钥块密码算法定义了一种操作模式,称为带密码块链接消息验证码(CCM)的计数器。CCM 可用于通过结合计数器 (CTR) 模式和密码块链接-消息验证码 (CBC-MAC) 算法的技术来保证计算机数据的机密性和真实性。

CCM=CBC-MAC认证 + CTR加密
CBC-MAC认证算法输出:长度为M的认证字段T
CTR加密算法针对两种数据进行加密:
(1)对T进行CFB/OFB加密,输出加密后的认证字段U
(2)对消息字段M(划分为一个或者多个blocks,不足一个block部分补0)进行CTR 加密

CCM参数

//认证域的字节长度,即认证tag(如下用U表示)的字节长度,有效值是在{4,6,8,10,12,14,16}中选取。M越大,则攻击者篡改后仍有效的可能越小,也即越安全。
M
//长度域的长度,即消息字节长度占用的字节数,有效值在2到8个字节(1个字节是保留值)
L
//一次性的认证信息,字节长度是15-L
Nonce
//额外的认证消息,其字节长度表示为len(a),要求0≤len(a)<2^64
AAD:

GCM(The Galois/Counter Mode of Operation)

见上述GCM计算流程

认证加密

目前先加密,再认证,是三者中最安全的。

//同时加密和MAC
C = Enc(K,M)
T = Mac(M)
//先加密、再MAC
C = Enc(K,M)
T = Enc(C)
//先MAC、再加密  //选择密文攻击
C = Enc(K,(M||Mac(M))

CFB

由NIST SP800-38A所定义的密码反馈模式(Cipher Feedback),特指CFB128

image-20230711163559969

全称:Cipher Feedback Mode
参考链接:https://www.zhihu.com/column/c_1380896366827388928

加密参数:明文P、加密密钥Key、初始向量IV
加密步骤
1.将P分为P0、P1、...、Pn,len(Pi) <= 128
2.用Key加密IV得到IV0,将IV0、P0做异或运算得到C0
3.用Key加密C0得到IV1,将IV1、P1做异或运算得到C1
...
4.用Key加密Cn-2得到IVn-1,将IVn-1、Pn-1做异或运算得到Cn-1
5.用Key加密Cn-1得到IVn,将IVn、Pn做异或运算得到Cn
6.拼接C0、C1、...、Cn得到密文,加密结束

解密参数:密文C、加密密钥Key、初始向量IV
解密步骤
1.将P分为C0、C1、...、Cn,len(Ci) <= 128
2.用Key加密IV得到IV0,将IV0、C0做异或运算得到P0
3.用Key加密C0得到IV1,将IV1、C1做异或运算得到P1
...
4.用Key加密Cn-2得到IVn-1,将IVn-1、Cn-1做异或运算得到Pn-1
5.用Key加密Cn-1得到IVn,将IVn、Cn做异或运算得到Pn
6.拼接P0、P1、...、Pn得到明文,解密结束

特点
1.CFB采用分组算法实现流算法(分组不大于16字节),明文数据不需要按分组大小对齐
2.加密不可并行,解密可以并行(当前分组解密需要上一分组密文经过Key加密后的值,与当前分组的密文异或)

OFB

由NIST SP800-38A所定义的输出反馈模式(Output Feedback)

image-20230711163658494

全称:Output Feedback Mode
参考链接:https://www.zhihu.com/column/c_1380896366827388928

加密参数:明文P、加密密钥Key、初始向量IV
加密步骤
1.将P分为P0、P1、...、Pn,len(Pi) <= 128
2.用Key加密IV得到IV0,将IV0、P0做异或运算得到C0
3.用Key加密IV0得到IV1,将IV1、P1做异或运算得到C1
...
4.用Key加密IVn-1得到IVn-1,将IVn-1、Pn-1做异或运算得到Cn-1
5.用Key加密IVn-1得到IVn,将IVn、Pn做异或运算得到Cn
6.拼接C0、C1、...、Cn得到密文,加密结束

解密参数:密文C、加密密钥Key、初始向量IV
解密步骤
1.将C分为C0、C1、...、Cn,len(Ci) <= 128
2.用Key加密IV得到IV0,将IV0、C0做异或运算得到P0
3.用Key加密IV0得到IV1,将IV1、C1做异或运算得到P1
...
4.用Key加密IVn-1得到IVn-1,将IVn-1、Cn-1做异或运算得到Pn-1
5.用Key加密IVn-1得到IVn,将IVn、Cn做异或运算得到Pn
6.拼接P0、P1、...、Pn得到明文,解密结束

特点
1.与CFB相同:分组、参数、加密模式类似:加密IV-与原文异或;
OFB的分组密文是异或出来的,可以理解为先加密"IV",再与分组原文异或
2.与CFB不同:OFB的当前分组输入IV是上一分组的已加密的IV(输出反馈);
CFB的当前分组输入IV是上一分组的密文(密文反馈);

3.OFB加解密理论上可以并行:先把所有分组对应的IVi计算出来,IV1=Enc(Key,IV),IV2=Enc(Key,IV1),然后每个分组各自加密(Key、IV、P)或解密(Key、IV、C),注意加解密的IV值是一样的。

4.克服CBC、CFB的错误传播问题(1bit错误只导致明文1bit的错误)

CTR

由NIST SP800-38A所定义的计数器模式(Counter),特指CTR32,参考RFC 3686标准

image-20230711163814847

全称:Counter Mode
参考链接:https://www.zhihu.com/column/c_1380896366827388928

加密参数:明文P、加密密钥Key、初始向量IV、随机数Nonce
加密步骤
1.将P分为P0、P1、...、Pn,len(Pi) <= 128
2.生成计数器Ctr0、Ctr1、...、Ctrn
3.用Key加密Nonce||Ctr0得到IV0,将IV0与P0异或得到C0
4.用Key加密Nonce||Ctr1得到IV1,将IV1与P1异或得到C1
...
5.用Key加密Nonce||Ctrn-1得到IVn-1,将IVn-1与Pn-1异或得到Cn-1
6.用Key加密Nonce||Ctrn得到IVn,将IVn、Pn做异或运算得到Cn
7.拼接C0、C1、...、Cn得到密文,加密结束

解密参数:密文C、加密密钥Key、初始向量IV、随机数Nonce
解密步骤
1.将P分为C0、C1、...、Cn,len(Ci) <= 128
2.生成计数器Ctr0、Ctr1、...、Ctrn
3.用Key加密Nonce||Ctr0得到IV0,将IV0与C0异或得到P0
4.用Key加密Nonce||Ctr1得到IV1,将IV1与C1异或得到P1
...
5.用Key加密Nonce||Ctrn-1得到IVn-1,将IVn-1与Cn-1异或得到Pn-1
6.用Key加密Nonce||Ctrn得到IVn,将IVn、Cn做异或运算得到Pn
7.拼接P0、P1、...、Pn得到明文,解密结束

特点:
1.加解密可并行,先把所有分组的IV值计算出来,各分组单独运行(C/P、Nonce||Ctr、Key)

//SM4 example
//key
ffffffffffffffffffffffffffffffff
//iv
ffffffffffffffffffffffffffffffff
//plain
ffffffffffffffffffffffffffffffff
//ECB(key, iv)
EDB119F8455FD2327AD6FBEDCB5B4F5D
//ECB(key, iv) ^ plain
EDB119F8455FD2327AD6FBEDCB5B4F5D ^ ffffffffffffffffffffffffffffffff
=124EE607BAA02DCD8529041234A4B0A2

CBC

image-20230711163445872

由NIST SP800-38A所定义的密码分组链接模式(Cipher Block Chaining)

Cipher Block Chaning密码块链接
https://blog.csdn.net/u013073067/article/details/87086562

加密参数:明文P、加密密钥Key、初始向量IV0
加密步骤
1.将P分组P0、P1、...、Pn,Pi=密钥模长
2.P0与初始向量IV0异或,再经过Key加密,得到C0
3.P1与C0异或,再经过Key加密,得到C1
4.P2与C1异或,再经过Key加密,得到C2
...
5.Pn与Cn-1异或,再经过Key加密,得到Cn
6.拼接C0、C1、...、Cn得到密文,加密结束

解密参数:密文C、加密密钥Key、初始向量IV0
解密步骤
1.将C分组C0、C1、...、Cn,Ci=密钥模长
2.C0经过Key解密,再与初始向量IV0异或,得到P0
3.C1经过Key解密,再与C0异或,得到P1
4.C2经过Key解密,再与C1异或,得到P2
...
5.Cn经过Key解密,再与Cn-1异或,得到Pn
6.拼接P0、P1、...、Pn得到明文,解密结束

特点:
加密:速度慢、对比ECB无法看出明文的规律
解密:速度快(可并行解密,只需要Key、C参与,每一分组的解密需要前一分组的密文)

PCBC

Propagating Cipher Block Chaining

加密参数:明文P、加密密钥Key、初始向量IV,数据填充模式M
加密步骤
1.将P分组P0、P1、...、Pn,Pi=密钥模长,长度不足需要填充
2.P0、IV异或,再经过Key加密,得到C0,下一分组IV1 = P0与C0异或
3.P1、IV1异或,再经过Key加密,得到C1,下一分组IV2 = P1与C1异或
4.P2、IV2异或,再经过Key加密,得到C2,下一分组IV3 = P2与C2异或
...
5.Pn、IVn异或,再经过Key加密,得到Cn
6.拼接C0、C1、...、Cn得到密文,加密结束

XTS

XEX(Xor–Encrypt–Xor) encryption mode with tweak and ciphertext stealing或XEX-based tweaked-codebook mode with ciphertext stealing (XTS), 由《IEEE p1619-2007》定义的对称分组密码算法的一种加密模式,使用了密文窃取技术,主要用于存储数据加密(如磁盘)

【128-bit-block-Enc:C = XTS-AES-block_Enc(Key, P, i, j)】
Key:256或者512bit,长度为普通AES密钥长度的2倍,等分为两个AES密钥,Key=key1||key2
P:128bit明文
i:128-bit tweak value
j:当前128-bit block在DataUnit内的序号
C:128bit密文

【DataUnit-Enc:C = XTS-AES-block_Enc(Key, P, i)】

XTS_ENC-for Plen>=128bit or more

//《IEEE_1619_2007_standard_for_cryptographic_protection_of_data_on_block_oriented_storage_devices.pdf》
//Input
Key //is the 256 or 512 bit XTS key
P //is the plaintext, bitlen(p)>=128
i //is the value of the 128-bit tweak
//Output
C

//calc step
P = P0||P1||...||Pm
1.for q <- 0 to m-2 do
    Cq = XTS_blockEnc(key, Pj, i, q)
2.b=bit_len(Pm)
3.if b == 0
    Cm-1 = XTS_blockEnc(key,Pm-1, i, m-1)
    Cm = empty
  else
    CC=XTS_blockEnc(key,pm-1,i,m-1)
    Cm=first b bits of CC
    CP=last (128-b) bits of CC
    PP=Pm || CP
    Cm-1=XTS_blockEnc(key,PP,i,m)
4.return C=C1||...||Cm-1||Cm

//XTS_blockEnc calc step
key=key1||key2
T=Enc(key2, i) ⊗ (alpha^j)
PP = P ⊕ T
CC=Enc(key1, PP)
C=CC ⊕ T

//T ⊗ (alpha)// multiply T by alpha
//input:T
//output:T
Cin = 0;
for (j=0;j<16;j++)
{
    Cout=(T[j]>>7)&1
    T[j]=((T[j]<<1)+Cin) & 0xFF
    Cin=Cout
}
if Cout
    T[0]^=0x87//GF_128_FDBK
//XTS AES128_Enc Demo
//Input
//key-256bit-32byte
27F86757EE3A22CF321E2C04931DD95F//key1
9DAD1FD72D56817C4E3E0A49AA462378//key2
//i
11223344556677881122334455667788//must be a block
//plain-33byte
27C066D4F46C716C9C7F7ED01F4B6812
CAE8E5549F276F703D7AEBFA397A74D3
11

//output
6654931E11319CAECDA1801149E740E2
18713E0EC80926DF795E3613E6570E21
01

//block-1
//T = AES128_ECB(key2,i)
D1184F906DB0B8368CC8639E3F337011
//PP = P ⊕ T
27C066D4F46C716C9C7F7ED01F4B6812^
D1184F906DB0B8368CC8639E3F337011
=F6D8294499DCC95A10B71D4E20781803
//CC=Enc(key1, PP)
=Enc(27F86757EE3A22CF321E2C04931DD95F,F6D8294499DCC95A10B71D4E20781803)
=B74CDC8E7C8124984169E38F76D430F3
//C=CC ⊕ T
B74CDC8E7C8124984169E38F76D430F3^
D1184F906DB0B8368CC8639E3F337011
=6654931E11319CAECDA1801149E740E2

//block-2 and block-3 (last)
// T ⊗ (alpha)// multiply T by alpha
a2319e20db60716d1891c73c7f66e022

//calc CC
//CC = Pm-1 ⊕ T
CAE8E5549F276F703D7AEBFA397A74D3^
a2319e20db60716d1891c73c7f66e022
=68D97B7444471E1D25EB2CC6461C94F1
//CC=Enc(key1, CC)
=Enc(27F86757EE3A22CF321E2C04931DD95F,68D97B7444471E1D25EB2CC6461C94F1)
=A33A4CEE7D5D5BCFB8868304988D182B
//CC=CC ⊕ T
A33A4CEE7D5D5BCFB8868304988D182B^
a2319e20db60716d1891c73c7f66e022
=010BD2CEA63D2AA2A0174438E7EBF809

//Cm=first b bits of CC
Cm=01

//PP = Pm||CP=last(128-b) bits of CC
11||0BD2CEA63D2AA2A0174438E7EBF809

//clac Cm-1
// T ⊗ (alpha)// multiply T by alpha
44633c41b6c1e2da30228f79feccc045
//Cm-1 = PP ⊕ T
110BD2CEA63D2AA2A0174438E7EBF809^
44633c41b6c1e2da30228f79feccc045
=5568EE8F10FCC8789035CB411927384C
//Cm-1=Enc(key1, CC)
=Enc(27F86757EE3A22CF321E2C04931DD95F,5568EE8F10FCC8789035CB411927384C)
=5C12024F7EC8C405497CB96A189BCE64
//Cm-1=Cm-1 ⊕ T
5C12024F7EC8C405497CB96A189BCE64^
44633c41b6c1e2da30228f79feccc045
=18713E0EC80926DF795E3613E6570E21

C=C1||Cm-1||Cm
=6654931E11319CAECDA1801149E740E2||18713E0EC80926DF795E3613E6570E21||01

最后两个分组处理流程(非分组对齐)

image-20250528104652524

ECB

由NIST SP800-38A所定义的密码分组链接模式(Cipher Block Chaining)

过于简单,略。

HCTR2

标准链接:https://csrc.nist.gov/csrc/media/Events/2023/third-workshop-on-block-cipher-modes-of-operation/documents/accepted-papers/Length%20Preserving%20Encryption.pdf

各模式对比

操作对象

模式 KEY个数 IV 加密对象 并行处理
ECB 1 N 明文分组 Enc&Dec
CBC 1 Y 明文分组与前一分组的异或后的值 Dec
CFB 1 Y 前一分组输出的密文 Dec
OFB 1 Y 前一分组中对IV加密后的值 NA
CTR 1 N 计数器CRT的值 Enc&Dec
XTS 2 N 明文和tweak值 Enc&Dec

优缺点

模式 优 缺
ECB 1.简单
2.快速
3.支持并行计算
1.明文中的重复排列会反馈在密文中
2.通过删除、替换密文分组可以对明文进行操作
3.不能抵御重放攻击
CBC 1.明文的重复排列不会反馈在密文中
2.支持并行计算(仅解密)
3.能够解密任意密文分组
1.加密不支持并行计算
2.对包含某些错误比特的密文进行解密时,第一个分组的全部比特以及后一个分组的相应比特会出错
CFB 1.不需要填充
2.支持并行计算(仅解密)
3.能解密任意密文分组
1.加密不支持并行计算
2.对包含某些错误比特的密文进行解密时,第一个分组的全部比特以及后一个分组的相应比特会出错
3.不能抵御重放攻击
OFB 1.不需要填充
2.可事先进行加密解密的准备
3.加解密使用相同结构
4.对包含某些错误bit的密文进行解密时,只有明文中相应的bit会出错
5.支持并行计算(加解密)
1.不支持并行计算
2.主动攻击者翻转密文分组中的某些bit,明文分组中相应的bit也会被翻转
CTR 1.不需要填充
2.可事先进行加密解密的准备
3.加解密使用相同结构
4.对包含某些错误bit的密文进行解密时,只有明文中相应的bit会出错
5.支持并行计算(加解密)
1.主动攻击者翻转密文分组中的某些bit,明文分组中相应的bit也会被翻转
XTS 1.支持并行计算(加解密)
2.可事先进行加密解密的准备
1.不能抵御重放攻击
2.对包含某些错误bit的密文,第一个分组的全部bit以及后一分组的相应bit会出错

填充模式

NoPadding

不填充,在此模式下原始数据必须是分组长度的整数倍

PKCS5_PKCS7

PKCS5:块大小固定为8
PKCS7:块大小1-255
以AES为例:分组长度16字节

填充方式为:满分组需要增加1block,不满分组需要填充至满分组,每字节填充值为(blocklen-bytes%blocklen)

原始:11223344556677881122334455667788
填充:11223344556677881122334455667788 10101010101010101010101010101010

原始:112233445566778811
填充:11223344556677881107070707070707

ISO/IEC7816-4

填充方式为:满分组需要增加1block,不满分组需要填充至满分组,先在数据右侧填充80,其他填充00至满分组

以AES为例:分组长度16字节

原始:11223344556677881122334455667788
填充:11223344556677881122334455667788,80000000000000000000000000000000

原始:112233445566778811
填充:11223344556677881180000000000000

ZeroPadding

填充00至满分组,若原始数据为分组整数倍,不需要填充

原始:11223344556677881122334455667788
填充:11223344556677881122334455667788

原始:112233445566778811
填充:11223344556677881100000000000000

PKCS1Padding

该填充模式是 RSA 加密中使用的,详见 RFC 2313。RSA 加密时,需要将原文填充至密钥大小,填充的格式为:00 + BT + PS + 00 + D。

  • 00 为固定字节

  • BT 为处理模式。公钥操作时为 02,私钥操作为 00 或 01

  • PS 为填充字节,填充数量为 k - 3 - D,k 表示密钥长度,D 表示原文长度。PS 的最小长度为 8 个字节。填充的值根据 BT 值不同而不同:

  • BT = 00 时,填充全 00

  • BT = 01 时,填充全 FF

  • BT = 02 时,随机填充,但不能为 00

ANSI X.923

填充的字节长度=块长度-(数据长度%块长度)

当不满分组长度时,填充“0”字节。最后一个字节填充padding的长度

1122334455667788 || 1122334455000003

当满分组长度时,

1122334455667788 || 0000000000000008

ISO 10126

填充若干随机字节,最后一个字节填充padding长度

ISO IEC 9797-1-2011

Padding Method 1
消息末尾填充尽可能少的0000直到满分组
注:如果消息为空,填充满分组0;如果满分组,不填充

Padding Method 2
消息末尾写1bit值‘1’,填充0000直到满分组
注:如果消息为空,填充1000..00直满分组;如果满分组,填充1000..00直满分组

Padding Method 3
输入到 MAC(消息认证码)算法的数据字符串 D应该右填充尽可能少的(可能为零个)‘0’ 位,以获得一个长度(以位为单位)为正整数倍的 的数据字符串。结果字符串随后将左填充一个块 L。块 L 由原始(未填充)数据字符串 D 的长度(以位为单位)LD 的二进制表示构成,并根据需要左填充尽可能少的(可能为零个)‘0’ 位,以形成一个 n 位的块。块 L 的最右边位对应于 LD 的二进制表示的最低有效位。

Padding Method 4
如果输入到 MAC(消息认证码)算法的数据字符串 D 的长度(以位为单位)是正整数倍的 n,则不应进行填充。否则,数据字符串 D 应该右填充一个单独的‘1’位。然后,结果字符串应继续右填充尽可能少的(可能为零个)‘0’位,以获得一个长度(以位为单位)为正整数倍的 n 的数据字符串。
注:跟【Padding Method 2】非常类似,区别在于满分组下,该padding不需要填充

填充示例,取自标准(标准只提供了Method1/2/3)

//原始数据-DES
4E6F77206973207468652074696D6520666F7220616C6C20  //3block=24byte=192bit
//Padding Method 1
4E6F77206973207468652074696D6520666F7220616C6C20
//Padding Method 2
4E6F77206973207468652074696D6520666F7220616C6C208000000000000000
//Padding Method 3
00000000000000C04E6F77206973207468652074696D6520666F7220616C6C20
//Padding Method 4
4E6F77206973207468652074696D6520666F7220616C6C20

9、Padding Oracles

如果输入的密文不合法,类库则会抛出异常,这便是一种提示。攻击者可以不断地提供密文,让解密程序给出提示,不断修正,最终得到的所需要的结果。这里的一个关键在于,攻击者所需要的提示仅仅是“解密成功与否”这样一个二元信息

【示例1】
前提
1.假设明文“TEST”(攻击者未知)经过加密成密文:6D367076036E2239F851D6CC68FC9537
2.服务器对解密只返回解密成功(不对比原文)或者填充位错误

攻击
手段:破解得到中间值(服务器对密文加密后的值),然后与IV异或得到明文
1.由于IV和密文分组等长,得IV=6D367076036E2239,C=F851D6CC68FC9537
2.IV置零,假设解密后的明文最后一字节为01(含填充),改变IV最后一个字节,IV=00000000000000XX,将C和IV上送服务器解密,直到不报填充位错误,最多256次遍历
3.将XX与01异或,得到中间值最后一字节TT
4.继续,IV=000000000000XXTT,将C和IV上送服务器解密,直到不报填充位错误,最多256次遍历
5.将XX与02异或,得到中间值TT
......
6.以此类推,直到中间值全部找出来,与密文异或,得到明文

攻击防范
1)先加密再认证
2)Nonce机制:Nonce不重用

密钥协商算法

Diffie-Hellman

国密算法

SM4(SMS4):对称算法,算法公开,分块长度16字节
SM1(SCB/SCB2):对称算法,算法不公开,分块长度16字节
SSF33:对称算法,算法不公开,分块长度16字节
SM6:对称算法,算法不公开,分块长度16字节
SM7:对称算法,算法不公开,分块长度16字节

10、密钥和分组长度

算法 key长度bit 分组长度bit
DES 64 64
TDES-128(2key) 128 64
TDES-192(3key) 192 64
AES-128 128 128
AES-192 192 128
AES-256 256 128
SM4 128 128

消息认证码

CBC-MAC流程

特点:
1)不需要IV(IV = 0)

IV = 00...00
for i = 1 to n //n分组
{
    temp = M_i XOR IV
    temp = Enc(K,temp)
    IV = temp;
}
最后一个密文block作为MAC

另外有标准,提到MAC的一些填充方式, 如《ISO/IEC 9797-1》

CMAC

由NIST SP800-38B所定义的用于认证的CMAC模式(Cipher-based Message Authentication Code)

标准:《RFC3610》《NIST-SP800-38B》

//《NIST-SP800-38B》
//Input,两个子密钥生成
Key
block cipher CIPH with block size b
//Output
subKeys K1、K2

//Step
1)当原文长度不是分组长度的整数倍时(10填充),最后一组明文与k2异或后进行CBC加密
2)当原文长度为分组长度的整数倍时,最后一组明文(不需padding)与k1异或后进行CBC加密
3)T长度至少64bit

当消息为空,block数量为1,即10填充后,与k2异或后进行CBC加密

子密钥生成流程

Prerequisites:
block cipher CIPH with block size b
key K

Output:
subkeys k1,k2

Suggested Notation:
SUBK(K)

Steps:
1.Let L = CIPH_k(0_b)//使用密钥对全0的分组做ECB加密
2.if MSB_1(L) = 0, then k1 = L<<1;
  else k1 = (L<<1) xor B_b //see follow
3.if MSB_1(k1) = 0, then K2 = k1<<1
  else k2 = (k1<<1) xor R_b
4.return k1,k2

R_128 = 0_120||10000111 = (0_15||87)hex
R_64 = 0_59||11011 = (0_7||1B)hex

CMAC计算示例

//AES128-CMAC
//key
e07099f1bfaffd7f240cd790ca4fe134
//k1
7051501d5233e9d2e1f43857dc30888c
//k2
e0a2a03aa467d3a5c3e870afb8611118

L=DES_ECB(key,00.00)=3828A80EA919F4E970FA1C2BEE184446
MSB_1(L)=0,k1=L<<1=7051501d5233e9d2e1f43857dc30888c
MSB_1(k1)=0,k2=(k1<<1) =7051501d5233e9d2e1f43857dc30888c<<1=e0a2a03aa467d3a5c3e870afb8611118
//DES CMAC
 k1: 9cce53a2d96b4d28
 k2: 399ca745b2d69a4b
 key: e07099f1bfaffd7f
//calc subkey
L=DES_ECB(key,00.00)=4E6729D16CB5A694
MSB_1(L)=0,k1=L<<1=9cce53a2d96b4d28
MSB_1(k1)=1,k2=(k1<<1) xor R_b=399CA745B2D69A50 xor 000000000000001B=399CA745B2D69A4B

//msg
616263
//pad
6162638000000000
//pad(msg) XOR k2
58FEC4C5B2D69A4B
//res=Enc(key, (pad(msg) XOR k2))
EE3F707F2C11D297

399CA745B2D69A50
000000000000001B

//msg
248F9D
//msg||padding
248F9D8000000000
//res=Enc(key, (pad(msg) XOR k2))
Enc(1D133AC5B2D69A4B)
=B8F9226E6B34BAE4
//DES CMAC
 k1: 9cce53a2d96b4d28
 k2: 399ca745b2d69a4b
 key: e07099f1bfaffd7f
//calc subkey
L=DES_ECB(key,00.00)=4E6729D16CB5A694
MSB_1(L)=0,k1=L<<1=9cce53a2d96b4d28
MSB_1(k1)=1,k2=(k1<<1) xor R_b=399CA745B2D69A50 xor 000000000000001B=399CA745B2D69A4B

//iv
0000000000000000
//msg
0001020304050607
08090a0b0c0d0e0f
//pad
0001020304050607
08090a0b0c0d0e0f

//cbc加密第一个分组
58BD1B8CEBD10955

//第二分组与k1异或
08090a0b0c0d0e0f xor 9cce53a2d96b4d28
=94C759A9D5664327
//msg
0001020304050607
94C759A9D5664327

//整个msg做cbc
58BD1B8CEBD10955
87B39963013D547F
//SM4-CMAC
//key
E07099F1BFAFFD7F240CD790CA4FE134
k1: 1d016f274a3a18888c48f7e5401a17d2
k2: 3a02de4e947431111891efca80342fa4
//p
000102030405060708090a0b0c0d0e0f
101112131415161718191a1b1c1d1e1f
202122232425262728292a2b2c2d2e2f
303132333435363738393a3b3c3d3e3f
40

//cmac
09D7F12496D4E84C39C05F298FD39DC5

1)IV=0..0
Enc(IV XOR 000102030405060708090a0b0c0d0e0f)=20B93A0C8A401D018464875F408136DE

2)IV=20B93A0C8A401D018464875F408136DE
Enc(IV XOR 101112131415161718191a1b1c1d1e1f)
=Enc(30A8281F9E550B169C7D9D445C9C28C1)
=F1295C1E1FFABBDADC0E909E1E2E2DC2

3)IV=F1295C1E1FFABBDADC0E909E1E2E2DC2
Enc(IV XOR 202122232425262728292a2b2c2d2e2f)
=Enc(D1087E3D3BDF9DFDF427BAB5320303ED)
=DA3AEEDBDBAD4F411C2EA7F7D352138B

3)IV=DA3AEEDBDBAD4F411C2EA7F7D352138B
Enc(IV XOR 303132333435363738393a3b3c3d3e3f)
=Enc(EA0BDCE8EF98797624179DCCEF6F2DB4)
=E557ECCBA0181C95D0EDF6D566064081

//最后block非block整数倍,k2 xor 后加密
3) IV=K2=3a02de4e947431111891efca80342fa4
(K2 XOR 40800000000000000000000000000000)
=(7A82DE4E947431111891EFCA80342FA4)

Enc(E557ECCBA0181C95D0EDF6D566064081 XOR 7A82DE4E947431111891EFCA80342FA4)
=Enc(9FD53285346C2D84C87C191FE6326F25)
=09D7F12496D4E84C39C05F298FD39DC5
//SM4-CMAC
//key
e07099f1bfaffd7fe07099f1bfaffd7f
//plain
e07099f1bfaffd7fe07099f1bfaffd7f
e07099f1bfaffd7fe07099f1bfaffd7f
e07099f1bfaffd7fe07099f1bfaffd7f

//mac
458AB613526E09AB50C7A7B8EC6CD753

//流程
 k1: 22b4c22b9e8e8b9c23c9da876039a8dc
 k2: 456984573d1d17384793b50ec07351b8

1)IV=0..0
Enc(IV XOR block1)=1B2273875F25284EA8823A473CD88E5C

2)IV=1B2273875F25284EA8823A473CD88E5C
Enc(IV XOR block2)
=Enc(1B2273875F25284EA8823A473CD88E5C XOR e07099f1bfaffd7fe07099f1bfaffd7f)
=Enc(fb52ea76e08ad53148f2a3b683777323)
=F76BFA239CC75759CB83F8D78E7B30DF

3) IV=K1=22b4c22b9e8e8b9c23c9da876039a8dc
(K1 XOR block3)
=(22b4c22b9e8e8b9c23c9da876039a8dc XOR e07099f1bfaffd7fe07099f1bfaffd7f)
=(c2c45bda212176e3c3b94376df9655a3)

Enc(c2c45bda212176e3c3b94376df9655a3 XOR F76BFA239CC75759CB83F8D78E7B30DF)
=Enc(35afa1f9bde621ba083abba151ed657c)
=458AB613526E09AB50C7A7B8EC6CD753
//TDES128
//key
E07099F1BFAFFD7F240CD790CA4FE134
k1: f72b4ee8a67f18ae
k2: ee569dd14cfe3147
//p
0001020304050607
08090a0b0c0d0e0f

//std_mac
E4C3593AD6F86AA9

1)IV=0..0
Enc(IV XOR block1)=C0D92C81A7AE8D03

2)IV=C0D92C81A7AE8D03
(k1 xor block2)
=f72b4ee8a67f18ae xor 08090a0b0c0d0e0f
=FF2244E3AA7216A1

CBC(IV, (FF2244E3AA7216A1))
=E4C3593AD6F86AA9

GMAC的计算

https://zhuanlan.zhihu.com/p/376692295

HMAC

《FIPS198-1》

HMAC是一种基于hash函数和密钥进行消息认证的方法
流程图:https://zhuanlan.zhihu.com/p/336054453

//输入
    K:秘密密钥
    message:消息
    w:压缩分组大小(哈希函数分组大小)
    Tlen:要求的MAC标记长度
//输出
    Tag:MAC标记

1. if length(K) > w then
    K = hash(K)
   else
    对K进行0填充至w字长
2. hmac = hash((opad XOR K) || hash(ipad XOR K || message))
3. 通过只保留前Tlen字节作为Tag

注:
1)ipad为00110110(0x36)的循环,直到达到单项散列函数的分组长度。
2)opad为01011100(0x5C)的循环,直到达到单项散列函数的分组长度。
//手动计算与在线计算验证HSHA256(分组512bit,输出256bit)
M:ABC(hex格式:616263)
K:313233343536(hex格式)
alg:SHA256
//在线计算
res:f6ced6f4883ffc0981a6b9945819f680102b43097ad8ef7a0df9bde06fb3d2e4

//手动计算,运算过程均为hex,验证成功
//K = K(pad)
31323334353600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
//ipadKey = ipad XOR K:
36363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636^
31323334353600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
=07040502030036363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636
//opadKey = opad XOR K
5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C^
31323334353600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
=6D6E6F68696A5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C
//SHA256(ipadKey || meassage)
=SHA256(07040502030036363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636363636||616263)
=29B4C2EE6B7392016EEB0E5729790C1F299B551F54902E78AD049BC33D8EF29C
//Tag=SHA256(opadKey||SHA256(ipadKey || meassage))
SHA256(6D6E6F68696A5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C5C||29B4C2EE6B7392016EEB0E5729790C1F299B551F54902E78AD049BC33D8EF29C)
=F6CED6F4883FFC0981A6B9945819F680102B43097AD8EF7A0DF9BDE06FB3D2E4

CRC校验码

https://blog.csdn.net/GMingZhou/article/details/111386451

计算示例:
1.选择CRC生成多项式G(X)=X4+X3+1
2.原数据二进制:10110011
3.CRC位数4(总位数(最高幂次+1,即4+1=5)-1)

计算过程:
1.把多项式转成二进制:11001
2.原数据后补CRC位数个零:10110011 || 0000
3.将2对1进行”模2除法“得到余数(不足4位前面补0)
4.执行步骤1-3,得到余数0100,即CRC校验码

“模2除法”:我们知道模2加减是不进位、不借位的加减法,比如1+1=0,1+0=1,101+011=110,等于每一位的异或运算,相同bit加减为0,不同bit加减则为1。模2除法同理,即当部分余数首位是1时商取1,反之商取0。然后每一位的减法运算是按位减,不产生借位。余数的位数一定要是比除数位数只能少一位,哪怕前面位是0,甚至是全为0(附带好整除时)也都不能省略。

AES_XCBC_MAC_96

标准:《RFC3566》

//Input
Key //128bit
Plaintext //could be NULL
//preprocess:calc subkey
t1 = 0x010101010101010101010101010101
t2 = 02020202020202020202020202020202
t3 = 03030303030303030303030303030303
K1 = AES128_ECB_ENC(Key, t1)
K2 = AES128_ECB_ENC(Key, t2)
k3 = AES128_ECB_ENC(Key, t3)
//Output
Mac //occupy 12 Bytes

//Step
1)初始iv全0
2)中间block进行CBC运算
1)当原文长度不是分组长度的整数倍时(10填充),最后一组明文与k3异或后进行CBC加密
2)当原文长度为分组长度的整数倍时,最后一组明文(padding)与k2异或后进行CBC加密
//《NIST-SP800-38B》

标准文档

《NIST-SP800-38C》

CCM

//CCM
//5.1 底层块密码算法和密钥的选择
the forward cipher function前向密码函数是对固定比特长度的比特串的函数,长度为块,128位
//5.2 两个加密原语的操作讨论要求
向前密码功能、CTR模式
//5.3 CCM元素
A:附加认证数据,可以为空,CCM没有为A提供保密性
P:CCM保护的数据消息组成
N:用一次的位串,不要求随机
T:CCM-MAC值
//5.4 有效数据元素讨论-输入格式化
1.第一块B0,唯一确定的Nonce
2.第一块B0,独特于其他技术块(整个调用过程中)
3....
4.格式化函数对N、P、A、Tlen有长度限制,例如Tlen<32的无效
//5.5 操作和function的例子
LBS3(111011010) = 010
MBS4(111011010) = 1110
lg(2^10) = 10

//CCM规格
1.计数器可以被使用前任何时间生成
//生成-加密过程
1.先行条件
    块加密算法、Key、计数器生成函数、格式化函数、MAC长度TLen
2.输入
    N(Nonce)、P(有效负载明文)、A(附加认证数据)
3.输出
    C(密文)
4.Steps
    1) 应用格式化函数从(N、A、P)生成B0,...,Br
    2) Set Y0 = CIPHK(B0)
    3) for i=1 to r do {Yi = CIPHK(Bi XOR Yi-1)}
    4) Set T = MSB_TLen(Yr)
    5) 利用计数器生成函数生成Ctr0,...,Ctrm,其中m = PLen/128
    6) for j=1 to m do {Sj = CIPHK(Ctrj)}
    7) Set S = S1||S2||...||Sm
    //以下看是密文+Mac
    8) Return C = (P XOR MSB_PLen(S))||(T XOR MSB_TLen(S0))

//解密-认证
1.先行条件
    块加密算法、Key、计数器生成函数、格式化函数、MAC长度TLen
2.输入
    N(Nonce)、C(密文)、A(附加认证数据)
3.输出
    P(明文)或者错误信息
4.Steps
    1) if CLen < T,return INVALID
    2) 利用计数器生成函数生成Ctr0,...,Ctrm,其中m = PLen/128
    3) for j=1 to m do {Sj = CIPHK(Ctrj)}
    4) Set S = S1||S2||...||Sm
    5) Set P = MSB_Clen-Tlen(C) XOR MSB_Clen-Tlen(S) //把T去掉,异或恢复明文
    6) Set T = LSB_Clen-Tlen(C) XOR MSB_Clen-Tlen(C)
    7) 应用格式化函数从(N、A、P)生成B0,...,Br
    8) Set Y0 = CIPHK(B0)
    9) for i=1 to r do {Yi = CIPHK(Bi XOR Yi-1)}
    10) if T != MSB_Tlen(Yr) return INVALID
        else return P

《RFC4309》-AES_CCM

AES-CCM
https://rfc2cn.com/rfc4309.html

//AES CCM有两个参数:
//M表示完整性检查值(ICV)的大小。CCM定义了4、6、8、10、12、14和16个八位字节的值;但是,为了保持对齐并提供足够的安全性,只允许使用四的倍数且至少为八的值。实现必须支持8个八位字节和16个八位字节的M值,并且实现可以支持12个八位字节的M值。
M  

//L表示长度字段的大小(以八位字节为单位)。CCM定义2个八位字节和8个八位字节之间的L值。本规范仅支持L=4。实现必须支持4个八位字节的L值,这可以容纳一个完整的巨型程序[JUMBO];但是,长度包括所有加密数据,其中还包括ESP Padding、Pad length和Next Header字段。
L

//CCM发起人处理有4个输入
//密钥单个密钥用于使用CBC-MAC计算ICV,并使用计数器模式执行有效负载加密。AES支持128位、192位和256位的密钥大小。默认键大小为128位,实现必须支持此密钥大小。实现还可以支持192位和256位的密钥大小。
Key

//nonce nonce的大小取决于为参数L选择的值。它是15-L八位字节。实现必须支持11个八位字节的nonce。第4节描述了nonce的构造
Nonce

//有效载荷ESP数据包的有效载荷。有效载荷不得超过4294967295个八位字节,这是一个巨型程序[JUMBO]的最大大小;但是,ESP Padding、Pad Length和Next Header字段也是有效负载的一部分。
ESP //ESP = IV(8 octets) || Encrypted Payload || Authentication

//AAD CCM为有效负载之外的某些数据提供数据完整性和数据源身份验证。CCM不允许附加认证数据(AAD)的长度超过18446744073709551615个八位字节。ICV根据ESP标题、有效载荷和ESP拖车字段计算,该字段明显小于CCM施加的限制。第5节中描述的AAD施工
AAD

注意:

1)同一IV和钥匙组合不得使用多次
2)KEYMAT的大小等于AES密钥长度+3字节
3)《RFC3610》提供测试向量

《RFC3610》//CCM

Counter with CBC-MAC(CCM)
CCM定义用于128位分组密码,如AES

CBC-MAC(CCM)计数器是一种通用的认证加密分组密码模式。CCM定义用于128位分组密码,如高级加密标准(AES)。

//CCM Mode Specification
//身份验证字段的大小。M值的选择涉及消息扩展和攻击者无法检测到修改消息的可能性之间的权衡。有效值为4、6、8、10、12、14和16个八位字节
M

//长度字段的大小。此值需要在最大消息大小和Nonce大小之间进行权衡。不同的应用程序需要不同的权衡,因此L是一个参数。L的有效值范围在2个八位字节和8个八位字节之间(保留值L=1)
L

//Input
//分组密码的加密密钥K
Key

//15-L个八位组的一个非正数N,唯一值,对使用相同密钥加密的两条不同消息使用相同Nonce会破坏此模式的安全属性
//有效长度:7-13字节(15-L)
N

//消息M
M

//附加认证数据,此附加数据经过身份验证但未加密,不包含在此模式的输出中,可用于验证明文数据包头,或影响消息解释的上下文消息。不希望验证其他数据的用户可以提供长度为0的字符串
aad
//计算认证字段T步骤
//1.定义B_0...B_n序列
字节序号:   0     || 1..15-L || 16-L...15
内容    : Flags       Nonce       Len(M)
//Flags of B_0
位序号:    7           ||  6   ||5..3  ||2..0
内容  : Reserved(通常为0)  Adata     M'    L'
if len(aad)>0 Adata = 1 else Adata = 0
M' = [1,7]
L' = L-1,保留0值  //Len(M)

//2.使用CTR模式,定义密钥流块
S_i = E(K, A_i) for i=0 to ... //S_0不用于加密消息
//值A_i的格式
位序号:0   ||  1..15-L ||  16-L..15
内容 :Flags    Nonce       Counter_i
//CBC-MAC计算流程
X_1 = E(K, B_0)
X_i+1 = E(K, X_i XOR B_i) for i=1 to n
T = first_M_bytes(X_n+1)

AES128-CCM计算流程1

B0构造(16byte)

Octet Number Contents
0 Flags
1 ... 15-L Nonce N
16-L ... 15 ByteLength(message)

Flags格式(1byte)

Octet Number Contents
7 Reserved (always is 0)
6 Adata(if len(aad) > 0, value is 1,else value is 0)
5 ... 3 M' = (M-2)/2, so M' = [1,7]
2 ... 0 L' = L -1, so L' = [0,7]

B1起始构造(2byte)

first two octets followed by Comment
0x0000 nothing Reserved
0x0001 ... 0xFEFF nothing 0 < ByteLen(aad) < (2^16 - 2^8)
0xFF00 ... 0xFFFD nothing Reserved
0xFFFE 4 octets of ByteLen(aad) (2^16 - 2^8) <= ByteLen(aad) < (2^32)
0xFFFF 8 octets of ByteLen(aad) (2^32) <=ByteLen(aad) < (2^64)

Si构造(i=0, 1, 2...)(16byte)

Octet Number Contents
0 Flags(对于Si, bit[0:3]为L', 其余bit为0),即Flags=L’
1 ... 15-L Nonce N
16-L ... 15 Counter i

注:S0经CTR计算得到最终MAC

总流程:
1.根据Nonce长度,Mac长度,AAD长度,消息长度,来构造B0
2.根据AAD构造B1起始,如果AAD=NULL,不占一个block
3.根据Message构造剩余block,0填充,如果Message=NULL,不占一个block

//-------------------------Input5---------------------------
//key-AES128-16bytes
27F86757EE3A22CF321E2C04931DD95F
//Nonce-7Bytes //有效位7-13bytes //so L=15-7=8
11223344556677
//AAD-15bytes 
D3691BC11966725BAD706DD7FAEF81
//plaintext-0bytes
NULL
//M=length(Mac)
6
//-------------------------Output5---------------------------
//cipher
NULL
//Tag
CA0EE26E9FE4


//B0-hex
57
11223344556677
0000000000000000
//Flag-bin,对应hex(‭00010111‬)=0x17
0//Reserved (always is 0)
1//Adata(if len(aad) > 0, value is 1,else value is 0)
010//M' = (M-2)/2, so M' = [1,7]
111//L' = L -1, so L' = [0,7]

//S0 - CTR IV
07//0Flags(对于Si, bit[0:3]为L', 其余bit为0),即Flags=L’
11223344556677//Nonce N
0000000000000000//Counter i

//blocks
57112233445566770000000000000000
000FD3691BC11966725BAD706DD7FAEF
81000000000000000000000000000000

//将blocks带入CBC计算得到最后一组block
D4A26C759CAF5A1330991E8563756A8C
//中间tag值,最后一组block,截取前M字节,并0填充(其实没必要做,因为ctr字节流加密,不影响前M字节)
D4A26C759CAF00000000000000000000
//IV为S0=07112233445566770000000000000000,中间tag值进行CTR加密计算,得
CA0EE26E9FE43C255FFD2386AE216B85
//Mac
CA0EE26E9FE4
//-------------------------Input4---------------------------
//key-AES128-16bytes
27F86757EE3A22CF321E2C04931DD95F
//Nonce-7Bytes //有效位7-13bytes //so L=15-7=8
11223344556677
//AAD-0bytes 
NULL
//plaintext-16bytes
NULL
//M=length(Mac)
6
//-------------------------Output4---------------------------
//cipher
NULL
//Tag
C246B98F34CC


//B0-hex
17
11223344556677
0000000000000000
//Flag-bin,对应hex(‭00010111‬)=0x17
0//Reserved (always is 0)
0//Adata(if len(aad) > 0, value is 1,else value is 0)
010//M' = (M-2)/2, so M' = [1,7]
111//L' = L -1, so L' = [0,7]

//S0 - CTR IV
07//0Flags(对于Si, bit[0:3]为L', 其余bit为0),即Flags=L’
11223344556677//Nonce N
0000000000000000//Counter i

//blocks
17112233445566770000000000000000

//将blocks带入CBC计算得到最后一组block
DCEA379437877AB8CCD74C12F01F31BE
//中间tag值,最后一组block,截取前M字节,并0填充(其实没必要做,因为ctr字节流加密,不影响前M字节)
DCEA3794378700000000000000000000
//IV为S0=07112233445566770000000000000000,中间tag值进行CTR加密计算,得
C246B98F34CC66366F643D03CD540109
//Mac
C246B98F34CC
//-------------------------Input3---------------------------
//key-AES128-16bytes
27F86757EE3A22CF321E2C04931DD95F
//Nonce-7Bytes //有效位7-13bytes //so L=15-7=8
11223344556677
//AAD-0bytes 
NULL
//plaintext-16bytes
3A1A07582FEECD2F6C42D18A04189082
//M=length(Mac)
6
//-------------------------Output3---------------------------
//cipher
B82F54D9D7AE4D0E739BA821416A4C46
//Tag
F6049BE2C785


//B0-hex
17
11223344556677
0000000000000010
//Flag-bin
//0x17
0
0
010
111

//S0
07
11223344556677
0000000000000000

//blocks
17112233445566770000000000000010
3A1A07582FEECD2F6C42D18A04189082

//将blocks带入CBC计算(IV为全0)得到最后一组block 
E8A815F9C4CEF6326EA31BA1E12232A3
//中间tag值,最后一组block,截取前M字节,并0填充
E8A815F9C4CE00000000000000000000
//IV为S0=07112233445566770000000000000000,中间tag值进行CTR加密计算,得
F6049BE2C78566366F643D03CD540109
//Mac
F6049BE2C785
//计算密文,IV++,CTR加密
B82F54D9D7AE4D0E739BA821416A4C46
//-------------------------Input1---------------------------
//key-AES128-16bytes
27F86757EE3A22CF321E2C04931DD95F
//Nonce-7Bytes //有效位7-13bytes //so L=15-7=8
11223344556677
//AAD-15bytes 
D3691BC11966725BAD706DD7FAEF81
//plaintext-16bytes
3A1A07582FEECD2F6C42D18A04189082
//M=length(Mac)
6
//-------------------------Output1---------------------------
//cipher
B82F54D9D7AE4D0E739BA821416A4C46
//Tag
198455B4E0AE


//B0-hex
57
11223344556677//Nonce
0000000000000010 //8byte, length(msg)
//Flag-bin
//0x57
0
1
010
111

//S0
07//注意非57,flag=L'
11223344556677
0000000000000000

//blocks
//B0||B1(2byte)||pad(AAD)||pad(msg)
57112233445566770000000000000010
000FD3691BC11966725BAD706DD7FAEF //注意此处前2byte,代表aad实际长度
81000000000000000000000000000000
3A1A07582FEECD2F6C42D18A04189082


//将blocks带入CBC计算得到最后一组block //CBC IV为0
0728DBAFE3E5D9E6A61FA10CE9DA281F
//中间tag值,最后一组block,截取前M字节,并0填充
0728DBAFE3E500000000000000000000
//IV为S0(即A0)=07112233445566770000000000000000,中间tag值进行CTR加密计算,得
198455B4E0AE66366F643D03CD540109
//Mac
198455B4E0AE
//计算密文,IV++,CTR加密
B82F54D9D7AE4D0E739BA821416A4C46//加密可以并行,因为S0已知


//-------------------------Input2---------------------------
//key-AES128-16bytes
27F86757EE3A22CF321E2C04931DD95F
//Nonce-7Bytes //有效位7-13bytes //so L=15-7=8
11223344556677
//AAD-15bytes 
D3691BC11966725BAD706DD7FAEF81
//plaintext-16bytes
3A1A07582FEECD2F6C42D18A04189082
//M=length(Mac)
16
//-------------------------Output2---------------------------
//cipher
B82F54D9D7AE4D0E739BA821416A4C46
//Tag
BD9DE8763952F5AFD0E112B056A084A3


//B0-hex
7F
11223344556677
0000000000000010
//Flag-bin
//0x7F
0
1
111
111

//block
7F112233445566770000000000000010
000FD3691BC11966725BAD706DD7FAEF
81000000000000000000000000000000
3A1A07582FEECD2F6C42D18A04189082

//blocks带入CBC_MAC,得
A331666D3A199399BF852FB39BF485AA
//中间Tag值,截取前M字节,0填充
A331666D3A199399BF852FB39BF485AA
//IV=S0
07112233445566770000000000000000
//中间Tag值进行CTR加密
BD9DE8763952F5AFD0E112B056A084A3
//计算cipher,iv++
B82F54D9D7AE4D0E739BA821416A4C46

2)计算B0

void ccm_get_B0(uint8_t *nonce, uint8_t M, uint8_t L, uint32_t aad_bytes, uint32_t payload_byte, uint8_t out[16])
{
    uint8_t tmp[4];

    //B0 Flag
    out[0] = 0;
    out[0] |= (M - 2) / 2;
    out[0] <<= 3;
    out[0] |= L - 1;

    if (aad_bytes)
    {
        out[0] |= 0x40;
    }

    //B0 nonce
    if (nonce != out + 1)
    {
        memcpy_(out + 1, nonce, 15 - L);
        memset_(out + 1 + 15 - L, 0, L);
    }

    reverse_byte_array((uint8_t *)&payload_byte, tmp, 4);

    if (L <= 4)
    {
        memcpy_(out + 16 - L, tmp + 4 - L, L);
    }
    else
    {
        memcpy_(out + 16 - 4, tmp, 4);
    }
}

3)计算B1

void ccm_get_B1(uint8_t *aad, uint32_t aad_bytes, uint32_t *aad_offset, uint8_t out[16])
{
    uint8_t tmp[4];
    uint32_t current_bytes, left_bytes;

    reverse_byte_array((uint8_t *)&aad_bytes, tmp, 4);

    if (aad_bytes < ((1 << 16) - (1 << 8)))
    {
        memcpy_(out, tmp + 2, 2);
        current_bytes = 2;
        left_bytes = 16 - 2;
    }
    else
    {
        out[0] = 0xFF;
        out[1] = 0xFE;
        memcpy_(out + 2, tmp, 4);
        current_bytes = 6;
        left_bytes = 16 - 6;
    }

    if (aad_bytes <= left_bytes)
    {
        memcpy_(out+current_bytes, aad, aad_bytes);
        memset_(out + current_bytes + aad_bytes, 0, left_bytes - aad_bytes);
        *aad_offset = aad_bytes;
    }
    else
    {
        memcpy_(out + current_bytes, aad, aad_bytes);
        *aad_offset = left_bytes;
    }
}

CCM计算流程2(可能有问题)

文档里的测试数据验证,已成功。

//《RFC3610规范》测试数据验证
//部分流程跟网上一些论文有出入
//https://www.doc88.com/p-3793128718693.html?r=1
//Input
T_L             = 8 //输出Mac的长度,字节
AES Key = C0 C1 C2 C3  C4 C5 C6 C7  C8 C9 CA CB  CC CD CE CF
Nonce   = 00 00 00 03  02 01 00 A0  A1 A2 A3 A4  A5
Total packet length = 31. [Input with 8 cleartext header octets]
          00 01 02 03  04 05 06 07  08 09 0A 0B  0C 0D 0E 0F
          10 11 12 13  14 15 16 17  18 19 1A 1B  1C 1D 1E


//Output
Total packet length = 39. [Authenticated and Encrypted Output]
          00 01 02 03  04 05 06 07  58 8C 97 9A  61 C6 63 D2
          F0 66 D0 C2  C0 F9 89 80  6D 5F 6B 61  DA C3 84 17
          E8 D1 2C FD  F9 26 E0


//1.提取信息
//K
C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF

//IV
5900000003020100A0A1A2A3A4A50017 //IV构造
//IV_Enc = Enc(K,IV)
=EB9D5547730955AB231E0A2DFE4B90D6

//M(带有8个明文标题八位字节的输入)
000102030405060708090A0B0C0D0E0F
101112131415161718191A1B1C1D1E

//Nonce,长度13字节
00000003020100A0A1A2A3A4A5
//T,长度8字节




//2.对报文进行分组
//M1构造:len(aad)用2字节表示 || packet header || zero padding
M1=00080001020304050607000000000000 
M2=08090A0B0C0D0E0F1011121314151617 //开始从原文划分
M3=18191A1B1C1D1E000000000000000000 //00填充




//3.计算T_CBC-MAC
//Block_1 = E(K,IV_Enc^M1)
=E(K,EB9D5547730955AB231E0A2DFE4B90D6^00080001020304050607000000000000)
=E(K,EB955546710A51AE25190A2DFE4B90D6)
=CDB6411E3CDC9B4F5D9258B69EE7F091

//Block_2 = E(K,Block_1^M2)
=E(K,CDB6411E3CDC9B4F5D9258B69EE7F091^08090A0B0C0D0E0F1011121314151617)
=(K,C5BF4B1530D195404D834AA58AF2E686)
=9C38405EA03C1BC904B58B40C76CA2EB

//Block_3 = E(K,Block_2^M3)
=E(K,9C38405EA03C1BC904B58B40C76CA2EB^18191A1B1C1D1E000000000000000000)
=(K,84215A45BC2105C904B58B40C76CA2EB)
=2DC697E411CA83A860C2C406CCAA542F

//T_CBC-MAC = Block_3[0:T_L-1]
=2DC697E411CA8 //取最后一分组密文前T_L字节




//4.计数器CTR加密计算
//A_0
=Enc(K,01||Nonce||0000)
=Enc(K,0100000003020100A0A1A2A3A4A50000)
=3A2E46C8EC33A5485620542C022CC07D
//A_0_first_T_M //截取结果前T_M长度数据
=3A2E46C8EC33A54

//计数器CTR加密计算
//CTR[0000] = 01||Nonce||0001
0100000003020100A0A1A2A3A4A50001

//CTR[0001]
E(K,CTR[0000])
=E(K,0100000003020100A0A1A2A3A4A50001)
=50859D916DCB6DDDE077C2D1D4EC9F97

//CTR[0002]
=E(K,CTR[0001])
=E(K,0100000003020100A0A1A2A3A4A50002)
=7546717AC6DE9AFF640C9C06DE6D0D8F

//CTR[MAC],未知,结果好像没用到
=E(K,CTR[0002])
=E(K,0100000003020100A0A1A2A3A4A50003)
=1E22952AEC3F6B8BB2AE125FF7E3986C //测试答案是3A2E46C8EC33A548




//5.CBC计算分组密文C
//M(已去掉前面带有8个明文标题八位字节的输入)
M1 = 08090A0B0C0D0E0F1011121314151617
M2 = 18191A1B1C1D1E000000000000000000

//C
C1 = M1^CTR[0001]
=08090A0B0C0D0E0F1011121314151617^50859D916DCB6DDDE077C2D1D4EC9F97
=588C979A61C663D2F066D0C2C0F98980
C1 = M2^CTR[0002]
=18191A1B1C1D1E000000000000000000^7546717AC6DE9AFF640C9C06DE6D0D8F
=6D5F6B61DAC384//截取有效长度6D5F6B61DAC384FF640C9C06DE6D0D8F



//6.计算T-CCM 
T-CCM = T_CBC-MAC^A_0_first_T_M
2DC697E411CA83A8^3A2E46C8EC33A54
=17E8D12CFDF926E0


//合并结果hdr||C||T-CCM
0001020304050607||
588C979A61C663D2F066D0C2C0F98980||
6D5F6B61DAC384||
17E8D12CFDF926E0

4、《RFC6655》

本备忘录描述了在传输层安全性(TLS)和数据报TLS(DTLS)内操作的密码块链-消息认证码(CBC-MAC)模式(CCM)计数器中使用高级加密标准(AES),以提供机密性和数据源认证。AES-CCM算法易于紧凑实现,因此适合于受限环境。

RFC3566》//XCBC

AES-XCBC-MAC-96

核心算法思想:
https://www.rfc-editor.org/rfc/rfc3566.html第4点

Input:k(AES128)、msg

Output:mac(96bit=12byte)

Step:
1.k1=Enc(k, 0x01010101010101010101010101010101);
2.k2=Enc(k, 0x02020202020202020202020202020202);
3.k3=Enc(k, 0x03030303030303030303030303030303);
4.C1=AES_CBC(k1,msg_exclude_last_block)
5.if last_block_byte == 16, C2=AES_CBC(k1, last_block⊕k2)
else last_block_byte == 16, C2=AES_CBC(k1, ISO/IEC7816-4_padding(last_block)⊕k3)
6.return C1||C2

明文少于128bits=16Bytes

//根据规范上的测试数据,手动计算了解流程
测试用例 #2:AES-XCBC-MAC-96 与 3 字节输入
密钥(K):000102030405060708090a0b0c0d0e0f
明文 (M) : 000102
AES-XCBC-MAC:5b376580ae2f19afe7219ceef172756f
AES-XCBC-MAC-96:5b376580ae2f19afe7219cee

//第一步,初始化
//Key,16字节128bit
000102030405060708090a0b0c0d0e0f
//M(填充)至分组长度,10*方式,M[1]
00010280000000000000000000000000
//IV,初始0000*
00000000000000000000000000000000

//**********参数配置**********
//从128位密钥中导出3个128bit密钥
//K1 
0x01010101010101010101010101010101
//AES(Key,K1,ECB)
C352805754237F311AC0FFF4E3E03E78

//K2
0x02020202020202020202020202020202
//AES(Key,K2,ECB)
BD862FFB97AD2FB8F8B891F6032F36CB

//K3
0x03030303030303030303030303030303
//AES(Key,K3,ECB)
C1A7ABA1A23A94065807A08CC8EED06E

//E[0]
00000000000000000000000000000000

//验证成功
//当最后一分组不满128bit时,bit位10*补足,下面已补足
Enc(K1,M[n]^E[n-1]^K3)
=Enc(K1,00010280000000000000000000000000^00000000000000000000000000000000^C1A7ABA1A23A94065807A08CC8EED06E)
=Enc(K1,00010280000000000000000000000000^C1A7ABA1A23A94065807A08CC8EED06E)
=Enc(C352805754237F311AC0FFF4E3E03E78,C1A6A921A23A94065807A08CC8EED06E)
=5B376580AE2F19AFE7219CEEF172756F
//从左往右取96bit=12字节数据
5B376580AE2F19AFE7219CEE

明文等于128bits=16Bytes

测试用例 #3:AES-XCBC-MAC-96 与 16 字节输入
密钥(K):000102030405060708090a0b0c0d0e0f
消息(M):000102030405060708090a0b0c0d0e0f
AES-XCBC-MAC:d2a246fa349b68a79998a4394ff7a263
AES-XCBC-MAC-96:d2a246fa349b68a79998a439

//Key
000102030405060708090a0b0c0d0e0f
//M
000102030405060708090a0b0c0d0e0f
//K1 
Enc(key,K1)
=Enc(Key,01010101010101010101010101010101)
=C352805754237F311AC0FFF4E3E03E78

//K2
Enc(key,K2)
=Enc(Key,02020202020202020202020202020202)
=BD862FFB97AD2FB8F8B891F6032F36CB

//K3
Enc(key,K3)
=Enc(Key,03030303030303030303030303030303)
=C1A7ABA1A23A94065807A08CC8EED06E

//E[0]
00000000000000000000000000000000

Enc(K1,M[n]^E[n-1]^K1)
=Enc(K1,000102030405060708090a0b0c0d0e0f^00000000000000000000000000000000^BD862FFB97AD2FB8F8B891F6032F36CB)
=Enc(K1,000102030405060708090a0b0c0d0e0f^BD862FFB97AD2FB8F8B891F6032F36CB)
=Enc(K1,BD872DF893A829BFF0B19BFD0F2238C4)
=Enc(C352805754237F311AC0FFF4E3E03E78,BD872DF893A829BFF0B19BFD0F2238C4)
=D2A246FA349B68A79998A4394FF7A263

明文为NULL

测试用例 #1:AES-XCBC-MAC-96 与 0 字节输入
密钥(K):000102030405060708090a0b0c0d0e0f
消息(M):<空字符串>
AES-XCBC-MAC:75f0??251d528ac01c4573dfd584d79f29
AES-XCBC-MAC-96:75f0??251d528ac01c4573dfd5

//Key
000102030405060708090a0b0c0d0e0f
//M
NULL
//M[n],注意比特位是10*填充,转到字节为80开头
80000000000000000000000000000000

//K1
Enc(key,K1)
=Enc(Key,01010101010101010101010101010101)
=C352805754237F311AC0FFF4E3E03E78

//K3
Enc(key,K3)
=Enc(Key,03030303030303030303030303030303)
=C1A7ABA1A23A94065807A08CC8EED06E

Enc(K1,M[n]^E[n-1]^K3)
=Enc(K1,80000000000000000000000000000000^00000000000000000000000000000000^C1A7ABA1A23A94065807A08CC8EED06E)
=Enc(K1,80000000000000000000000000000000^C1A7ABA1A23A94065807A08CC8EED06E)
=Enc(K1,41A7ABA1A23A94065807A08CC8EED06E)
=Enc(C352805754237F311AC0FFF4E3E03E78,D1A7ABA1A23A94065807A08CC8EED06E)
=75F0251D528AC01C4573DFD584D79F29

明文长度大于128bit时

测试用例 #4:AES-XCBC-MAC-96 与 20 字节输入
密钥(K):000102030405060708090a0b0c0d0e0f
消息(M):000102030405060708090a0b0c0d0e0f10111213
AES-XCBC-MAC:47f51b4564966215b8985c63055ed308
AES-XCBC-MAC-96:47f51b4564966215b8985c63

//Key
000102030405060708090a0b0c0d0e0f

//M[1]
000102030405060708090a0b0c0d0e0f
//M[2]
10111213800000000000000000000000

//E[0]
00000000000000000000000000000000

//K1
Enc(key,K1)
=Enc(Key,01010101010101010101010101010101)
=C352805754237F311AC0FFF4E3E03E78

//K3
Enc(key,K3)
=Enc(Key,03030303030303030303030303030303)
=C1A7ABA1A23A94065807A08CC8EED06E

CBC-MAC:先XOR,再Enc,C作为下一组的IV

//计算E[i](需要参数:明文,K1密钥,不需要密文参与)
//只需要计算到分组个数
E[0] = 00000000000000000000000000000000
E[1]
=Enc(K1,M[1]^E[0])
=Enc(K1,000102030405060708090A0B0C0D0E0F^00000000000000000000000000000000)
=Enc(K1,000102030405060708090A0B0C0D0E0F)
=1D0448FACF4D9C6F55B993DA09803DB3


//第一分组
Enc(Key,M[1]^E[0])
=Enc(Key,000102030405060708090a0b0c0d0e0f^00000000000000000000000000000000)
=Enc(000102030405060708090a0b0c0d0e0f,000102030405060708090a0b0c0d0e0f)
=0A940BB5416EF045F1C39458C653EA5A

//最后一分组,原文分组不满128bits
Enc(K1,M[2]^E[1]^K3)
=Enc(K1,10111213800000000000000000000000^1D0448FACF4D9C6F55B993DA09803DB3^C1A7ABA1A23A94065807A08CC8EED06E)
=Enc(K1,0D155AE94F4D9C6F55B993DA09803DB3^C1A7ABA1A23A94065807A08CC8EED06E)
=Enc(K1,CCB2F148ED7708690DBE3356C16EEDDD)
=Enc(C352805754237F311AC0FFF4E3E03E78,CCB2F148ED7708690DBE3356C16EEDDD)
=47F51B4564966215B8985C63055ED308
测试用例 #6:AES-XCBC-MAC-96 与 34 字节输入
密钥(K):000102030405060708090a0b0c0d0e0f
消息(M):000102030405060708090a0b0c0d0e0f10111213141516171819
                    1a1b1c1d1e1f2021
AES-XCBC-MAC:becbb3bccdb518a30677d5481fb6b4d8
AES-XCBC-MAC-96:becbb3bccdb518a30677d548


//Key
000102030405060708090a0b0c0d0e0f
//M[1]
000102030405060708090a0b0c0d0e0f
//M[2]
101112131415161718191a1b1c1d1e1f
//M[3]
20218000000000000000000000000000

//K1
Enc(key,K1)
=Enc(Key,01010101010101010101010101010101)
=C352805754237F311AC0FFF4E3E03E78
//K3
Enc(key,K3)
=Enc(Key,03030303030303030303030303030303)
=C1A7ABA1A23A94065807A08CC8EED06E

//E[0]
00000000000000000000000000000000
//E[1]
=Enc(K1,M[1]^E[0])
=Enc(C352805754237F311AC0FFF4E3E03E78,000102030405060708090a0b0c0d0e0f)
=1D0448FACF4D9C6F55B993DA09803DB3
//E[2]
=Enc(K1,M[2]^E[1])
=Enc(K1,101112131415161718191a1b1c1d1e1f^1D0448FACF4D9C6F55B993DA09803DB3)
=Enc(K1,101112131415161718191a1b1c1d1e1f^1D0448FACF4D9C6F55B993DA09803DB3)
=Enc(C352805754237F311AC0FFF4E3E03E78,0D155AE9DB588A784DA089C1159D23AC)
=09025E5A6725207244145C6B80668579

//第1分组运算C1
Enc(Key,M[1]^E[0])
=Enc(000102030405060708090a0b0c0d0e0f,000102030405060708090a0b0c0d0e0f)
=0A940BB5416EF045F1C39458C653EA5A
//第2分组运算C2
Enc(Key,101112131415161718191A1B1C1D1E1F^1D0448FACF4D9C6F55B993DA09803DB3)
=Enc(000102030405060708090a0b0c0d0e0f,0D155AE9DB588A784DA089C1159D23AC)
=9D35AF36E5755C77C7B9814EB90F5E8A

//不涉及上面两分组加密运算
//最后一分组C3,原文分组不满128bits
Enc(K1,M[3]^E[2]^K3)
=Enc(K1,20218000000000000000000000000000^09025E5A6725207244145C6B80668579^C1A7ABA1A23A94065807A08CC8EED06E)
=Enc(K1,2923DE5A6725207244145C6B80668579^C1A7ABA1A23A94065807A08CC8EED06E)
=Enc(C352805754237F311AC0FFF4E3E03E78,E88475FBC51FB4741C13FCE748885517)
=BECBB3BCCDB518A30677D5481FB6B4D8

总结

已知Key、M外部给定,求Mac

算法约定参数值:
E[0] = 00..00(16字节)

if 原文为16字节倍数
K1 = Enc(Key,01...01)
K2 = Enc(Key,02...02)
Calculate -> E[1]...E[N-1]:
E[x] = Enc(K1, M[x]^E[x-1])-> N-1轮计算
Mac = Enc(K1,M[n]E[n-1]K2)
else
K1 = Enc(Key,01...01)
K3 = Enc(Key,03...03)
Calculate -> E[1]...E[N-1]:
E[x] = Enc(K1, M[x]^E[x-1])-> N-1轮计算
Mac = Enc(K1, M[N]E[N-1]K3)

《rfc5288.AES_Galois_Counter_Mode_(GCM)_Cipher_Suites_for_TLS》

也可参考《RFC4106》

《NIST-SP800-38D》

chacha20-《RFC7539》

chacha20:高速密码,在纯软比AES快得多。在缺乏专用AES硬件平台上,速度大约是AES的三倍。(20轮)

ploy1305:验证器:高速消息身份验证代码,实现简单,容易正确。

CHACHA20-POLY1305认证加密与相关数据(AEAD)构造。

chacha20_poly1305

标准文档《RFC8349》

chacha20_poly1305,已完成两版本,一个是自写实现,调用openssl大数计算,另外一版本是从openssl抽出chacha20、poly1305源码,其余自写,已发布在公众号。

《The Galois/Counter Mode of Operation (GCM)》

gcm-revised-spec

//Input
Key
IV //any number of bits between 1 and 2^64
Plaintext //any number of bits between 0 and 2^39 - 256
AAD // any number of bits between 0 and 2^64

//Output
Ciphertext //as same as Plaintext length
Tag //whose bits length can be value between 64 and 128