文章目录
相关标准和文档
-
《GBT 15852.1-2008 信息技术 安全技术 消息鉴别码 第1部分:采用分组密码的机制》
-
《GBT 15852.1-2020 信息技术 安全技术 消息鉴别码 第1部分:采用分组密码的机制》
-
ISO 9797 Message Authentication Codes (MACs)
Part 1: Mechanisms using a block cipher
https://www.doc88.com/p-57347146035924.html
Part 2: Mechanisms using a dedicated hash-function
https://www.doc88.com/p-0159667006070.html
Part 3: Mechanisms using a universal hash-function
https://www.doc88.com/p-9734810928184.html -
RFC4493: The AES-CMAC Algorithm
https://datatracker.ietf.org/doc/rfc4493 -
T. Iwata and K. Kurosawa. OMAC: One-Key CBC MAC
https://csrc.nist.gov/CSRC/media/Projects/Block-Cipher-Techniques/documents/BCM/proposed-modes/omac/omac-ad.pdf -
NIST SP800-38A Recommendation for Block Cipher modes of Operation – Methods and Techniques
-
NIST SP800-38B Recommendation for Block Cipher Modes of Operation – the CMAC Mode for Authentication
https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38b.pdf -
ANSI X3.92 Data Encryption Algorithm (DEA)
-
ANSI X3.106 Modems of DEA Operation
-
ANSI X4.16 American National Standard for financial services, financial transaction cards, magnetic stripe encoding
-
ANSI X9.8 Personal Identification Number (PIN) Management and Security
-
ANSI X9.9 Financial institution message authentication (wholesale)
-
ANSI X9.19 Financial Institution Retail Message Authentication (MAC)
-
ISO 7810 Identification cards – Physical characteristics
-
ISO 7811 Identification cards – Recording technique
-
ISO 7812 Identification cards – Identification of issuers
-
ISO 7813 Identification cards – Financial transaction cards
-
ISO 7816 Identification cards – Integrated circuit(s) cards with contacts
-
ISO 8583 Bank card originated messages – Interchange message specifications – Content for financial transactions
-
ISO 8731-1 Banking: Approved algorithms for message authentication
Part 1 – DEA
https://www.doc88.com/p-373487237594.html
Part 2 – Message Authentication algorithms
https://www.doc88.com/p-1426368720696.html -
ISO 9807 Banking and releated financial service – Requirements for Message Authentication(Retail)
https://www.doc88.com/p-9992812642133.html
代码下载
- GBT 15852.1-2020: https://github.com/yaoyuanyylyy/CMacTest
- GBT 15852.1-2008: https://download.youkuaiyun.com/download/yaoyuanyylyy/86902073 (old)
概述
CMAC, Cipher-based MAC, 即基于AES对称加密算法的MAC,可参考ISO 9797-1
标准,其中详细定义了CMAC算法,其对应的国标为《GBT 15852.1》
。
最早的CMAC是基于DES的CBC模式构造的MAC,即CBC-MAC,可参考ANSI X9.9
、ANSI X9.19
。
然后 John Black 和 Phillip Rogaway 于2000年提出的避免CBC-MAC安全缺陷的XCBC模式(Extend Cipher Block Chaining Mode),作为CBC模式的扩展,用来构造MAC,即XCBC-MAC
。
再后来,Tetsu Iwata 和 Kaoru Kurosawa 基于XCBC-MAC提出了OMAC
,即One-Key CBC-MAC
,接着又精益求精第提出了OMAC1,前面的OMAC被重新命名为OMAC2,可参考其论文。
现在提到CMAC通常是指OMAC,而OMAC通常是指OMAC1,可参考NIST SP800-38B
标准,也可参考RFC4493
文档,其中的测试数据里使用了AES128/192/256算法和3DES算法。
基于《GBT 15852.1》
的算法1和填充1可以实现《GBT 36322》中的SDF_CalculateMAC
接口。
文档说明
- ISO 9797: CMAC算法,定义了几种不同MAC算法和填充方式。
- GBT 15852.1: 国家标准。2008版本对标
ISO 9797-1:1999
;2020版本对标ISO 9797-1:2011
。 - X9.9: DES CBC-MAC,其算法对应到“GBT 15852.1”中的“算法1,填充1”。
- X9.19: 3DES CBC-MAC,其算法对应到“GBT 15852.1”中的“算法3,填充1”。
- SP800-38B: 定义了使用AES和TDEA算法来计算OMAC。
OMAC
-
OMAC算法特点
- 对称算法的CBC向量IV是全0的
- 在初始化时会根据标准中的子密钥算法生成两个子密钥key1和key2
- 在处理最后一个分组时,如果是完整的分组,就与key1相异或,然后再加密。如果不是完整的分组,就填充比特串
100000000*
到完整分组,然后与key2相异或,然后再加密。
-
实现
- BC库中的实现了OMAC算法,底层的实现类为
org.bouncycastle.crypto.macs.CMac
。对应到《GBT 15852.1-2020》的算法5。在使用时可直接通过java的Mac
进行使用,算法名称是在相应的对称算法后面添加CMAC
。
CMAC:《GBT 15852.1-2020》
- 总结
算法 | 密钥诱导 (可选;2种) | 消息填充 (4种) | 初始变换 (3种) | 最终迭代 (4种) | 输出变换 (3种) | 截断操作 (2种) |
---|---|---|---|---|---|---|
算法1: CBC-MAC | 1/2/3 | 1 | 1 | 1 | 1 | |
算法2: EMAC | 1(可能) | 1/2/3 | 1 | 1 | 2-key2 | 1 |
算法3: ANSI retail MAC | 1/2/3 | 1 | 1 | 3-key2 | 1 | |
算法4: MacDES | 1(可能) | 1/2/3 | 2-K1 | 1 | 2-key2 | 1 |
算法5: CMAC/OMAC1 | 2 | 4 | 1 | 3-(K1,K2) | 1 | 1 |
算法6: LMAC | 1(可能) | 1/2/3 | 1 | 2-K2 | 1 | 1 |
算法7: TrCBC | 4 | 1 | 1 | 1 | 2 | |
算法8: CBCR | 4 | 3 | 4 | 1 | 1 |
ParametersWithPadding类
ParametersWithPadding类用来设置算法的各种参数。其中定义key1表示需要输入的原始密钥;key2表示在输出变换中使用的密钥,可能是在最开始设置的,也可能是通过密钥诱导生成的。
public class ParametersWithPadding implements CipherParameters {
int typeAlg; //算法类型:1~6
int typePad; //填充类型:1、2、3、4
int length; //仅 typePad=3 时有效,表示输入数据的总长度
int transformInit; //初始变换:1、2、3
int transformOut; //输出变换:1、2、3
int lastIteration; //最终迭代:1、2、3、4
int truncate; //截断操作:1、2
int keyInduce = 1; //密钥诱导方式:0、1;仅用于算法2中。
byte[] key1;
byte[] key2;
byte[] iv;
public ParametersWithPadding(
byte[] key1, byte[] key2,
int typeAlg, int typePad) {
this(key1, key2, typeAlg, typePad, 0);
}
public ParametersWithPadding(
byte[] key1, byte[] key2, byte[] iv,
int typeAlg, int typePad) {
this(key1, key2, iv, typeAlg, typePad, 0);
}
public ParametersWithPadding(
byte[] key1, byte[] key2,
int typeAlg, int typePad, int length) {
this(key1, key2, null, typeAlg, typePad, length);
}
public ParametersWithPadding(
byte[] key1, byte[] key2, byte[] iv,
int typeAlg, int typePad, int length) {
this.key1 = key1;
this.key2 = key2;
this.iv = iv;
this.typeAlg = typeAlg;
this.typePad = typePad;
this.length = length;
transformInit = 1;
transformOut = 1;
lastIteration = 1;
truncate = 1;
switch (typeAlg) {
case 2:
transformOut = 2;
break;
case 3:
transformOut = 3;
//算法3的两个密钥应独立选取;当key2为null时为避免错误,这里将其设置为key1,此时算法3和算法1一致
if (this.key2 == null)
this.key2 = key1;
break;
case 4:
transformInit = 2;
transformOut = 2;
break;
case 5:
lastIteration = 3;
break;
case 6:
lastIteration = 2;
break;
case 7:
truncate = 2;
break;
case 8:
transformInit = 3;
lastIteration = 4;
break;
}
}
/**
* 密钥诱导方式,仅用于算法2中。
* <p>
* 默认为1。为了兼容2008标准或验证2008标准的附录测试,需要手动设置为0.
*
* @param keyInduce 0表示使用2008标准中的密钥诱导;在2008标准中定义,并在附录测试中用到;<br>
* 1表示使用2020标准中的密钥诱导1。在2020标准中定义,但附录测试中提供了2个密钥,未用到。
*/
public void setKeyInduce(int keyInduce) {
this.keyInduce = keyInduce;
}
public CipherParameters getParameters() {
if (iv == null)
return new KeyParameter(key1);
else
return new ParametersWithIV(new KeyParameter(key1), iv);
}
YCMac类
在YCMac类中实现了标准中的8种算法。其中定义的K1,表示用在初始变换2或最终迭代3中的密钥;K2表示用在最终迭代2/3中的密钥。
2020标准中定义的MAC算法的8步操作在YCMac中的处理方法如下:
- 第1步:密钥诱导: keyInduce
- 第2步:消息填充: paddingTransform
- 第3步:数据分割: 在 update 中自动处理
- 第4步:初始变换: initTransform
- 第5步:迭代应用分组密码: 在 update 中自动处理
- 第6步:最终迭代: lastIteration
- 第7步:输出变换: outTransform
- 第8步:截断操作: truncate
public class YCMac implements Mac {
private final byte[] mac; //mac值
private final int macSize; //所需的Mac大小
private final byte[] buf; //内部缓冲区
private int bufOff; //缓冲区当前数据长度
private byte[] K1; //用在初始变换2或最终迭代3中的密钥
private byte[] K2; //用在最终迭代2/3中的密钥
private final BlockCipher cipher; //底层对称算法对象
ParametersWithPadding parameters; //算法参数
public YCMac(BlockCipher cipher) {
this(cipher, cipher.getBlockSize() * 8);
}
public YCMac(BlockCipher cipher, int macSizeInBits) {
if ((macSizeInBits % 8) != 0) {
throw new IllegalArgumentException("MAC size must be multiple of 8");
}
if (macSizeInBits > (cipher.getBlockSize() * 8)) {
throw new IllegalArgumentException("MAC size must be less or equal to " + (cipher.getBlockSize() * 8));
}
this.cipher = new CBCBlockCipher(cipher);
this.macSize = macSizeInBits / 8;
mac = new byte[cipher.getBlockSize()];
buf = new byte[cipher.getBlockSize()];
bufOff = 0;
}
public String getAlgorithmName() {
return cipher.getAlgorithmName();
}
public void init(CipherParameters params) {
validate(params);
cipher.init(true, parameters.getParameters());
keyInduce(); //1.密钥诱导
reset();
//填充方式3:处理在开头添加的填充块
if (parameters.typePad == 3) {
byte[] temp = new byte[cipher.getBlockSize()];
byte[] bLen = Pack.intToBigEndian(parameters.length * 8);
System.arraycopy(bLen, 0, temp, temp.length - bLen.length, bLen.length);
update(temp, 0, temp.length);
}
}
void validate(CipherParameters params) {
if (params instanceof ParametersWithPadding)
parameters = (ParametersWithPadding) params;
else
throw new IllegalArgumentException("CMac mode only permits parameters type of ParametersWithPadding.");
}
public int getMacSize() {
return macSize;
}
public void update(byte in) {
if (bufOff == buf.length) {
cipher.processBlock(buf, 0, mac, 0);
bufOff = 0;
}
buf[bufOff++] = in;
}
public void update(byte[] in, int inOff, int len) {
if (len < 0) {
throw new IllegalArgumentException("Can't have a negative input length!");
}
int blockSize = cipher.getBlockSize();
int gapLen = blockSize - bufOff;
if (len > gapLen) {
System.arraycopy(in, inOff, buf, bufOff, gapLen);
initTransform(parameters.transformInit); //4.初始变换
bufOff = 0;
len -= gapLen;
inOff += gapLen;
//5.迭代应用分组密码
while (len > blockSize) {
cipher.processBlock(in, inOff, mac, 0);
len -= blockSize;
inOff += blockSize;
}
}
System.arraycopy(in, inOff, buf, bufOff, len);
bufOff += len;
}
public int doFinal(byte[] out, int outOff) {
int msgLen = bufOff;
paddingTransform(parameters.typePad); //2.消息填充。填充最后一个分组
lastIteration(parameters.lastIteration, msgLen); //6.最终迭代
outTransform(parameters.transformOut); //7.输出变换
truncate(parameters.truncate, out, outOff, msgLen); //8.截断操作
reset();
return macSize;
}
/**
* 密钥诱导。
*/
void keyInduce() {
KeyInduce keyInduce = new KeyInduce(cipher);
if (parameters.typeAlg == 2) {
//如果没有提供key2,则需要生成。
//为了兼容2008,通过keyInduce参数决定密钥生成方式。0表示使用2008标准中的密钥诱导;1表示使用2020标准中的密钥诱导1。
if (parameters.key2 == null) {
if(parameters.keyInduce==0)
parameters.key2 = keyInduce.induce0(parameters.key1);
else {
keyInduce.induce1(parameters.key1.length);
parameters.key1 = keyInduce.K1;
parameters.key2 = keyInduce.K2;
}
}
} else if (parameters.typeAlg == 4) {
//需要生成初始变换2的密钥K1:如果提供了key2,则用2008标准中的密钥诱导生成K1;
//如果没有提供key2,则需用密钥诱导1生成K1,以及要在输出变换2中使用的密钥key2
if (parameters.key2 != null)
K1 = keyInduce.induce0(parameters.key2);
else {
keyInduce.induce1(parameters.key1.length);
parameters.key2 = keyInduce.K1;
K1 = keyInduce.K2;
}
} else if (parameters.typeAlg == 5) {
//最终迭代3中的两个密钥用密钥诱导2生成;分别放在K1和K2中
keyInduce.induce2();
K1 = keyInduce.K1;
K2 = keyInduce.K2;
} else if (parameters.typeAlg == 6) {
//当只提供一个密钥时,需用密钥诱导1生成所需的两个密钥。用于最终迭代2的密钥放在K2中
if (parameters.key2 == null) {
keyInduce.induce1(parameters.key1.length);
parameters.key1 = keyInduce.K1;
K2 = keyInduce.K2; //用于最终迭代2,故不设置key2
cipher.init(true, parameters.getParameters()); //使用密钥诱导生成了key1,需要重新初始化cipher
} else
K2 = parameters.key2;
}
}
/**
* 填充。
*
* @param type 填充方式
*/
void paddingTransform(int type) {
int blockSize = cipher.getBlockSize();
if (type == 1 || type == 3) {
if (bufOff != blockSize)
new ZeroBytePadding().addPadding(buf, bufOff);
} else if (type == 2) {
if (bufOff == blockSize) {
cipher.processBlock(buf, 0, mac, 0);
bufOff = 0;
}
new ISO7816d4Padding().addPadding(buf, bufOff);
} else if (type == 4) {
if (bufOff != blockSize)
new ISO7816d4Padding().addPadding(buf, bufOff);
}
}
/**
* 初始变换。
*
* @param type 初始变换方式
*/
void initTransform(int type) {
cipher.processBlock(buf, 0, mac, 0);
if (type == 2) {
//初始变换2:使用子密钥加密后再使用原密钥进行后续加密
reset();
cipher.init(true, new KeyParameter(K1));
cipher.processBlock(mac, 0, mac, 0);
cipher.init(true, new ParametersWithIV(parameters.getParameters(), mac));
} else if (type == 3) {
cipher.reset();
byte[] zeroes = new byte[cipher.getBlockSize()];
cipher.processBlock(zeroes, 0, mac, 0);
xor(buf, mac);
cipher.reset();
cipher.processBlock(buf, 0, mac, 0);
}
}
/**
* 输出变换。
*
* @param type 输出变换方式
*/
void outTransform(int type) {
if (type == 2) {
//使用子密钥再加密一次
reset();
//这里需要使用全0的IV进行初始化,因为在算法4的“初始化变换”中使用了非0的IV,如果只是reset,则IV不是全0,会导致结果有误
cipher.init(true, new ParametersWithIV(new KeyParameter(parameters.key2), new byte[cipher.getBlockSize()]));
cipher.processBlock(mac, 0, mac, 0);
} else if (type == 3) {
//使用子密钥解密后再使用原密钥加密
cipher.init(false, new KeyParameter(parameters.key2));
cipher.processBlock(mac, 0, mac, 0);
reset();
cipher.init(true, parameters.getParameters());
cipher.processBlock(mac, 0, mac, 0);
}
}
/**
* 最终迭代。
*
* @param type 迭代类型
* @param msgLen 最后的消息长度
*/
void lastIteration(int type, int msgLen) {
if (type == 1)
cipher.processBlock(buf, 0, mac, 0);
if (type == 2) {
xor(mac, buf);
reset();
cipher.init(true, new ParametersWithIV(new KeyParameter(K2), new byte[cipher.getBlockSize()]));
cipher.processBlock(mac, 0, mac, 0);
} else if (type == 3) {
if (msgLen % cipher.getBlockSize() == 0)
xor(buf, K1);
else
xor(buf, K2);
cipher.processBlock(buf, 0, mac, 0);
} else if (type == 4) {
byte[] temp = new byte[cipher.getBlockSize()];
xor(mac, buf);
if (msgLen % cipher.getBlockSize() == 0)
shiftRight(mac, temp);
else
shiftLeft(mac, temp);
System.arraycopy(temp, 0, mac, 0, temp.length);
reset();
cipher.init(true, parameters.getParameters());
cipher.processBlock(mac, 0, mac, 0);
}
}
/**
* 截断操作。
*
* @param type 截断类型
* @param out 输出缓冲
* @param outOff 输出偏移
* @param msgLen 最后的消息长度
*/
void truncate(int type, byte[] out, int outOff, int msgLen) {
if (type == 2 && msgLen % cipher.getBlockSize() != 0)
System.arraycopy(mac, mac.length - macSize, out, outOff, macSize);
else
System.arraycopy(mac, 0, out, outOff, macSize);
}
public void reset() {
//clean the buffer.
Arrays.fill(buf, (byte) 0);
bufOff = 0;
//reset the underlying cipher.
cipher.reset();
}
static void xor(byte[] a, byte[] b) {
for (int i = 0; i < a.length; i++)
a[i] ^= b[i];
}
/**
* 循环左移。
*/
private static int shiftLeft(byte[] input, byte[] output) {
int i = input.length;
int bit = 0;
while (--i >= 0) {
int b = input[i] & 0xff;
output[i] = (byte) ((b << 1) | bit);
bit = (b >>> 7) & 1;
}
return bit;
}
/**
* 循环右移。
*/
private static int shiftRight(byte[] input, byte[] output) {
int i = 0;
int bit = 0;
while (i < input.length) {
int b = input[i] & 0xff;
output[i] = (byte) ((b >>> 1) | bit);
bit = (b << 7) & 0x80;
i++;
}
output[0] |= bit;
return bit;
}
/**
* 密钥诱导。
*/
static class KeyInduce {
final BlockCipher cipher;
byte[] K1;
byte[] K2;
KeyInduce(BlockCipher blockCipher) {
this.cipher = blockCipher;
}
/**
* 密钥诱导1.
*
* @param keyLength 分组密钥密钥长度k
*/
void induce1(int keyLength) {
int t = keyLength / cipher.getBlockSize();
K1 = genKey(0, t);
cipher.reset();
K2 = genKey(t, 2 * t);
}
/**
* 密钥诱导2.
*/
void induce2() {
byte[] zeroes = new byte[cipher.getBlockSize()];
byte[] L = new byte[zeroes.length];
cipher.processBlock(zeroes, 0, L, 0);
K1 = multx(L);
K2 = multx(K1);
}
/**
* 《GBT 15852.1-2008》密钥诱导。
* <p>
* 用在算法2和算法4中。
* <p>
* 过程:对K从第1个4比特组开始,每隔4比特交替取补和不变
*
* @param key 密钥
* @return 子密钥
*/
public byte[] induce0(byte[] key) {
byte[] result = key.clone();
for (int i = 0; i < result.length; i++)
result[i] = (byte) ((~result[i] & 0xF0) ^ (result[i] & 0x0F));
return result;
}
byte[] genKey(int start, int end) {
int blockSize = cipher.getBlockSize();
int len = end - start;
byte[] S = new byte[len * blockSize];
for (int i = start; i < end; i++) {
byte[] ct = new byte[blockSize];
byte[] temp = Pack.intToBigEndian(i + 1);
System.arraycopy(temp, 0, ct, ct.length - temp.length, temp.length);
cipher.processBlock(ct, 0, S, (i - start) * blockSize);
}
return Arrays.copyOfRange(S, (len - 1) * blockSize, S.length);
}
/**
* multx(CMac.doubleLu).
*
* @param in 比特串T
* @see CMac
*/
byte[] multx(byte[] in) {
byte[] ret = new byte[in.length];
int carry = shiftLeft(in, ret);
byte[] poly = lookupPoly(cipher.getBlockSize());
int mask = (-carry) & 0xff;
ret[in.length - 3] ^= poly[1] & mask;
ret[in.length - 2] ^= poly[2] & mask;
ret[in.length - 1] ^= poly[3] & mask;
return ret;
}
/**
* lookup.
*
* @see CMac
*/
static byte[] lookupPoly(int blockSizeLength) {
int xor = 0;
switch (blockSizeLength * 8) {
case 64:
xor = 0x1B;
break;
case 128:
xor = 0x87;
break;
}
return Pack.intToBigEndian(xor);
}
}
}
密钥诱导
在2008标准中定义了一个密钥诱导,在2020标准中定义了另外两个不同的密钥诱导,即密钥诱导1和密钥诱导2。密钥诱导在YCMac中的keyInduce方法中按照不同的算法进行处理。
但对于算法2有点特殊,为了兼容2008标准及其附录测试,在ParametersWithPadding中定义了keyInduce参数表示密钥诱导方式(仅用于算法2中)。
- 0表示使用2008标准中的密钥诱导;在2008标准中定义,并在附录测试中用到;
- 1表示使用2020标准中的密钥诱导1。在2020标准中定义,但附录测试中提供了2个密钥,未用到。
默认为1,以符合2020标准。所以为了兼容2008标准或验证2008标准的附录测试,需要手动设置为0.
算法1/3/7/8不需要密钥诱导,其他算法的密钥诱导参看下面的代码:
void keyInduce() {
KeyInduce keyInduce = new KeyInduce(cipher);
if (parameters.typeAlg == 2) {
//如果没有提供key2,则需要生成。
//为了兼容2008,通过keyInduce参数决定密钥生成方式。0表示使用2008标准中的密钥诱导;1表示使用2020标准中的密钥诱导1。
if (parameters.key2 == null) {
if(parameters.keyInduce==0)
parameters.key2 = keyInduce.induce0(parameters.key1);
else {
keyInduce.induce1(parameters.key1.length);
parameters.key1 = keyInduce.K1;
parameters.key2 = keyInduce.K2;
}
}
} else if (parameters.typeAlg == 4) {
//需要生成初始变换2的密钥K1:如果提供了key2,则用2008标准中的密钥诱导生成K1;
//如果没有提供key2,则需用密钥诱导1生成K1,以及要在输出变换2中使用的密钥key2
if (parameters.key2 != null)
K1 = keyInduce.induce0(parameters.key2);
else {
keyInduce.induce1(parameters.key1.length);
parameters.key2 = keyInduce.K1;
K1 = keyInduce.K2;
}
} else if (parameters.typeAlg == 5) {
//最终迭代3中的两个密钥用密钥诱导2生成;分别放在K1和K2中
keyInduce.induce2();
K1 = keyInduce.K1;
K2 = keyInduce.K2;
} else if (parameters.typeAlg == 6) {
//当只提供一个密钥时,需用密钥诱导1生成所需的两个密钥。用于最终迭代2的密钥放在K2中
if (parameters.key2 == null) {
keyInduce.induce1(parameters.key1.length);
parameters.key1 = keyInduce.K1;
K2 = keyInduce.K2; //用于最终迭代2,故不设置key2
cipher.init(true, parameters.getParameters()); //使用密钥诱导生成了key1,需要重新初始化cipher
} else
K2 = parameters.key2;
}
}
测试
在YMacTest的 test_GBT15852_2020() 里对《GBT 15852.1-2020 信息技术 安全技术 消息鉴别码 第1部分:采用分组密码的机制》-附录B 进行了测试和验证。
CMAC测试: 《GBT 15852.1-2020 信息技术 安全技术 消息鉴别码 第1部分:采用分组密码的机制》-附录B
消息1:This is the test message for mac
Hex: 54686973206973207468652074657374206d65737361676520666f72206d6163
填充方式1:
D1 | 54 68 69 73 20 69 73 20 74 68 65 20 74 65 73 74
D2 | 20 6D 65 73 73 61 67 65 20 66 6F 72 20 6D 61 63
填充方式2:
D1 | 54 68 69 73 20 69 73 20 74 68 65 20 74 65 73 74
D2 | 20 6D 65 73 73 61 67 65 20 66 6F 72 20 6D 61 63
D3 | 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
填充方式3:
D1 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00
D2 | 54 68 69 73 20 69 73 20 74 68 65 20 74 65 73 74
D3 | 20 6D 65 73 73 61 67 65 20 66 6F 72 20 6D 61 63
填充方式4:
D1 | 54 68 69 73 20 69 73 20 74 68 65 20 74 65 73 74
D2 | 20 6D 65 73 73 61 67 65 20 66 6F 72 20 6D 61 63
消息2:This is the test message
hex: 54686973206973207468652074657374206d65737361676520
填充方式1:
D1 | 54 68 69 73 20 69 73 20 74 68 65 20 74 65 73 74
D2 | 20 6D 65 73 73 61 67 65 20 00 00 00 00 00 00 00
填充方式2:
D1 | 54 68 69 73 20 69 73 20 74 68 65 20 74 65 73 74
D2 | 20 6D 65 73 73 61 67 65 20 80 00 00 00 00 00 00
填充方式3:
D1 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C8
D2 | 54 68 69 73 20 69 73 20 74 68 65 20 74 65 73 74
D3 | 20 6D 65 73 73 61 67 65 20 00 00 00 00 00 00 00
填充方式4:
D1 | 54 68 69 73 20 69 73 20 74 68 65 20 74 65 73 74
D2 | 20 6D 65 73 73 61 67 65 20 80 00 00 00 00 00 00
mac算法测试:
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
MAC算法1:
填充方法1:
MAC= 16 E0 29 04 EF B7 65 B7
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
MAC算法1:
填充方法2:
MAC= 4B 65 53 AF 3C 4E 27 44
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
MAC算法1:
填充方法3:
MAC= 71 AF 7E 45 53 40 4C BC
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520
MAC算法1:
填充方法1:
MAC= BA 89 E4 5F E8 AB F2 42
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520
MAC算法1:
填充方法2:
MAC= 42 1A D1 69 0A A1 52 E2
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520
MAC算法1:
填充方法3:
MAC= 6A 4A 86 F5 B5 E4 68 DA
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
MAC算法2:
填充方法1:
MAC= 1E 9A 71 D3 BC 92 DF A7
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
MAC算法2:
填充方法2:
MAC= E4 23 E3 55 99 AF D9 48
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
MAC算法2:
填充方法3:
MAC= 40 03 BA 1B 6A DC 53 A8
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520
MAC算法2:
填充方法1:
MAC= 4E C3 C7 FA CF AA C6 07
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520
MAC算法2:
填充方法2:
MAC= F0 26 25 CE AD 00 8D 4E
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520
MAC算法2:
填充方法3:
MAC= FF D5 F1 F2 E5 ED A5 CB
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
MAC算法3:
填充方法1:
MAC= 27 63 21 1B 2B CA F7 19
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
MAC算法3:
填充方法2:
MAC= 51 E9 92 8C 22 38 33 0C
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
MAC算法3:
填充方法3:
MAC= 7C D4 8C 42 42 E4 55 75
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520
MAC算法3:
填充方法1:
MAC= E3 2D 99 A6 89 C0 52 59
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520
MAC算法3:
填充方法2:
MAC= 19 72 47 22 9C E9 D7 B6
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520
MAC算法3:
填充方法3:
MAC= 3C 43 0F 1E A4 3B 54 0C
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
MAC算法4:
填充方法1:
MAC= DD 10 52 A7 AF E8 99 9B
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
MAC算法4:
填充方法2:
MAC= 7E 1A 9A 5E 0E F0 94 7F
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
MAC算法4:
填充方法3:
MAC= 28 A7 0D 6B CC F7 44 22
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520
MAC算法4:
填充方法1:
MAC= AA 9D B3 D9 65 1F 86 2B
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520
MAC算法4:
填充方法2:
MAC= 94 94 76 D3 5F 17 26 1E
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520
MAC算法4:
填充方法3:
MAC= C9 D3 4E 16 C4 9A B6 43
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
MAC算法5:
填充方法4:
MAC= 69 2C 43 71 00 F3 B5 EE
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520
MAC算法5:
填充方法4:
MAC= 47 38 A6 C7 60 B2 80 FC
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
MAC算法6:
填充方法1:
MAC= B3 8A 96 19 5B AA 61 FC
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
MAC算法6:
填充方法2:
MAC= A0 C4 65 EE 58 96 97 2F
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
MAC算法6:
填充方法3:
MAC= 43 05 0D 51 C6 56 AE 60
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520
MAC算法6:
填充方法1:
MAC= 8C F6 E6 43 14 FE F4 17
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520
MAC算法6:
填充方法2:
MAC= 60 DD 95 5E D0 CA 3D 7A
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520
MAC算法6:
填充方法3:
MAC= 61 E0 00 49 E2 69 62 A3
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
MAC算法7:
填充方法4:
MAC= 16 E0 29 04 EF B7 65 B7
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520
MAC算法7:
填充方法4:
MAC= 84 6F A2 A5 D8 34 45 A9
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520666f72206d6163
MAC算法8:
填充方法4:
MAC= E4 0E D7 9C 31 49 A1 C9
--------------------------------------------------
消息: 54686973206973207468652074657374206d65737361676520
MAC算法8:
填充方法4:
MAC= A9 9D 13 01 3E 89 2E E2
以下是2008标准的相关内容,现可忽略。
CMAC:《GBT 15852.1-2008》
- 总结
MAC算法(6种) | 数据填充(3种) | 初始变换(2种) | 输出变换(3种) | 输入密钥1 | 输入密钥2 | 生成诱导密钥 |
---|---|---|---|---|---|---|
算法1 | 任选 | 1 | 1 | √ | × | × |
算法2 | 任选 | 1 | 2 | √ | × | √ |
算法3 | 任选 | 1 | 3 | √ | √ | × |
算法4 | 任选 | 2 | 2 | √ | √ | √ |
算法5 | 任选 | √ | √ | |||
算法6 | 任选 | √ | √ | √ |
其中,算法5
是两个算法1
的MAC相异或;算法6
是两个算法4
的MAC相异或 。
- 实现
- CMac14实现了算法 1-4 ,CMac56实现了算法5~6。
- 算法参数放在ParametersWithPadding类中,包括算法类型,填充方式,密钥,向量,初始变换,输出变换。默认CMAC的向量为全0,添加了IV以支持其他向量值。
- YCMac类中还提供了一个基于
算法1,填充1
的支持update
模式的CMAC方法。
在《GBT 36322》中有一个SDF_CalculateMAC
接口,支持IV的输入输出,支持多包处理,可以用此方法来实现。
其他的MAC算法实现不了,因为它们的输出变换用了另外的密钥来进行处理,所以不支持update模式。
- 代码示例
/**
* 《GBT 15852.1-2008 信息技术 安全技术 消息鉴别码 第1部分:采用分组密码的机制》算法1~4。
*
* @author YaoYuan
* @since 2022/11/2
*/
public class CMac14 implements Mac {
private byte[] mac; //mac值
private byte[] buf; //内部缓冲区
private int bufOff; //缓冲区当前数据长度
private BlockCipher cipher; //底层对称算法对象
private int macSize; //所需的Mac大小
private byte[] subKey; //子密钥
ParametersWithPadding parameters; //算法参数
private boolean needTransformInit = false; //是否需要初始变换
public CMac14(BlockCipher cipher) {
this(cipher, cipher.getBlockSize() * 8);
}
public CMac14(BlockCipher cipher, int macSizeInBits) {
if ((macSizeInBits % 8) != 0) {
throw new IllegalArgumentException("MAC size must be multiple of 8");
}
if (macSizeInBits > (cipher.getBlockSize() * 8)) {
throw new IllegalArgumentException("MAC size must be less or equal to "+ (cipher.getBlockSize() * 8));
}
this.cipher = new CBCBlockCipher(cipher);
this.macSize = macSizeInBits / 8;
mac = new byte[cipher.getBlockSize()];
buf = new byte[cipher.getBlockSize()];
bufOff = 0;
}
public String getAlgorithmName() {
return cipher.getAlgorithmName();
}
public void init(CipherParameters params) {
validate(params);
cipher.init(true, parameters.getParameters());
//设置子密钥
if (parameters.typeAlg == 2)
subKey = YCMac.genKey(parameters.key1);
else if (parameters.typeAlg == 3)
subKey = parameters.key2.clone();
else if (parameters.typeAlg == 4)
subKey = YCMac.genKey(parameters.key2);
//只有在初始变换2中才需要额外的初始变换操作
if (parameters.transformInit == 2)
needTransformInit = true;
reset();
//填充方式3:处理在开头添加的填充块
if (parameters.typePad == 3) {
byte[] temp = new byte[cipher.getBlockSize()];
byte[] bLen = Pack.intToBigEndian(parameters.length * 8);
System.arraycopy(bLen, 0, temp, temp.length - bLen.length, bLen.length);
update(temp, 0, temp.length);
}
}
void validate(CipherParameters params) {
if (params instanceof ParametersWithPadding)
parameters = (ParametersWithPadding) params;
else
throw new IllegalArgumentException("CMac mode only permits parameters type of ParametersWithPadding.");
}
public int getMacSize() {
return macSize;
}
public void update(byte in) {
if (bufOff == buf.length) {
cipher.processBlock(buf, 0, mac, 0);
bufOff = 0;
}
buf[bufOff++] = in;
}
public void update(byte[] in, int inOff, int len) {
if (len < 0) {
throw new IllegalArgumentException("Can't have a negative input length!");
}
int blockSize = cipher.getBlockSize();
int gapLen = blockSize - bufOff;
if (len > gapLen) {
System.arraycopy(in, inOff, buf, bufOff, gapLen);
cipher.processBlock(buf, 0, mac, 0);
//初始变换
if (needTransformInit) {
needTransformInit = false;
initTransform(parameters.transformInit);
//重设算法4的密钥
if (parameters.typeAlg == 4)
subKey = parameters.key2.clone();
}
bufOff = 0;
len -= gapLen;
inOff += gapLen;
while (len > blockSize) {
cipher.processBlock(in, inOff, mac, 0);
len -= blockSize;
inOff += blockSize;
}
}
System.arraycopy(in, inOff, buf, bufOff, len);
bufOff += len;
}
public int doFinal(byte[] out, int outOff) {
//最后一个分组的填充
paddingTransform(parameters.typePad);
cipher.processBlock(buf, 0, mac, 0);
//输出变换
outTransform(parameters.transformOut);
System.arraycopy(mac, 0, out, outOff, macSize);
reset();
return macSize;
}
/**
* 填充。
*
* @param type 填充方式
*/
void paddingTransform(int type) {
int blockSize = cipher.getBlockSize();
if (type == 1 || type == 3) {
if (bufOff != blockSize)
new ZeroBytePadding().addPadding(buf, bufOff);
} else {
if (bufOff == blockSize) {
cipher.processBlock(buf, 0, mac, 0);
bufOff = 0;
}
new ISO7816d4Padding().addPadding(buf, bufOff);
}
}
/**
* 初始变换。
*
* @param type 变换方式
*/
void initTransform(int type) {
//只有初始变换2才需要处理:使用子密钥加密后再使用原密钥进行后续加密
if (type == 2) {
reset();
cipher.init(true, new KeyParameter(subKey));
cipher.processBlock(mac, 0, mac, 0);
cipher.init(true, new ParametersWithIV(parameters.getParameters(), mac));
}
}
/**
* 输出变换。
*
* @param type 变换方式
*/
void outTransform(int type) {
if (type == 2) {
//使用子密钥再加密一次
reset();
//这里需要使用全0的IV进行初始化,因为在算法4的“初始化变换”中使用了非0的IV,如果只是reset,则IV不是全0,会导致结果有误
cipher.init(true, new ParametersWithIV(new KeyParameter(subKey), new byte[cipher.getBlockSize()]));
cipher.processBlock(mac, 0, mac, 0);
} else if (type == 3) {
//先解密再加密
cipher.init(false, new KeyParameter(subKey));
cipher.processBlock(mac, 0, mac, 0);
reset();
cipher.init(true, parameters.getParameters());
cipher.processBlock(mac, 0, mac, 0);
}
}
public void reset() {
//clean the buffer.
Arrays.fill(buf, (byte) 0);
bufOff = 0;
//reset the underlying cipher.
cipher.reset();
}
}
测试
在例子中测试了:
- 《GBT 15852.1》附录A 测试和验证
- SP800-38B测试和验证:其中的TDEA中有两个Mac值验证失败,应该是文档本身的错误。
- CMac-update-iv的测试和验证
IDEA中的测试输出:
- GBT 15852.1:
CMAC测试: 《GBT 15852.1-2008 信息技术 安全技术 消息鉴别码 第1部分:采用分组密码的机制》-附录A
消息1:Now is the time for all
Hex: 4e6f77206973207468652074696d6520666f7220616c6c20
填充方式1:
D1 | 4E 6F 77 20 69 73 20 74
D2 | 68 65 20 74 69 6D 65 20
D3 | 66 6F 72 20 61 6C 6C 20
填充方式2:
D1 | 4E 6F 77 20 69 73 20 74
D2 | 68 65 20 74 69 6D 65 20
D3 | 66 6F 72 20 61 6C 6C 20
D4 | 80 00 00 00 00 00 00 00
填充方式3:
D1 | 00 00 00 00 00 00 00 C0
D2 | 4E 6F 77 20 69 73 20 74
D3 | 68 65 20 74 69 6D 65 20
D4 | 66 6F 72 20 61 6C 6C 20
消息2:Now is the time for it
hex: 4e6f77206973207468652074696d6520666f72206974
填充方式1:
D1 | 4E 6F 77 20 69 73 20 74
D2 | 68 65 20 74 69 6D 65 20
D3 | 66 6F 72 20 69 74 00 00
填充方式2:
D1 | 4E 6F 77 20 69 73 20 74
D2 | 68 65 20 74 69 6D 65 20
D3 | 66 6F 72 20 69 74 80 00
填充方式3:
D1 | 00 00 00 00 00 00 00 B0
D2 | 4E 6F 77 20 69 73 20 74
D3 | 68 65 20 74 69 6D 65 20
D4 | 66 6F 72 20 69 74 00 00
mac算法测试:
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f7220616c6c20
MAC算法1:
填充方法1:
MAC= 70 A3 06 40
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f7220616c6c20
MAC算法1:
填充方法2:
MAC= 10 E1 F0 F1
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f7220616c6c20
MAC算法1:
填充方法3:
MAC= 2C 58 FB 8F
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f72206974
MAC算法1:
填充方法1:
MAC= E4 5B 3A D2
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f72206974
MAC算法1:
填充方法2:
MAC= A9 24 C7 21
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f72206974
MAC算法1:
填充方法3:
MAC= B1 EC D6 FC
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f7220616c6c20
MAC算法2:
填充方法1:
MAC= 10 F9 BC 67
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f7220616c6c20
MAC算法2:
填充方法2:
MAC= BE 7C 2A B7
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f7220616c6c20
MAC算法2:
填充方法3:
MAC= 8E FC 8B C7
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f72206974
MAC算法2:
填充方法1:
MAC= 21 5E 9C E6
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f72206974
MAC算法2:
填充方法2:
MAC= 17 36 AC 1A
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f72206974
MAC算法2:
填充方法3:
MAC= 05 38 26 96
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f7220616c6c20
MAC算法3:
填充方法1:
MAC= A1 C7 2E 74
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f7220616c6c20
MAC算法3:
填充方法2:
MAC= E9 08 62 30
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f7220616c6c20
MAC算法3:
填充方法3:
MAC= AB 05 94 63
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f72206974
MAC算法3:
填充方法1:
MAC= 2E 2B 14 28
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f72206974
MAC算法3:
填充方法2:
MAC= 5A 69 2C E6
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f72206974
MAC算法3:
填充方法3:
MAC= C5 9F 7E ED
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f7220616c6c20
MAC算法4:
填充方法1:
MAC= AD 35 02 B7
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f7220616c6c20
MAC算法4:
填充方法2:
MAC= 61 C3 33 E3
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f7220616c6c20
MAC算法4:
填充方法3:
MAC= 95 2A F8 38
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f72206974
MAC算法4:
填充方法1:
MAC= 05 F1 08 4C
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f72206974
MAC算法4:
填充方法2:
MAC= A1 BC 09 31
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f72206974
MAC算法4:
填充方法3:
MAC= AF DE E0 F9
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f7220616c6c20
MAC算法5:
填充方法1:
MAC= F4 E4 02 B6 B7 2C 13 17
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f7220616c6c20
MAC算法5:
填充方法2:
MAC= 70 F0 5E C9 E4 F7 2F 99
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f7220616c6c20
MAC算法5:
填充方法3:
MAC= D6 1F 51 F2 EA 2A 2D 63
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f72206974
MAC算法5:
填充方法1:
MAC= 0F 24 BD A4 AC 22 0F 4F
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f72206974
MAC算法5:
填充方法2:
MAC= E0 04 13 41 9A FC 16 0B
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f72206974
MAC算法5:
填充方法3:
MAC= DD DF 5E D3 0F 18 EB FC
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f7220616c6c20
MAC算法6:
填充方法1:
MAC= 57 7E F2 21 18 CE 5D BA
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f7220616c6c20
MAC算法6:
填充方法2:
MAC= 60 74 60 B8 D8 C0 FD FA
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f7220616c6c20
MAC算法6:
填充方法3:
MAC= FD 3D BB 6E F1 65 07 54
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f72206974
MAC算法6:
填充方法1:
MAC= 10 F7 47 D1 4F 72 C2 29
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f72206974
MAC算法6:
填充方法2:
MAC= B2 9B 9A 76 DD 1C 39 12
--------------------------------------------------
消息: 4e6f77206973207468652074696d6520666f72206974
MAC算法6:
填充方法3:
MAC= F6 45 FB 7D 4D 4A 42 B4
- SP800-3B
com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 org.yy.mac.YMacTest,test_omac1
omac SP800-38B verify:
====================================================================
algorithm : AES128
key: 2b7e151628aed2a6abf7158809cf4f3c
msg:
mac: bb1d6929e95937287fa37d129b756746
====================================================================
algorithm : AES128
key: 2b7e151628aed2a6abf7158809cf4f3c
msg: 6bc1bee22e409f96e93d7e117393172a
mac: 070a16b46b4d4144f79bdd9dd04a287c
====================================================================
algorithm : AES128
key: 2b7e151628aed2a6abf7158809cf4f3c
msg: 6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411
mac: dfa66747de9ae63030ca32611497c827
====================================================================
algorithm : AES128
key: 2b7e151628aed2a6abf7158809cf4f3c
msg: 6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710
mac: 51f0bebf7e3b9d92fc49741779363cfe
====================================================================
algorithm : AES192
key: 8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
msg:
mac: d17ddf46adaacde531cac483de7a9367
====================================================================
algorithm : AES192
key: 8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
msg: 6bc1bee22e409f96e93d7e117393172a
mac: 9e99a7bf31e710900662f65e617c5184
====================================================================
algorithm : AES192
key: 8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
msg: 6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411
mac: 8a1de5be2eb31aad089a82e6ee908b0e
====================================================================
algorithm : AES192
key: 8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b
msg: 6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710
mac: a1d5df0eed790f794d77589659f39a11
====================================================================
algorithm : AES256
key: 603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4
msg:
mac: 028962f61b7bf89efc6b551f4667d983
====================================================================
algorithm : AES256
key: 603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4
msg: 6bc1bee22e409f96e93d7e117393172a
mac: 28a7023f452e8f82bd4bf28d8c37c35c
====================================================================
algorithm : AES256
key: 603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4
msg: 6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411
mac: aaf3d8f1de5640c232f5b169b9c911e6
====================================================================
algorithm : AES256
key: 603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4
msg: 6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710
mac: e1992190549f6ed5696a2c056c315410
====================================================================
algorithm : DESede3
key: 8aa83bf8cbda10620bc1bf19fbb6cd58bc313d4a371ca8b5
msg:
mac: b7a688e122ffaf95
====================================================================
algorithm : DESede3
key: 8aa83bf8cbda10620bc1bf19fbb6cd58bc313d4a371ca8b5
msg: 6bc1bee22e409f96
mac: 8e8f293136283797
====================================================================
algorithm : DESede3
key: 8aa83bf8cbda10620bc1bf19fbb6cd58bc313d4a371ca8b5
msg: 6bc1bee22e409f96e93d7e117393172aae2d8a57
mac: 743ddbe0ce2dc2ed
====================================================================
algorithm : DESede3
key: 8aa83bf8cbda10620bc1bf19fbb6cd58bc313d4a371ca8b5
msg: 6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51
mac: 33e6b1092400eae5
====================================================================
algorithm : DESede
key: 4cf15134a2850dd58a3d10ba80570d38
msg:
mac: bd2ebf9a3ba00361
====================================================================
algorithm : DESede
key: 4cf15134a2850dd58a3d10ba80570d38
msg: 6bc1bee22e409f96
mac: 4ff2ab813c53ce83
====================================================================
algorithm : DESede
key: 4cf15134a2850dd58a3d10ba80570d38
msg: 6bc1bee22e409f96e93d7e117393172aae2d8a57
mac: 62dd1b471902bd4e
====================================================================
algorithm : DESede
key: 4cf15134a2850dd58a3d10ba80570d38
msg: 6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51
mac: 31b1e431dabc4eb8