C语言实现AES-128 CMAC算法

原创 2016年08月29日 13:00:01

MessageAuthentication CodeMAC)是一种保障信息完整性和认证的密码学方法,其中CMAC的全称是Cypher-Based Message Authentication Code,基于AES等对称加密方式实现消息认证。通信双方需要共享一个对称密钥,由发送方生成一个MAC值,附在消息后面,接收方计算收到消息的MAC,如果和收到的MAC一致,则说明没有被篡改,并且能确认发送方一定拥有相同的密钥,即认证身份。

        美国国家标准与技术研究院NIST推荐了一种CMAC计算方式,可以避免CBC-MAC带来的缺点,编号为800-3B,文档可以从其官网上下载。该算法通过MAC密钥生成k1k2两个子密钥,并规定了数据位填充的规则,可以通过AES-128AES-192AES-256三种模式进行MAC计算,支持所有整数字节的数据以及长度为0的输入。下图为MAC算法处理不需要位填充和需要位填充的两种情况。本文介绍AES-128生成的CMAC实现。





    本C代码外部依赖项是mbedTLS的密码学库,下载及使用见《C语言实现AES加密解密》。


1外部调用列表


     本CMAC算法包括的内部函数如下。


2本代码中设计的函数


    本CMAC算法包括的全局变量如下。


3本代码中的全局变量



CMAC实现部分代码如下:

#include<stdio.h>
#include "mbedtls/aes.h"
#include "mbedtls/compat-1.3.h"


uint8_t MAC[16];
uint8_t MACkey[16]; 
uint8_t k1[16];
uint8_t k2[16];


mbedtls_aes_context aes;

void leftshift(int len, uint8_t* add, uint8_t*des)
{
	int i;
	for (i = 0; i < len - 1; i++)
	{
		des[i] = (add[i] << 1) + (add[i + 1] >= 0x80?1:0);
	}
	des[len - 1] = add[len - 1] << 1;
}

void ArrayXor(int len, uint8_t*a1, uint8_t*a2, uint8_t*des)
{
	int i;
	for (i = 0; i < len; i++)
	{
		des[i] = a1[i] ^ a2[i];
	}
}

