LibTomCrypt学习笔记——工作模式——OMAC

2023-10-28 18:58

本文主要是介绍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学习笔记——工作模式——OMAC的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/295261

相关文章

C#利用Free Spire.XLS for .NET复制Excel工作表

《C#利用FreeSpire.XLSfor.NET复制Excel工作表》在日常的.NET开发中,我们经常需要操作Excel文件,本文将详细介绍C#如何使用FreeSpire.XLSfor.NET... 目录1. 环境准备2. 核心功能3. android示例代码3.1 在同一工作簿内复制工作表3.2 在不同

深入浅出Spring中的@Autowired自动注入的工作原理及实践应用

《深入浅出Spring中的@Autowired自动注入的工作原理及实践应用》在Spring框架的学习旅程中,@Autowired无疑是一个高频出现却又让初学者头疼的注解,它看似简单,却蕴含着Sprin... 目录深入浅出Spring中的@Autowired:自动注入的奥秘什么是依赖注入?@Autowired

Unity新手入门学习殿堂级知识详细讲解(图文)

《Unity新手入门学习殿堂级知识详细讲解(图文)》Unity是一款跨平台游戏引擎,支持2D/3D及VR/AR开发,核心功能模块包括图形、音频、物理等,通过可视化编辑器与脚本扩展实现开发,项目结构含A... 目录入门概述什么是 UnityUnity引擎基础认知编辑器核心操作Unity 编辑器项目模式分类工程

Python中的filter() 函数的工作原理及应用技巧

《Python中的filter()函数的工作原理及应用技巧》Python的filter()函数用于筛选序列元素,返回迭代器,适合函数式编程,相比列表推导式,内存更优,尤其适用于大数据集,结合lamb... 目录前言一、基本概念基本语法二、使用方式1. 使用 lambda 函数2. 使用普通函数3. 使用 N

C#和Unity中的中介者模式使用方式

《C#和Unity中的中介者模式使用方式》中介者模式通过中介者封装对象交互,降低耦合度,集中控制逻辑,适用于复杂系统组件交互场景,C#中可用事件、委托或MediatR实现,提升可维护性与灵活性... 目录C#中的中介者模式详解一、中介者模式的基本概念1. 定义2. 组成要素3. 模式结构二、中介者模式的特点

Python学习笔记之getattr和hasattr用法示例详解

《Python学习笔记之getattr和hasattr用法示例详解》在Python中,hasattr()、getattr()和setattr()是一组内置函数,用于对对象的属性进行操作和查询,这篇文章... 目录1.getattr用法详解1.1 基本作用1.2 示例1.3 原理2.hasattr用法详解2.

setsid 命令工作原理和使用案例介绍

《setsid命令工作原理和使用案例介绍》setsid命令在Linux中创建独立会话,使进程脱离终端运行,适用于守护进程和后台任务,通过重定向输出和确保权限,可有效管理长时间运行的进程,本文给大家介... 目录setsid 命令介绍和使用案例基本介绍基本语法主要特点命令参数使用案例1. 在后台运行命令2.

Java中的xxl-job调度器线程池工作机制

《Java中的xxl-job调度器线程池工作机制》xxl-job通过快慢线程池分离短时与长时任务,动态降级超时任务至慢池,结合异步触发和资源隔离机制,提升高频调度的性能与稳定性,支撑高并发场景下的可靠... 目录⚙️ 一、调度器线程池的核心设计 二、线程池的工作流程 三、线程池配置参数与优化 四、总结:线程

Java设计模式---迭代器模式(Iterator)解读

《Java设计模式---迭代器模式(Iterator)解读》:本文主要介绍Java设计模式---迭代器模式(Iterator),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录1、迭代器(Iterator)1.1、结构1.2、常用方法1.3、本质1、解耦集合与遍历逻辑2、统一

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操