本文主要是介绍LibTomCrypt学习笔记——工作模式——OMAC,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
介绍
OMAC是一种认证模式,CMAC is an essentially the One-Key CBC-MAC (OMAC)。NIST官网的介绍如下。
The CMAC authentication mode is specified inSpecial Publication 800-38B for use with any approved block cipher.CMAC stands for cipher-based message authentication code (MAC), analogous to HMAC, the hash-based MAC algorithm.
CMAC is an essentially the One-Key CBC-MAC (OMAC) algorithm submitted by Iwata and Kurosawa. OMAC is an improvement of the XCBC algorithm, submitted by Rogaway and Black, which itself is an improvement of the CBC-MAC algorithm. XCBC efficiently addresses the security deficiencies of CBC-MAC;OMAC efficiently reduces the key size of XCBC.
算法
OMAC采用的是CBC模式得到MAC值,当然在其中某些地方做了调整,主要调整在:子密钥的生成和最后一个分组的padding上。
子密钥生成
The following is a specification of the subkey generation process of CMAC:
Prerequisites:
block cipher CIPH with block size b;
key K.
Output:
subkeys K1, K2.
Suggested Notation:
SUBK(K).
Steps:
1. Let L = CIPHK(0b).
2. If MSB1(L) = 0, then K1 = L << 1;
Else K1 = (L << 1) ⊕ Rb; see Sec. 5.3 for the definition of Rb.
3. If MSB1(K1) = 0, then K2 = K1 << 1;
Else K2 = (K1 << 1) ⊕ Rb.
3. Return K1, K2.
其中Rb的含义如下:
b表示分组大小(bit),R128= 012010000111, and R64= 05911011.
012010000111就是前面120bit的0再在低位接10000111,其余类似
子密钥生成的流程图(生成子密钥K1和K2)
MAC生成
block cipher CIPH with block sizeb;
key K;
MAC length parameter Tlen.
Input:
message M of bit lengthMlen.
Output:
MAC T of bit lengthTlen.
Suggested Notation:
CMAC(K, M,Tlen) or, ifTlenis understood from the context, CMAC(K,M).
Steps:
1. Apply the subkey generation process in Sec. 6.1 toKto produceK1and K2.
2. If Mlen = 0, letn= 1; else, letn= 向上取整(Mlen/b).
3. Let M1, M2, ... , Mn-1, Mn* denote the unique sequence of bit strings such thatM=
M1 || M2 || ... ||Mn-1 ||Mn*, whereM1,M2,..., Mn-1 are complete blocks.2
4. If Mn* is a complete block, letMn=K1⊕ Mn*; else, letMn=K2 ⊕ (Mn*||10j),
where j = nb-Mlen-1.
5. Let C0 = 0b.
6. For i = 1 ton, letCi= CIPHK(Ci-1⊕Mi).
7. Let T = MSBTlen(Cn).
8. Return T.
MAC生成的流程图(MAC值为T)
代码
在LibTomCrypt中omac主要有以下函数
int omac_init(omac_state *omac, int cipher, const unsigned char *key, unsigned long keylen);
int omac_process(omac_state *omac, const unsigned char *in, unsigned long inlen);
int omac_done(omac_state *omac, unsigned char *out, unsigned long *outlen);
int omac_memory(int cipher, const unsigned char *key, unsigned long keylen, const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen);
int omac_memory_multi(int cipher, const unsigned char *key, unsigned long keylen, unsigned char *out, unsigned long *outlen, const unsigned char *in, unsigned long inlen, ...);
int omac_file(int cipher, const unsigned char *key, unsigned long keylen, const char *filename, unsigned char *out, unsigned long *outlen);
int omac_test(void);
──────────────────────────────────────
int omac_init(omac_state *omac, int cipher, const unsigned char *key, unsigned long keylen);
// [功能] 初始化
// [返回] 0 [正常] or other [出错]
// [出处] omac_init.c
l omac // [输入/输出] OMAC状态
l cipher // [输入] 初始化向量
l key // [输入] 密钥
l keylen // [输入] 密钥长度
──────────────────────────────────────
──────────────────────────────────────
int omac_process(omac_state *omac, const unsigned char *in, unsigned long inlen);
// [功能] 处理输入信息
// [返回] 0 [正常] or other [出错]
// [出处] omac_process.c
l omac // [输入/输出] OMAC状态
l in // [输入] 消息
l inlen // [输入] 消息长度
//[备注] 消息长度可以不是分组长度的倍数。可多次调用此函数输入消息
──────────────────────────────────────
──────────────────────────────────────
int omac_done(omac_state *omac, unsigned char *out, unsigned long *outlen);
// [功能] 结束并输出mac值
// [返回] 0 [正常] or other [出错]
// [出处] omac_done.c
l omac // [输入/输出] OMAC状态
l out // [输出] mac值
l outlen // [输出] mac值长度
//[备注] 实际输出长度 = min ( 输入的outlen长度, 分组长度 )
──────────────────────────────────────
说明
OMAC通常的执行流程是:
omac_init(***);
while( want_send_message )
{
omac_ process (***);//每次送入的消息长度可以为任意值
}
omac_ done (***);
──────────────────────────────────────
int omac_memory(int cipher, const unsigned char *key, unsigned long keylen, const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen);
// [功能] 计算一段数据的mac值
// [返回] 0 [正常] or other [出错]
// [出处] omac_memory.c
l cipher // [输入] 密码算法
l key // [输入] 密钥
l keylen // [输入] 密钥长度
l in // [输入] 消息
l inlen // [输入] 消息长度
l out // [输出] mac值
l outlen // [输出] mac值长度
//[备注] 适合消息不太长的场合。实际处理过程为
omac_init(***);
omac_ process (***);
omac_ done (***);
──────────────────────────────────────
──────────────────────────────────────
int omac_memory_multi(int cipher, const unsigned char *key, unsigned long keylen, unsigned char *out, unsigned long *outlen, const unsigned char *in, unsigned long inlen, ...);
// [功能] 计算多段数据的mac值
// [返回] 0 [正常] or other [出错]
// [出处] omac_memory_multi.c
l cipher // [输入] 密码算法
l key // [输入] 密钥
l keylen // [输入] 密钥长度
l out // [输出] mac值
l outlen // [输出] mac值长度
l in // [输入] 消息
l inlen // [输入] 消息长度
l … // [输入] 可选参数,先跟消息地址,再跟消息长度,如此反复
//[备注] 类似omac_memory,只不过处理的是多段数据
──────────────────────────────────────
──────────────────────────────────────
int omac_file(int cipher, const unsigned char *key, unsigned long keylen, const char *filename, unsigned char *out, unsigned long *outlen);
// [功能] 计算文件的mac值
// [返回] 0 [正常] or other [出错]
// [出处] omac_file.c
l cipher // [输入] 密码算法
l key // [输入] 密钥
l keylen // [输入] 密钥长度
l filename // [输入] 文件名
l out // [输出] mac值
l outlen // [输出] mac值长度
//[备注] 适合消息不太长的场合。实际处理过程为
omac_init(***);
while ( file_not end )
{
fread(***);
omac_ process (***);
}
omac_ done (***);
──────────────────────────────────────
──────────────────────────────────────
int omac_test(void);
// [功能] 测试函数
// [返回] 0 [正常] or other [出错]
// [出处] omac_ test.c
──────────────────────────────────────
测试代码
使用NIST提供的测试向量
参见 Test_CMAC_AES.c
测试代码
//------------------------------------------------------------ 代码分割线 ---------------------------------------------------------------------------------------
#include "tomcrypt.h"
#include "TestMode.h"
//lie test , use nist test vetor
int Test_CMAC_AES(void)
{
// 数据来源
// NIST SP 800-38B (Recommendation for Block Cipher Modes of Operation:The CMAC Mode for Authentication).pdf
NistTestVector vect[] = {
{//vect[0]
/*name*/ "D.1 AES-128 Example 1: Mlen = 0",
/*keylen*/ 16,
/*msglen*/ 16*0,
/*Key*/ "2b7e151628aed2a6abf7158809cf4f3c",
/*IV */ "",
{// pt Message
""
},
{//ct T
"bb1d6929e95937287fa37d129b756746"
}
},
//
{//vect[1]
/*name*/ "D.1 AES-128 Example 2: Mlen = 128",
/*keylen*/ 16,
/*msglen*/ 16*1,
/*Key*/ "2b7e151628aed2a6abf7158809cf4f3c",
/*IV */ "",
{// pt Message
"6bc1bee22e409f96e93d7e117393172a"
},
{//ct T
"070a16b46b4d4144f79bdd9dd04a287c"
}
},
//
{//vect[2]
/*name*/ "D.1 AES-128 Example 3: Mlen = 320",
/*keylen*/ 16,
/*msglen*/ 16*5/2,
/*Key*/ "2b7e151628aed2a6abf7158809cf4f3c",
/*IV */ "",
{// pt Message
"6bc1bee22e409f96e93d7e117393172a",
"ae2d8a571e03ac9c9eb76fac45af8e51",
"30c81c46a35ce411"
},
{//ct T
"dfa66747de9ae63030ca32611497c827"
}
},
//
{//vect[3]
/*name*/ "D.1 AES-128 Example 4: Mlen = 512",
/*keylen*/ 16,
/*msglen*/ 16*4,
/*Key*/ "2b7e151628aed2a6abf7158809cf4f3c",
/*IV */ "",
{// pt Message
"6bc1bee22e409f96e93d7e117393172a",
"ae2d8a571e03ac9c9eb76fac45af8e51",
"30c81c46a35ce411e5fbc1191a0a52ef",
"f69f2445df4f9b17ad2b417be66c3710"
},
{//ct T
"51f0bebf7e3b9d92fc49741779363cfe"
}
},
//
{//vect[4]
/*name*/ "D.2 AES-192 Example 5: Mlen = 0",
/*keylen*/ 24,
/*msglen*/ 16*0,
/*Key*/ "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
/*IV */ "",
{// pt
"",
},
{//ct
"d17ddf46adaacde531cac483de7a9367"
}
},
//
{//vect[5]
/*name*/ "D.2 AES-192 Example 6: Mlen = 128",
/*keylen*/ 24,
/*msglen*/ 16*1,
/*Key*/ "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
/*IV */ "",
{// pt
"6bc1bee22e409f96e93d7e117393172a",
},
{//ct
"9e99a7bf31e710900662f65e617c5184"
}
},
//
{//vect[6]
/*name*/ "D.2 AES-192 Example 7: Mlen = 320",
/*keylen*/ 24,
/*msglen*/ 16*5/2,
/*Key*/ "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
/*IV */ "",
{// pt
"6bc1bee22e409f96e93d7e117393172a",
"ae2d8a571e03ac9c9eb76fac45af8e51",
"30c81c46a35ce411"
},
{//ct
"8a1de5be2eb31aad089a82e6ee908b0e"
}
},
//
{//vect[7]
/*name*/ "D.2 AES-192 Example 8: Mlen = 512",
/*keylen*/ 24,
/*msglen*/ 16*4,
/*Key*/ "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
/*IV */ "",
{// pt
"6bc1bee22e409f96e93d7e117393172a",
"ae2d8a571e03ac9c9eb76fac45af8e51",
"30c81c46a35ce411e5fbc1191a0a52ef",
"f69f2445df4f9b17ad2b417be66c3710"
},
{//ct
"a1d5df0eed790f794d77589659f39a11"
}
} ,
//
{//vect[8]
/*name*/ "D.3 AES-256 Example 9: Mlen = 0",
/*keylen*/ 32,
/*msglen*/ 16*0,
/*Key*/ "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
/*IV */ "",
{// pt
"",
},
{//ct
"028962f61b7bf89efc6b551f4667d983"
}
},
//
{//vect[9]
/*name*/ "D.3 AES-256 Example 10: Mlen = 128",
/*keylen*/ 32,
/*msglen*/ 16*1,
/*Key*/ "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
/*IV */ "",
{// pt
"6bc1bee22e409f96e93d7e117393172a",
},
{//ct
"28a7023f452e8f82bd4bf28d8c37c35c"
}
},
//
{//vect[10]
/*name*/ "D.3 AES-256 Example 11: Mlen = 320",
/*keylen*/ 32,
/*msglen*/ 16*5/2,
/*Key*/ "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
/*IV */ "",
{// pt
"6bc1bee22e409f96e93d7e117393172a",
"ae2d8a571e03ac9c9eb76fac45af8e51",
"30c81c46a35ce411"
},
{//ct
"aaf3d8f1de5640c232f5b169b9c911e6"
}
},
//
{//vect[11]
/*name*/ "D.3 AES-256 Example 12: Mlen = 512",
/*keylen*/ 32,
/*msglen*/ 16*4,
/*Key*/ "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
/*IV */ "",
{// pt
"6bc1bee22e409f96e93d7e117393172a",
"ae2d8a571e03ac9c9eb76fac45af8e51",
"30c81c46a35ce411e5fbc1191a0a52ef",
"f69f2445df4f9b17ad2b417be66c3710"
},
{//ct
"e1992190549f6ed5696a2c056c315410"
}
}
};
int idx, err, i, res;
BYTE buf[16];
int keylen, msglen, len;
BYTE key[32], IV[16], pt[64], ct[64];
/* AES can be under rijndael or aes... try to find it */
if ( register_cipher (&aes_desc) != CRYPT_OK )
{
return CRYPT_INVALID_CIPHER;
}
if ((idx = find_cipher("aes")) == -1)
{
return CRYPT_NOP;
}
for ( i = 0; i < (int)(sizeof(vect)/sizeof(vect[0])); i++ )
{
keylen = vect[i].keylen;
msglen = vect[i].msglen;
Str2Num(vect[i].key, 1, key);
Str2Num(vect[i].IV, 1, IV);
Str2Num(vect[i].pt, 4, pt);
Str2Num(vect[i].ct, 4, ct);
len = 16;//sizeof(out);
if ((err = omac_memory(idx, key, keylen, pt, msglen, buf, &len)) != CRYPT_OK)
{
return err;
}
res = XMEMCMP(buf, ct, 16);//(XMEMCMP(out, tests[x].tag, 16)
printf("Test Vetor : %s pass ? \t%s \n", vect[i].name, (res == 0)?"Yes":"No" );
}
printf("\nTest CMAC AES Finish!\n" );
return CRYPT_OK;
}
需要的子函数
int char2int(BYTE ch)
{
if ( ( '0' <= ch ) && ( ch <= '9' ) ) return ch - '0';
else if ( ( 'a' <= ch ) && ( ch <= 'f' ) ) return ch - 'a' + 10;
else if (( 'A' <= ch ) && ( ch <= 'F' ) ) return ch - 'A' + 10;
else { _ASSERT(0); return 0; }
}
void Str2Num(BYTE *t[], int size, BYTE *p_bytes)
{
int i, j, k = 0;
int tmp = 0;
for( i = 0; i < size; ++i )
{
int len = ( t[i] != NULL ) ? (int)strlen(t[i]) : 0;
for (j = 0; j<len; j +=2 )
{
p_bytes[k++] = ( ( char2int(t[i][j]) ) << 4 ) | ( char2int(t[i][j+1]) );
}
}
}
这篇关于LibTomCrypt学习笔记——工作模式——OMAC的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!