赞
踩
CMAC(基于分组加密的消息认证码),一般用作消息的签名。与HMAC相同的是都需要一把秘钥来加密内容得到MAC,只是MAC的产生方法不同,一个是用hash算法,一个是用分组加密算法。两种方法具体原理参见:
https://blog.csdn.net/kkxgx/article/details/10307663
实际上,CMAC-128的计算结果是128位的,而AES的密钥也是128位的,所以利用这个特性,我们可以将一个AES密钥经过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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。