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加密模式实现)相关推荐

  1. SM4 ECB加密模式 数据对比试验论证

    程序如下 开启服务器密码机,调用SM4加密函数,需要注意的是 程序输入的数据全部使用Hex 十六进制的格式  Key IV Data IV   0000000000000000000000000000 ...

  2. SpringBoot+Vue中使用AES进行加解密(加密模式等对照关系)

    场景 若依前后端分离版本地搭建开发环境并运行项目的教程: 若依前后端分离版手把手教你本地搭建环境并运行项目_霸道流氓气质的博客-CSDN博客 在上面搭建起来前后端架构之后,在前后端分别进行AES方式的 ...

  3. 用python实现DES加解密,并附带EBC和CBC两种分组加密模式

    之前在网上看了好多关于DES加解密的文章,很多都是直接贴代码,然而大多数都不能运行.花了一天写了个能运行的程序,其中有参考网上的一些好的代码.希望入了密码学坑的同学能得到帮助.python刚上手,代码 ...

  4. 3des java ecb_PHP 3DES加密 与JAVA通用 加密模式:ECB

    昨天帮同事解决了一个接口加密的算法,同事是个小姑娘,不懂,所以老大派我协助她,所以我为了不在姑凉面前掉面子~~火速解决它... 甲方是电信,JAVA写的接口,我一听头就大了,大家都知道~~PHP在加密 ...

  5. java ecb加密_各加密模式的演示(ECB,CBC) .

    对于较长的明文进行加密需要进行分块加密,但是直接加密(ecb)不容易隐藏模式,用OpenCV写了个程序论证了一下 ECB 优点就是简单,可以并行计算,不会迭代误差 缺点就是隐藏不了模式 CBC 需要初 ...

  6. php openssl支持的加密算法和加密模式及加密解密示范实例

    <style> textarea{width:88%;height:188px;} </style><?php // 定义要加密的数据 $data = '我是中文@Thi ...

  7. 【安全算法之DES】DES算法(支持ECB/CBC模式)的C语言源码实现

    [安全算法之DES]DES算法(支持ECB/CBC模式)的C语言源码实现 概述 头文件定义 C语言版本的实现源码 数据分组模式:ECB模式和CBC模式 测试用例 github仓库 更多参考链接 概述 ...

  8. 各加密模式的演示(ECB,CBC)

    对于较长的明文进行加密需要进行分块加密,但是直接加密(ecb)不容易隐藏模式,用OpenCV写了个程序论证了一下 ECB 优点就是简单,可以并行计算,不会迭代误差 缺点就是隐藏不了模式 CBC 需要初 ...

  9. 常见分组加密算法和加密模式

    加密算法 DES DES算法是1972年由IBM设计的,然后被美国政府选为标准加密算法. 分组大小64位,缺点是密钥较短,只有56位,抵抗破解的能力较弱,后来有了3DES. 3DES 3DES算法19 ...

最新文章

  1. 敏捷开发团队管理系列之三:程序与测试团队II
  2. maven+eclipse编译常见问题
  3. 从分布式一致性算法到区块链共识机制
  4. 深度运用LSTM神经网络并与经典时序模型对比
  5. spring mvc返回页面显示空白_Spring 框架基础(06):Mvc架构模式简介,执行流程详解...
  6. UVA 11021 - Tribles(概率递推)
  7. 两个字符串的最长公共子序列长度_【面试】动态规划-之最长公共子序列、最长公共子串问题...
  8. 适用于Java开发人员的Elasticsearch:Java的Elasticsearch
  9. 生成器函数,推导式,生成器表达式
  10. SQLite 3.31.0 发布,世界上使用量最大的数据库引擎
  11. sql日期大于某天_(十五)sql/Linux 小技巧
  12. Python 总体架构
  13. 小白系列:修改美化pycharm主题
  14. 超级搜索术2-人脉搜索/分类整理
  15. java 对象转xml 工具类_工具类 Java对象和XML之间的相互转换-搜云库
  16. led同步回显到计算机屏幕,手把手教您如何将笔记本电脑的画面投屏到LED大屏幕上显示,音视频同步传输...
  17. 地铁线路查询(easyx)
  18. vim/gvim 主题配色方案下载 安装修改配置
  19. 篮球记分牌c语言程序和报告,跪求:设计一款篮球记分牌,包括C语言程序和proteus的仿真图,最好附带设计报告.。邮箱liuzhonghuaol@126.com。...
  20. C#卸载程序需要密码/防卸载功能

热门文章

  1. linux中无法联网小电脑图标不见,电脑桌面上的网络连接图标突然不见怎么解决?...
  2. IP地址(分类)、子网掩码、网络号、主机号、子网号
  3. JS短信接口代码示例
  4. 【Python基础】对象的浅拷贝与深拷贝
  5. 分布式电商项目五:使用人人开源搭建前后分离的后台管理系统
  6. 人工智能教你识别口红色号
  7. 超人气思维导图XMind新年新版本,这6个新功能你一定要看
  8. ClippingNode做游戏的新手指导
  9. 国产Linux系统UOS安装
  10. 图片批量下载 +图片马赛克:多张图片组成端午安康!