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就是前面120bit0再在低位接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=K1Mn*; 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 is a fairly comprehensive, modular and portable cryptographic toolkit that provides developers with a vast array of well known published block ciphers, one-way hash functions, chaining modes, pseudo-random number generators, public key cryptography and a plethora of other routines. LibTomCrypt has been designed from the ground up to be very simple to use. It has a modular and standard API that allows new ciphers, hashes and PRNGs to be added or removed without change to the overall end application. It features easy to use functions and a complete user manual which has many source snippet examples. LibTomCrypt is free for all purposes under the public domain. This includes commercial use, redistribution and even branching. Sports the following Public domain and open source. Written entirely in portable ISO C source (except for things like RNGs for natural reasons) Builds out of the box on virtually every box. All that is required is GCC for the source to build. Includes a 180+ page user manual in PDF format (with working examples in it) Block Ciphers Ciphers come with an ECB encrypt/decrypt, setkey and self-test interfaces. All ciphers have the same prototype which facilitates using multiple ciphers at runtime. Some of the ciphers are flexible in terms of code size and memory usage. Ciphers Supported. Blowfish XTEA RC5 RC6 SAFER+ Rijndael (aka AES) Twofish SAFER (K64, SK64, K128, SK128) RC2 DES, 3DES CAST5 Noekeon Skipjack Anubis (with optional tweak as proposed by the developers) Khazad KASUMI SEED Chaining Modes Modes come with a start, encrypt/decrypt and set/get IV interfaces. Mode supported. ECB CBC OFB CFB CTR IEEE LRW mode F8 Chaining Mode One-Way Hash Functions Hashes come with init, process, done and self-test interfaces. All hashes use the same prototypes for the interfaces. Hashes supported. MD2 MD4 MD5 SHA-1 SHA-224/256/384/512 TIGER-192 RIPE-MD 128/160/256/320 WHIRLPOOL Message Authenticat
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值