CMAC--基于分组密码的消息认证码的实现及其应用

前言
CMAC(基于分组加密的消息认证码),一般用作消息的签名。与HMAC相同的是都需要一把秘钥来加密内容得到MAC,只是MAC的产生方法不同,一个是用hash算法,一个是用分组加密算法。两种方法具体原理参见:

https://blog.csdn.net/kkxgx/article/details/10307663

实际上,CMAC-128的计算结果是128位的,而AES的密钥也是128位的,所以利用这个特性,我们可以将一个AES密钥经过CMAC生产出多个输出,这些输出可以用来做不同用途的密钥,所以,当我们一个模块需要多个密钥参与时,又不想利用用户输入过个密钥,那么这是个很好的解决办法,模块内部实现密钥的派生,我们称这个过程叫密钥的推算。

Openssl实现CMAC生成

  1 #include <openssl/cmac.h>
  2 #include <openssl/evp.h>
  3 #include <stdio.h>
  4 #include <stdlib.h>
  5 #include <string.h>
  6 int main(int arg, char *argv[]){
  7     char key[17]="1234567891234567";
  8     const EVP_CIPHER* cipher = EVP_aes_128_cbc();
  9     CMAC_CTX* cmac_ctx = CMAC_CTX_new();
 10     if (!cmac_ctx){
 11         printf("create error!\n");
 12         return -1;
 13     }
 14     if (!CMAC_Init(cmac_ctx,key,16,cipher,0)){
 15         CMAC_CTX_free(cmac_ctx);
 16         printf("init error!\n");
 17         return -1;
 18     }
 19     char *meg = "adadffdfsdif2345";
 20     if(!CMAC_Update(cmac_ctx,meg,strlen(meg))){
 21         CMAC_CTX_free(cmac_ctx);
 22         printf("update error!\n");
 23         return -1;
 24     }
 25     size_t reslen;
 26     uint8_t res[128];
 27     if (!CMAC_Final(cmac_ctx, res, &reslen)) {
 28         printf("[DeriveKey(): OEMCrypto_ERROR_CMAC_FAILURE]\n");
 29         return -1;
 30     }
 31     printf("derive key len[%ld]data:\n",reslen);
 32     for(int i = 0; i < reslen; i++){
 33         printf("%x_",res[i]);
 34     }
 35     printf("\n");
 36     CMAC_CTX_free(cmac_ctx);
 37     return 0;
 38 
 39 }

运行结果:

jilinglin@ubuntu:~/SourceCode/OpensslProject/CMAC$ ./cmac
derive key len[16]data:
1_3e_6c_3e_33_48_1e_64_4b_e3_94_66_56_2f_ea_93_

密钥推算(派生)
对于秘钥的推算,我们可以采用这种方法:将一段内容固定,然后在其后分别添加计数值,这样生成的结果就会随着计数值得不同而不同。在通信双方只需传递固定的那段内容,双方都可以推算出相同的秘钥。

  1 #include <openssl/cmac.h>
  2 #include <openssl/evp.h>
  3 #include <stdio.h>
  4 #include <stdlib.h>
  5 #include <string.h>
  6 int derivekey(char *msg) {
  7     char key[17]="1234567891234567";
  8     const EVP_CIPHER* cipher = EVP_aes_128_cbc();
  9     CMAC_CTX* cmac_ctx = CMAC_CTX_new();
 10     if (!cmac_ctx){
 11         printf("create error!\n");
 12         return -1;
 13     }
 14     if (!CMAC_Init(cmac_ctx,key,16,cipher,0)){
 15         CMAC_CTX_free(cmac_ctx);
 16         printf("init error!\n");
 17         return -1;
 18     }
 19     //char *meg = "adadffdfsdif2345";
 20     if(!CMAC_Update(cmac_ctx,msg,strlen(msg))){
 21         CMAC_CTX_free(cmac_ctx);
 22         printf("update error!\n");
 23         return -1;
 24     }
 25     size_t reslen;
 26     uint8_t res[128];
 27     if (!CMAC_Final(cmac_ctx, res, &reslen)) {
 28         printf("[DeriveKey(): OEMCrypto_ERROR_CMAC_FAILURE]\n");
 29         return -1;
 30     }
 31     printf("derive key len[%ld]data:\n",reslen);
 32     for(int i = 0; i < reslen; i++){
 33         printf("%x_",res[i]);
 34     }
 35     printf("\n");
 36     CMAC_CTX_free(cmac_ctx);
 37     return 0;
 38 }
 39 
 40 int main(int argc,char *argv[]){
 41     char *meg_0 = "adadffdfsdif2345";
 42     unsigned int string_len = strlen(meg_0);
 43     printf("strlen =[%d]\n",string_len);
 44     char *msg = malloc(string_len+2);
 45     memcpy(msg,meg_0,string_len);
 46     for(int i = 0; i<5; i++ ){
 47         printf("key num[%d] ",i);
 48         *(msg+string_len)= i;
 49         *(msg+string_len+1)= '\0';
 50         derivekey(msg);
 51     }
 52     free(msg);
 53     return 0;
 54 }

运行结果:

strlen =[16]
key num[0] derive key len[16]data:
1_3e_6c_3e_33_48_1e_64_4b_e3_94_66_56_2f_ea_93_
key num[1] derive key len[16]data:
20_75_a8_67_c7_d4_f5_5b_3_ef_cc_cb_a0_1c_11_be_
key num[2] derive key len[16]data:
5c_c4_14_f4_c3_4d_a6_69_fd_79_a2_c8_8e_4a_4f_cf_
key num[3] derive key len[16]data:
cf_c3_19_e6_8e_ea_c3_c6_c0_34_20_7e_95_7d_a9_32_
key num[4] derive key len[16]data:
42_af_a1_c0_2b_f6_1_d9_4b_9c_29_ee_b1_86_65_c_

自此,key的推算就完成了,例子只推算了5个key,固定消息的长度可以自己设置,输出结果都是128位(16字节)。

两个例子的编译方法:gcc -o cmac cmac.c -lcrypto -lssl

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值