AES128加密算法实现(C语言:ECB加密模式实现)
AES简介
高级加密标准AES(Advanced Encryption Standard)是一种常见的对称加密算法.
详细介绍如下链接:
https://blog.csdn.net/qq_28205153/article/details/55798628
其余基本概念,我这不再加以描述了,主要攻克一些技术难点:
实现AES算法主要包括以下学习步骤:
1、GF(2^8)域上的多项式运算
2、扩展的欧几里德算法
3、生成S盒
4、生成逆S盒
5、S盒置换
6、行移位
7、列混合
8、生成秘钥
9、循环加密
详细学习路径如下:
https://blog.csdn.net/u013605322/article/details/83443612
以上两篇链接,你就可以对AES算法有个大致的了解
算法流程如下:
具体实现如下:
加密接口函数:
// AES-128加密接口,输入key应为16字节长度,输入长度应该是16字节整倍数,
// 这样输出长度与输入长度相同,函数调用外部为输出数据分配内存
int aesEncrypt(const uint8_t *key, uint32_t keyLen, const uint8_t *pt, uint8_t *ct, uint32_t len) {AesKey aesKey;uint8_t *pos = ct;const uint32_t *rk = aesKey.eK; //解密秘钥指针uint8_t out[BLOCKSIZE] = {0};uint8_t actualKey[16] = {0};uint8_t state[4][4] = {0};if (NULL == key || NULL == pt || NULL == ct){printf("param err.\n");return -1;}if (keyLen > 16){printf("keyLen must be 16.\n");return -1;}if (len % BLOCKSIZE){printf("inLen is invalid.\n");return -1;}memcpy(actualKey, key, keyLen);keyExpansion(actualKey, 16, &aesKey); // 秘钥扩展// 使用ECB模式循环加密多个分组长度的数据for (int i = 0; i < len; i += BLOCKSIZE) {// 把16字节的明文转换为4x4状态矩阵来进行处理loadStateArray(state, pt);// 轮秘钥加addRoundKey(state, rk);for (int j = 1; j < 10; ++j) {rk += 4;subBytes(state); // 字节替换shiftRows(state); // 行移位mixColumns(state); // 列混合addRoundKey(state, rk); // 轮秘钥加}subBytes(state); // 字节替换shiftRows(state); // 行移位// 此处不进行列混合addRoundKey(state, rk+4); // 轮秘钥加// 把4x4状态矩阵转换为uint8_t一维数组输出保存storeStateArray(state, pos);pos += BLOCKSIZE; // 加密数据内存指针移动到下一个分组pt += BLOCKSIZE; // 明文数据指针移动到下一个分组rk = aesKey.eK; // 恢复rk指针到秘钥初始位置}return 0;
}
秘钥扩展函数:
//秘钥扩展
int keyExpansion(const uint8_t *key, uint32_t keyLen, AesKey *aesKey) {if (NULL == key || NULL == aesKey){printf("keyExpansion param is NULL\n");return -1;}if (keyLen != 16){printf("keyExpansion keyLen = %d, Not support.\n", keyLen);return -1;}uint32_t *w = aesKey->eK; //加密秘钥uint32_t *v = aesKey->dK; //解密秘钥/* keyLen is 16 Bytes, generate uint32_t W[44]. *//* W[0-3] */for (int i = 0; i < 4; ++i) {LOAD32H(w[i], key + 4*i);}/* W[4-43] */for (int i = 0; i < 10; ++i) {w[4] = w[0] ^ MIX(w[3]) ^ rcon[i];w[5] = w[1] ^ w[4];w[6] = w[2] ^ w[5];w[7] = w[3] ^ w[6];w += 4;}w = aesKey->eK+44 - 4;//解密秘钥矩阵为加密秘钥矩阵的倒序,方便使用,把ek的11个矩阵倒序排列分配给dk作为解密秘钥//即dk[0-3]=ek[41-44], dk[4-7]=ek[37-40]... dk[41-44]=ek[0-3]for (int j = 0; j < 11; ++j) {for (int i = 0; i < 4; ++i) {v[i] = w[i];}w -= 4;v += 4;}return 0;
}
使用ECB模式循环加密多个分组长度的数据
/* copy in[16] to state[4][4] */
int loadStateArray(uint8_t (*state)[4], const uint8_t *in) {for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {state[j][i] = *in++;}}return 0;
}
轮秘钥加
// 轮秘钥加
int addRoundKey(uint8_t (*state)[4], const uint32_t *key) {uint8_t k[4][4];/* i: row, j: col */for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {k[i][j] = (uint8_t) BYTE(key[j], 3 - i); /* 把 uint32 key[4] 先转换为矩阵 uint8 k[4][4] */state[i][j] ^= k[i][j];}}return 0;
}
// 从uint32_t x中提取从低位开始的第n个字节
#define BYTE(x, n) (((x) >> (8 * (n))) & 0xff)
字节替换,行移位,列混合
//字节替换
int subBytes(uint8_t (*state)[4]) {/* i: row, j: col */for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {state[i][j] = S[state[i][j]]; //直接使用原始字节作为S盒数据下标}}return 0;
}
//行移位
int shiftRows(uint8_t (*state)[4]) {uint32_t block[4] = {0};/* i: row */for (int i = 0; i < 4; ++i) {//便于行循环移位,先把一行4字节拼成uint_32结构,移位后再转成独立的4个字节uint8_tLOAD32H(block[i], state[i]);block[i] = ROF32(block[i], 8*i);STORE32H(block[i], state[i]);}return 0;
}
// 列混合
int mixColumns(uint8_t (*state)[4]) {uint8_t tmp[4][4];uint8_t M[4][4] = {{0x02, 0x03, 0x01, 0x01},{0x01, 0x02, 0x03, 0x01},{0x01, 0x01, 0x02, 0x03},{0x03, 0x01, 0x01, 0x02}};/* copy state[4][4] to tmp[4][4] */for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j){tmp[i][j] = state[i][j];}}for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) { //伽罗华域加法和乘法state[i][j] = GMul(M[i][0], tmp[0][j]) ^ GMul(M[i][1], tmp[1][j])^ GMul(M[i][2], tmp[2][j]) ^ GMul(M[i][3], tmp[3][j]);}}return 0;
}
把4X4状态矩阵转换为uint8_t一维数组输出保存
/* copy state[4][4] to out[16] */
int storeStateArray(uint8_t (*state)[4], uint8_t *out) {for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {*out++ = state[j][i];}}return 0;
}
解密即为上面解密的逆运算:
解密函数:
int aesDecrypt(const uint8_t *key, uint32_t keyLen, const uint8_t *ct, uint8_t *pt, uint32_t len) {AesKey aesKey;uint8_t *pos = pt;const uint32_t *rk = aesKey.dK; //解密秘钥指针uint8_t out[BLOCKSIZE] = {0};uint8_t actualKey[16] = {0};uint8_t state[4][4] = {0};if (NULL == key || NULL == ct || NULL == pt){printf("param err.\n");return -1;}if (keyLen > 16){printf("keyLen must be 16.\n");return -1;}if (len % BLOCKSIZE){printf("inLen is invalid.\n");return -1;}memcpy(actualKey, key, keyLen);keyExpansion(actualKey, 16, &aesKey); //秘钥扩展,同加密for (int i = 0; i < len; i += BLOCKSIZE) {// 把16字节的密文转换为4x4状态矩阵来进行处理loadStateArray(state, ct);// 轮秘钥加,同加密addRoundKey(state, rk);for (int j = 1; j < 10; ++j) {rk += 4;invShiftRows(state); // 逆行移位invSubBytes(state); // 逆字节替换,这两步顺序可以颠倒addRoundKey(state, rk); // 轮秘钥加,同加密invMixColumns(state); // 逆列混合}invSubBytes(state); // 逆字节替换invShiftRows(state); // 逆行移位// 此处没有逆列混合addRoundKey(state, rk+4); // 轮秘钥加,同加密storeStateArray(state, pos); // 保存明文数据pos += BLOCKSIZE; // 输出数据内存指针移位分组长度ct += BLOCKSIZE; // 输入数据内存指针移位分组长度rk = aesKey.dK; // 恢复rk指针到秘钥初始位置}return 0;
}
//逆行移位
int invShiftRows(uint8_t (*state)[4]) {uint32_t block[4] = {0};/* i: row */for (int i = 0; i < 4; ++i) {LOAD32H(block[i], state[i]);block[i] = ROR32(block[i], 8*i);STORE32H(block[i], state[i]);}return 0;
}
//逆字节替换
int invSubBytes(uint8_t (*state)[4]) {/* i: row, j: col */for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {state[i][j] = inv_S[state[i][j]];}}return 0;
}
// 逆列混合
int invMixColumns(uint8_t (*state)[4]) {uint8_t tmp[4][4];uint8_t M[4][4] = {{0x0E, 0x0B, 0x0D, 0x09},{0x09, 0x0E, 0x0B, 0x0D},{0x0D, 0x09, 0x0E, 0x0B},{0x0B, 0x0D, 0x09, 0x0E}}; //使用列混合矩阵的逆矩阵/* copy state[4][4] to tmp[4][4] */for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j){tmp[i][j] = state[i][j];}}for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {state[i][j] = GMul(M[i][0], tmp[0][j]) ^ GMul(M[i][1], tmp[1][j])^ GMul(M[i][2], tmp[2][j]) ^ GMul(M[i][3], tmp[3][j]);}}return 0;
}
罗华域乘法运算的实现
* Galois Field (256) Multiplication of two Bytes */
// 两字节的伽罗华域乘法运算
uint8_t GMul(uint8_t u, uint8_t v) {uint8_t p = 0;for (int i = 0; i < 8; ++i) {if (u & 0x01) { //p ^= v;}int flag = (v & 0x80);v <<= 1;if (flag) {v ^= 0x1B; /* x^8 + x^4 + x^3 + x + 1 */}u >>= 1;}return p;
}
最后测试一下对应的加解密的输出数据和结果
/*AES加解密:采用对称分组密码体制待加解密字符串:32字节长度字符串明文算法模式: ECB (Electronic Code Book , 电子密码本) 模式秘钥长度:秘钥长度输入key应为16字节长度,输入长度应该是16字节整倍数,秘钥:key[]="1234567890123456"秘钥偏移量:None补码方式:None输出编码:十六进制(Hex)
*/
#include "AES128.h"int main()
{/* 加密步骤1.申明秘钥 key2[]2.明文 *data3.加密 aesEncrypt
*/
//****************************************************************************//// 16字节字符串形式秘钥const uint8_t key[]="1234567800000000";// 32字节长度字符串明文const uint8_t *P = (uint8_t*)"WOSHINIANGQINGDEGONGCHENGSHI111"; //外部申请输出数据内存,用于存放加密后数据uint8_t Encrypted_data[32] = {0}; //外部申请输出数据内存,用于存放解密后数据uint8_t Decrypted_data[32] = {0}; //加密32字节明文aesEncrypt(key, 16, P, Encrypted_data, 32); //加密
//****************************************************************************//printf("\n原始明文:\n%s\n", P); //原始明文数据printHex(Encrypted_data, 32, "加密编码(HEX):");//加密后Hex
/* 解密步骤解密函数 aesDecrypt(key, 密钥数据长度, 加密后的数据存放的地址, 用于存放解密后的数据地址, 解密数据的长度)
*/
//****************************************************************************//// 解密32字节密文aesDecrypt(key, 16, Encrypted_data, Decrypted_data, 32);
//****************************************************************************//// 打印16进制形式的解密后的明文printHex(Decrypted_data, 32, "解密编码(HEX):"); //解密后Hex// 因为加密前的数据为可见字符的字符串,打印解密后的明文字符,与加密前明文进行对比printf("解密后反编译出原始明文 \n"); for (int i = 0; i < 32; ++i) {printf("%c ", Decrypted_data[i]);}return 0;
}
输出结果如下:
AES128加密算法实现(C语言:ECB加密模式实现)相关推荐
- SM4 ECB加密模式 数据对比试验论证
程序如下 开启服务器密码机,调用SM4加密函数,需要注意的是 程序输入的数据全部使用Hex 十六进制的格式 Key IV Data IV 0000000000000000000000000000 ...
- SpringBoot+Vue中使用AES进行加解密(加密模式等对照关系)
场景 若依前后端分离版本地搭建开发环境并运行项目的教程: 若依前后端分离版手把手教你本地搭建环境并运行项目_霸道流氓气质的博客-CSDN博客 在上面搭建起来前后端架构之后,在前后端分别进行AES方式的 ...
- 用python实现DES加解密,并附带EBC和CBC两种分组加密模式
之前在网上看了好多关于DES加解密的文章,很多都是直接贴代码,然而大多数都不能运行.花了一天写了个能运行的程序,其中有参考网上的一些好的代码.希望入了密码学坑的同学能得到帮助.python刚上手,代码 ...
- 3des java ecb_PHP 3DES加密 与JAVA通用 加密模式:ECB
昨天帮同事解决了一个接口加密的算法,同事是个小姑娘,不懂,所以老大派我协助她,所以我为了不在姑凉面前掉面子~~火速解决它... 甲方是电信,JAVA写的接口,我一听头就大了,大家都知道~~PHP在加密 ...
- java ecb加密_各加密模式的演示(ECB,CBC) .
对于较长的明文进行加密需要进行分块加密,但是直接加密(ecb)不容易隐藏模式,用OpenCV写了个程序论证了一下 ECB 优点就是简单,可以并行计算,不会迭代误差 缺点就是隐藏不了模式 CBC 需要初 ...
- php openssl支持的加密算法和加密模式及加密解密示范实例
<style> textarea{width:88%;height:188px;} </style><?php // 定义要加密的数据 $data = '我是中文@Thi ...
- 【安全算法之DES】DES算法(支持ECB/CBC模式)的C语言源码实现
[安全算法之DES]DES算法(支持ECB/CBC模式)的C语言源码实现 概述 头文件定义 C语言版本的实现源码 数据分组模式:ECB模式和CBC模式 测试用例 github仓库 更多参考链接 概述 ...
- 各加密模式的演示(ECB,CBC)
对于较长的明文进行加密需要进行分块加密,但是直接加密(ecb)不容易隐藏模式,用OpenCV写了个程序论证了一下 ECB 优点就是简单,可以并行计算,不会迭代误差 缺点就是隐藏不了模式 CBC 需要初 ...
- 常见分组加密算法和加密模式
加密算法 DES DES算法是1972年由IBM设计的,然后被美国政府选为标准加密算法. 分组大小64位,缺点是密钥较短,只有56位,抵抗破解的能力较弱,后来有了3DES. 3DES 3DES算法19 ...
最新文章
- 敏捷开发团队管理系列之三:程序与测试团队II
- maven+eclipse编译常见问题
- 从分布式一致性算法到区块链共识机制
- 深度运用LSTM神经网络并与经典时序模型对比
- spring mvc返回页面显示空白_Spring 框架基础(06):Mvc架构模式简介,执行流程详解...
- UVA 11021 - Tribles(概率递推)
- 两个字符串的最长公共子序列长度_【面试】动态规划-之最长公共子序列、最长公共子串问题...
- 适用于Java开发人员的Elasticsearch:Java的Elasticsearch
- 生成器函数,推导式,生成器表达式
- SQLite 3.31.0 发布,世界上使用量最大的数据库引擎
- sql日期大于某天_(十五)sql/Linux 小技巧
- Python 总体架构
- 小白系列:修改美化pycharm主题
- 超级搜索术2-人脉搜索/分类整理
- java 对象转xml 工具类_工具类 Java对象和XML之间的相互转换-搜云库
- led同步回显到计算机屏幕,手把手教您如何将笔记本电脑的画面投屏到LED大屏幕上显示,音视频同步传输...
- 地铁线路查询(easyx)
- vim/gvim 主题配色方案下载 安装修改配置
- 篮球记分牌c语言程序和报告,跪求:设计一款篮球记分牌,包括C语言程序和proteus的仿真图,最好附带设计报告.。邮箱liuzhonghuaol@126.com。...
- C#卸载程序需要密码/防卸载功能