void LoadMacKey(uint8_t *key)
{
	int i;
	uint8_t plain[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
	uint8_t Rb[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 };
	uint8_t c0[16];
	for (i = 0; i < 16; i++)
	{
		MACkey[i] = key[i];   //  set MAC key	
	}
	mbedtls_aes_setkey_enc(&aes, MACkey, 128);  		
	mbedtls_aes_crypt_ecb(&aes, AES_ENCRYPT, plain, c0);
	if (c0[0]<0x80)    //generate k1
	{
		leftshift(16, c0, k1);
	}
	else
	{
		leftshift(16, c0, k1);
		ArrayXor(16, k1, Rb, k1);
	}

	if (k1[0] < 0x80)   //generate k2
	{
		leftshift(16, k1, k2);
	}
	else
	{
		leftshift(16, k1, k2);
		ArrayXor(16, k2, Rb, k2);
	}
}

void GenerateMAC(int len, uint8_t *add, uint8_t *macvalue)
{
	int i,block;
	uint8_t IVtemp[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
	uint8_t Blocktemp[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

		
	if (len % 16 == 0 && len!=0)
	{
		mbedtls_aes_setkey_enc(&aes, MACkey, 128);// load mac key
		block = len / 16;
		for (i = 0; i < block-1; i++)
		{
			ArrayXor(16, &add[i * 16], IVtemp, Blocktemp);
			mbedtls_aes_crypt_ecb(&aes, AES_ENCRYPT, Blocktemp, IVtemp);
		}
		ArrayXor(16, &add[(block-1)*16], IVtemp, Blocktemp);
		ArrayXor(16, Blocktemp, k1, Blocktemp);
		mbedtls_aes_crypt_ecb(&aes, AES_ENCRYPT, Blocktemp, macvalue);
	}
	else
	{
		if (len==0)
		{
			mbedtls_aes_setkey_enc(&aes, MACkey, 128);// load mac key
			block = 1;
			Blocktemp[0] = 0x80;//padding the first bit with 1
			ArrayXor(16, Blocktemp, k2, Blocktemp);
			mbedtls_aes_crypt_ecb(&aes, AES_ENCRYPT, Blocktemp, macvalue);
		}
		else
		{
			mbedtls_aes_setkey_enc(&aes, MACkey, 128);// load mac key
			uint8_t remain = len % 16;
			block = len / 16 + 1;
			for (i = 0; i < block - 1; i++)
			{
				ArrayXor(16, &add[i * 16], IVtemp, Blocktemp);
				mbedtls_aes_crypt_ecb(&aes, AES_ENCRYPT, Blocktemp, IVtemp);
			}
			// the last block padding
			for (i = 0; i < remain; i++) 
			{
				Blocktemp[i] = add[(block - 1) * 16 + i];
			}
			Blocktemp[remain] = 0x80;
			for (i = remain + 1; i < 16; i++)
			{
				Blocktemp[i] = 0;
			}
			// end of the last block padding			
			
			ArrayXor(16, Blocktemp, k2, Blocktemp);
			ArrayXor(16, Blocktemp, IVtemp, Blocktemp);
			mbedtls_aes_crypt_ecb(&aes, AES_ENCRYPT, Blocktemp, macvalue);
		}

	}
}

uint8_t VerifyMAC(int len, uint8_t *add, uint8_t *macvalue1)
{
	int i, block;
	uint8_t IVtemp[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
	uint8_t Blocktemp[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
	uint8_t macvalue[16];
	uint8_t result=1;


	if (len % 16 == 0 && len != 0)
	{
		mbedtls_aes_setkey_enc(&aes, MACkey, 128);// load mac key
		block = len / 16;
		for (i = 0; i < block - 1; i++)
		{
			ArrayXor(16, &add[i * 16], IVtemp, Blocktemp);
			mbedtls_aes_crypt_ecb(&aes, AES_ENCRYPT, Blocktemp, IVtemp);
		}
		ArrayXor(16, &add[(block - 1) * 16], IVtemp, Blocktemp);
		ArrayXor(16, Blocktemp, k1, Blocktemp);
		mbedtls_aes_crypt_ecb(&aes, AES_ENCRYPT, Blocktemp, macvalue);
	}
	else
	{
		if (len == 0)
		{
			mbedtls_aes_setkey_enc(&aes, MACkey, 128);// load mac key
			block = 1;
			Blocktemp[0] = 0x80;//padding the first bit with 1
			ArrayXor(16, Blocktemp, k2, Blocktemp);
			mbedtls_aes_crypt_ecb(&aes, AES_ENCRYPT, Blocktemp, macvalue);
		}
		else
		{
			mbedtls_aes_setkey_enc(&aes, MACkey, 128);// load mac key
			uint8_t remain = len % 16;
			block = len / 16 + 1;
			for (i = 0; i < block - 1; i++)
			{
				ArrayXor(16, &add[i * 16], IVtemp, Blocktemp);
				mbedtls_aes_crypt_ecb(&aes, AES_ENCRYPT, Blocktemp, IVtemp);
			}
			// the last block padding
			for (i = 0; i < remain; i++)
			{
				Blocktemp[i] = add[(block - 1) * 16 + i];
			}
			Blocktemp[remain] = 0x80;
			for (i = remain + 1; i < 16; i++)
			{
				Blocktemp[i] = 0;
			}
			// end of the last block padding			

			ArrayXor(16, Blocktemp, k2, Blocktemp);
			ArrayXor(16, Blocktemp, IVtemp, Blocktemp);
			mbedtls_aes_crypt_ecb(&aes, AES_ENCRYPT, Blocktemp, macvalue);
		}

	}
	result = 1;
	for (i = 0; i < 16; i++)
	{
		if (macvalue[i] != macvalue1[i])
		{
			return(result);
		}
	}
	result = 0;
	return(result);
}

Main函数部分代码如下:

<pre class="cpp" name="code">int main()
{
uint8_t data[64] = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
		                 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 
						 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
						 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 };
	uint8_t tf=2;
	
	uint8_t tk[16] = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
	LoadMacKey(tk);//加载MAC key
	GenerateMAC(33, data, MAC);// 数据字节长度,数据地址,MAC地址
	tf=VerifyMAC(33, data, MAC); // 数据字节长度,数据地址,MAC地址
}









版权声明:本文为博主原创文章,未经博主允许不得转载。

MAC加密算法·银联标准 C语言实现

这几天因为项目的关系需要用到。以下的des算法和mac算法都来源于网络,我修改了下输入输出格式、改掉了原来mac算法里面的一个错误。需要特别注意的是,des算法有很多种,不同实现方法的结果可能不一样。...

openssl 消息认证码CMAC支持

之前在openssl0.9.8中还不支持CMC,而现在的最新版开始支持CMAC了,我目前下载了两个版本openssl-1.0.1c 及openssl-1.0.1e 中都支持。而HMAC在openssl...
  • kkxgx
  • kkxgx
  • 2013年08月27日 22:40
  • 4389

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

基于c语言aes加密算法

#include #include #include #include "aes.h" #define AES256 //Brian Gladman aes http://www.gl...
  • earbao
  • earbao
  • 2015年02月09日 18:49
  • 8355

AES 加密算法的 C 语言实现

      这个AES 的C 语言实现,是从linux 中port 而来,放在这里方便自己日后使用。 很容易把这个code 转为为C++ 的封装。      aes.ha#ifndef __AES_H...
  • free2o
  • free2o
  • 2008年05月25日 15:22
  • 20989

AES加密解密算法的C代码实现

 AES 加密解密的原理我就不说了, 弟兄们自己上百度去查, 文章很多。   我这里只列出从网上获取的代码的实现, 我修改了一些, 可以很方便的使用到你的代码里面。   AES 比DES...

AES加密算法C代码分析

0.引言 对于加密算法的软件实现,通常已经有很多的成熟的库可供选择,只需要根据自己的要求进行选择即可相应的库即可(有的可能需要进行些许修改)。这里选择的是C语言实现的一个开源密码库mbedTLS,m...

AES在openssl和mbedtls中的简单代码示例

在openssl中:// AES_test.cpp : Defines the entry point for the console application. // #include "stdaf...

AES 加密 解密(Hex编码解码)

Aes加密解密方法使用Hex进行了编码解码 package com.baidu.wallet.bdwallet.utils; import java.io.UnsupportedEncodingExc...
  • QH_JAVA
  • QH_JAVA
  • 2016年10月21日 15:23
  • 3741
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C语言实现AES-128 CMAC算法
举报原因:
原因补充:

(最多只允许输入30个字)