网站备案年限查询,广州市网站搭建制作,北京网站开发公司有哪些,营销型网站建设哪里好AES简介高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。
对称加密算法也就是加密和解密用相同的密钥#xff0c;具体的加密流程如下图#xff1a; 下面简单介绍下各个部分的作用与意义#xff1a;
明文P没…AES简介高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。
对称加密算法也就是加密和解密用相同的密钥具体的加密流程如下图 下面简单介绍下各个部分的作用与意义
明文P没有经过加密的数据。密钥K用来加密明文的密码在对称加密算法中加密与解密的密钥是相同的。密钥为接收方与发送方协商产生但不可以直接在网络上传输否则会导致密钥泄漏通常是通过非对称加密算法加密密钥然后再通过网络传输给对方或者直接面对面商量密钥。密钥是绝对不可以泄漏的否则会被攻击者还原密文窃取机密数据。AES加密函数设AES加密函数为E则 C  E(K, P),其中P为明文K为密钥C为密文。也就是说把明文P和密钥K作为加密函数的参数输入则加密函数E会输出密文C。密文C经加密函数处理后的数据AES解密函数设AES解密函数为D则 P  D(K, C),其中C为密文K为密钥P为明文。也就是说把密文C和密钥K作为解密函数的参数输入则解密函数会输出明文P。
在这里简单介绍下对称加密算法与非对称加密算法的区别。对称加密算法加密和解密用到的密钥是相同的这种加密方式加密速度非常快适合经常发送数据的场合。缺点是密钥的传输比较麻烦。非对称加密算法加密和解密用的密钥是不同的这种加密方式是用数学上的难解问题构造的通常加密解密的速度比较慢适合偶尔发送数据的场合。优点是密钥传输方便。常见的非对称加密算法为RSA、ECC和EIGamal。
实际中一般是通过RSA加密AES的密钥传输到接收方接收方解密得到AES密钥然后发送方和接收方用AES密钥来通信。本文下面AES原理的介绍参考自《现代密码学教程》AES的实现在介绍完原理后开始。
AES的基本结构
AES为分组密码分组密码也就是把明文分成一组一组的每组长度相等每次加密一组数据直到加密完整个明文。在AES标准规范中分组长度只能是128位也就是说每个分组为16个字节每个字节8位。密钥的长度可以使用128位、192位或256位。密钥的长度不同推荐加密轮数也不同如下表所示
AES密钥长度32位比特字)分组长度(32位比特字)加密轮数AES-1284410AES-1926412AES-2568414
轮数在下面介绍这里实现的是AES-128也就是密钥的长度为128位加密轮数为10轮。 上面说到AES的加密公式为C  E(K,P)在加密函数E中会执行一个轮函数并且执行10次这个轮函数这个轮函数的前9次执行的操作是一样的只有第10次有所不同。也就是说一个明文分组会被加密10轮。AES的核心就是实现一轮中的所有操作。
AES的处理单位是字节128位的输入明文分组P和输入密钥K都被分成16个字节分别记为P  P0 P1 … P15 和 K  K0 K1 … K15。如明文分组为P  abcdefghijklmnop,其中的字符a对应P0p对应P15。一般地明文分组用字节为单位的正方形矩阵描述称为状态矩阵。在算法的每一轮中状态矩阵的内容不断发生变化最后的结果作为密文输出。该矩阵中字节的排列顺序为从上到下、从左至右依次排列如下图所示现在假设明文分组P为”abcdefghijklmnop”则对应上面生成的状态矩阵图如下 上图中0x61为字符a的十六进制表示。可以看到明文经过AES加密后已经面目全非。
类似地128位密钥也是用字节为单位的矩阵表示矩阵的每一列被称为1个32位比特字。通过密钥编排函数该密钥矩阵被扩展成一个44个字组成的序列W[0],W[1], … ,W[43],该序列的前4个元素W[0],W[1],W[2],W[3]是原始密钥用于加密运算中的初始密钥加下面介绍;后面40个字分为10组每组4个字128比特分别用于10轮加密运算中的轮密钥加如下图所示 上图中设K  “abcdefghijklmnop”则K0  a, K15  p, W[0]  K0 K1 K2 K3  “abcd”。
AES的整体结构如下图所示其中的W[0,3]是指W[0]、W[1]、W[2]和W[3]串联组成的128位密钥。加密的第1轮到第9轮的轮函数一样包括4个操作字节代换、行位移、列混合和轮密钥加。最后一轮迭代不执行列混合。另外在第一轮迭代之前先将明文和原始密钥进行一次异或加密操作。 上图也展示了AES解密过程解密过程仍为10轮每一轮的操作是加密操作的逆操作。由于AES的4个轮操作都是可逆的因此解密操作的一轮就是顺序执行逆行移位、逆字节代换、轮密钥加和逆列混合。同加密操作类似最后一轮不执行逆列混合在第1轮解密之前要执行1次密钥加操作。
AES解密
在文章开始的图中有AES解密的流程图可以对应那个流程图来进行解密。下面介绍的是另一种等价的解密模式流程图如下图所示。这种等价的解密模式使得解密过程各个变换的使用顺序同加密过程的顺序一致只是用逆变换取代原来的变换。 
AES原理到这里就结束了下面主要为AES的实现AES算法实现
AES加密函数预览
aes加密函数中首先进行密钥扩展然后把128位长度的字符串读进一个4*4的整数数组中这个数组就是状态矩阵。例如pArray[0][0]  S0,pArray[1][0]  S1, pArray[0][1]  S4。这个读取过程是通过 convertToIntArray()函数来实现的。每个轮操作的函数都对pArray进行修改也就是对状态矩阵进行混淆。在执行完10轮加密后会把pArray转换回字符串再存入明文p的字符数组中所以在加密完后明文p的字符串中的字符就是加密后的字符了。这个转换过程是通过convertArrayToStr()函数来实现的。
/*** 参数 p: 明文的字符串数组。* 参数 plen: 明文的长度。* 参数 key: 密钥的字符串数组。*/
void aes(char *p, int plen, char *key){int keylen  strlen(key);if(plen  0 || plen % 16 ! 0) {printf(明文字符长度必须为16的倍数\n);exit(0);}if(!checkKeyLen(keylen)) {printf(密钥字符长度错误长度必须为16、24和32。当前长度为%d\n,keylen);exit(0);}extendKey(key);//扩展密钥int pArray[4][4];for(int k  0; k  plen; k  16) {convertToIntArray(p  k, pArray);addRoundKey(pArray, 0);//一开始的轮密钥加for(int i  1; i  10; i){//前9轮subBytes(pArray);//字节代换shiftRows(pArray);//行移位mixColumns(pArray);//列混合addRoundKey(pArray, i);}//第10轮subBytes(pArray);//字节代换shiftRows(pArray);//行移位addRoundKey(pArray, 10);convertArrayToStr(pArray, p  k);}
}
1.密钥扩展的实现
在开始加密前必须先获得第一轮加密用到的密钥故先实现密钥扩展 下面是密钥扩展函数的实现这个函数传入密钥key的字符串表示然后从字符串中读取W[0]到W[3],函数getWordFromStr()用于实现此功能。读取后就开始扩展密钥当i是4的倍数的时候就会调用T()函数来进行扩展因为T函数的行为与加密的轮数有关故要把加密的轮数 j 作为参数传进去。
//密钥对应的扩展数组
static int w[44];/*** 扩展密钥结果是把w[44]中的每个元素初始化*/
static void extendKey(char *key) {for(int i  0; i  4; i)w[i]  getWordFromStr(key  i * 4); for(int i  4, j  0; i  44; i) {if( i % 4  0) {w[i]  w[i - 4] ^ T(w[i - 1], j); j;//下一轮}else {w[i]  w[i - 4] ^ w[i - 1]; }}   }下面是T()函数的代码实现T()函数中接收两个参数参数num为上面传进的W[i - 1]round为加密的轮数。首先用一个numArray储存从32位的W[i-1]中取得4个字节。如果W[i-1]为0x12ABCDEF,那么numArray[0]  0x12,numArray[1]  0xAB。函数splitIntToArray()用于从32位整数中读取这四个字节之所以这样做是因为整数数组比较容易操作。然后调用leftLoop4int()函数把numArray数组中的4个元素循环左移1位。然后执行字节代换通过getNumFromSBox()函数来获取S盒中相应的值来替换numArray中的值。接着通过mergeArrayToInt()函数把字节代换后的numArray合并回32位的整数在进行轮常量异或后返回。
/*** 常量轮值表*/
static const int Rcon[10]  { 0x01000000, 0x02000000,0x04000000, 0x08000000,0x10000000, 0x20000000,0x40000000, 0x80000000,0x1b000000, 0x36000000 };
/*** 密钥扩展中的T函数*/
static int T(int num, int round) {int numArray[4];splitIntToArray(num, numArray);leftLoop4int(numArray, 1);//字循环//字节代换for(int i  0; i  4; i)numArray[i]  getNumFromSBox(numArray[i]);int result  mergeArrayToInt(numArray);return result ^ Rcon[round];
}2. 字节代换的实现
字节代换的代码很简单就是把状态矩阵中的每个元素传进getNumFromSBox()函数中然后取得前面8位中的高4位作为行值低4位作为列值然后返回S[row][col]这里的S是储存S盒的数组。/*** 根据索引从S盒中获得元素*/
static int getNumFromSBox(int index) {int row  getLeft4Bit(index);int col  getRight4Bit(index);return S[row][col];
}/*** 字节代换*/
static void subBytes(int array[4][4]){for(int i  0; i  4; i)for(int j  0; j  4; j)array[i][j]  getNumFromSBox(array[i][j]);
}3.行移位的实现
行移位的时候首先把状态矩阵中第234行复制出来然后对它们行进左移相应的位数然后再复制回去状态矩阵array中。/*** 将数组中的元素循环左移step位*/
static void leftLoop4int(int array[4], int step) {int temp[4];for(int i  0; i  4; i)temp[i]  array[i];int index  step % 4  0 ? 0 : step % 4;for(int i  0; i  4; i){array[i]  temp[index];index;index  index % 4;}
}/*** 行移位*/
static void shiftRows(int array[4][4]) {int rowTwo[4], rowThree[4], rowFour[4];//复制状态矩阵的第2,3,4行for(int i  0; i  4; i) {rowTwo[i]  array[1][i];rowThree[i]  array[2][i];rowFour[i]  array[3][i];}//循环左移相应的位数leftLoop4int(rowTwo, 1);leftLoop4int(rowThree, 2);leftLoop4int(rowFour, 3);//把左移后的行复制回状态矩阵中for(int i  0; i  4; i) {array[1][i]  rowTwo[i];array[2][i]  rowThree[i];array[3][i]  rowFour[i];}
}4.列混合的实现
列混合函数中先把状态矩阵初始状态复制一份到tempArray中然后把tempArray与colM矩阵相乘colM为存放要乘的常数矩阵的数组。其中的GFMul()函数定义了矩阵相乘时的乘法加法则直接通过异或来实现。GFMul()通过调用乘以各个数对应的函数来实现乘法。例如S1 * 2 刚通过调用GFMul2(S1)来实现。S1 * 3 刚通过GFMul3(S1)来实现。在这里主要实现GFMul2()函数就行了其它的都可以通过GFMul2()的组合来实现。举个例子吧为计算下面这条等式需要像下面这样调用函数 
s  GFMul3(0xC9) ^ 0x7A ^ 0x63 ^ GFMul2(0xB0)
/*** 列混合要用到的矩阵*/
static const int colM[4][4]  { 2, 3, 1, 1,1, 2, 3, 1,1, 1, 2, 3,3, 1, 1, 2 };static int GFMul2(int s) {int result  s  1;int a7  result  0x00000100;if(a7 ! 0) {result  result  0x000000ff;result  result ^ 0x1b;}return result;
}static int GFMul3(int s) {return GFMul2(s) ^ s;
}/*** GF上的二元运算*/
static int GFMul(int n, int s) {int result;if(n  1)result  s;else if(n  2)result  GFMul2(s);else if(n  3)result  GFMul3(s);else if(n  0x9)result  GFMul9(s);else if(n  0xb)//11result  GFMul11(s);else if(n  0xd)//13result  GFMul13(s);else if(n  0xe)//14result  GFMul14(s);return result;
}/*** 列混合*/
static void mixColumns(int array[4][4]) {int tempArray[4][4];for(int i  0; i  4; i)for(int j  0; j  4; j)tempArray[i][j]  array[i][j];for(int i  0; i  4; i)for(int j  0; j  4; j){array[i][j]  GFMul(colM[i][0],tempArray[0][j]) ^ GFMul(colM[i][1],tempArray[1][j])^ GFMul(colM[i][2],tempArray[2][j]) ^ GFMul(colM[i][3], tempArray[3][j]);}
}5.轮密钥加的实现
轮密钥加的实现很简单就是根据传入的轮数来把状态矩阵与相应的W[i]异或。/*** 轮密钥加*/
static void addRoundKey(int array[4][4], int round) {int warray[4];for(int i  0; i  4; i) {splitIntToArray(w[ round * 4  i], warray);for(int j  0; j  4; j) {array[j][i]  array[j][i] ^ warray[j];}}
}AES解密函数
AES的解密函数和加密函数有点不同可以参考上面的等价解密流程图来理解解密函数中调用的是各轮操作的逆函数。逆函数在这里就不详细讲解了可以参考最后的完整代码。
/*** 参数 c: 密文的字符串数组。* 参数 clen: 密文的长度。* 参数 key: 密钥的字符串数组。*/
void deAes(char *c, int clen, char *key) {int keylen  strlen(key);if(clen  0 || clen % 16 ! 0) {printf(密文字符长度必须为16的倍数现在的长度为%d\n,clen);exit(0);}if(!checkKeyLen(keylen)) {printf(密钥字符长度错误长度必须为16、24和32。当前长度为%d\n,keylen);exit(0);}extendKey(key);//扩展密钥int cArray[4][4];for(int k  0; k  clen; k  16) {convertToIntArray(c  k, cArray);addRoundKey(cArray, 10);int wArray[4][4];for(int i  9; i  1; i--) {deSubBytes(cArray);deShiftRows(cArray);deMixColumns(cArray);getArrayFrom4W(i, wArray);deMixColumns(wArray);addRoundTowArray(cArray, wArray);}deSubBytes(cArray);deShiftRows(cArray);addRoundKey(cArray, 0);convertArrayToStr(cArray, c  k);}
}完整的程序代码
Linux版本
aes.h
#ifndef AES_H
#define AES_H/*** 参数 p: 明文的字符串数组。* 参数 plen: 明文的长度,长度必须为16的倍数。* 参数 key: 密钥的字符串数组。*/
void aes(char *p, int plen, char *key);/*** 参数 c: 密文的字符串数组。* 参数 clen: 密文的长度,长度必须为16的倍数。* 参数 key: 密钥的字符串数组。*/
void deAes(char *c, int clen, char *key);#endifaes.c
#include stdio.h
#include stdlib.h
#include string.h
#include aes.h/*** S盒*/
static const int S[16][16]  { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 };/*** 逆S盒*/
static const int S2[16][16]  { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };/*** 获取整形数据的低8位的左4个位*/
static int getLeft4Bit(int num) {int left  num  0x000000f0;return left  4;
}/*** 获取整形数据的低8位的右4个位*/
static int getRight4Bit(int num) {return num  0x0000000f;
}
/*** 根据索引从S盒中获得元素*/
static int getNumFromSBox(int index) {int row  getLeft4Bit(index);int col  getRight4Bit(index);return S[row][col];
}/*** 把一个字符转变成整型*/
static int getIntFromChar(char c) {int result  (int) c;return result  0x000000ff;
}/*** 把16个字符转变成4X4的数组* 该矩阵中字节的排列顺序为从上到下* 从左到右依次排列。*/
static void convertToIntArray(char *str, int pa[4][4]) {int k  0;for(int i  0; i  4; i)for(int j  0; j  4; j) {pa[j][i]  getIntFromChar(str[k]);k;}
}/*** 打印4X4的数组*/
static void printArray(int a[4][4]) {for(int i  0; i  4; i){for(int j  0; j  4; j)printf(a[%d][%d]  0x%x , i, j, a[i][j]);printf(\n);}printf(\n);
}/*** 打印字符串的ASSCI* 以十六进制显示。*/
static void printASSCI(char *str, int len) {for(int i  0; i  len; i)printf(0x%x , getIntFromChar(str[i]));printf(\n);
}/*** 把连续的4个字符合并成一个4字节的整型*/
static int getWordFromStr(char *str) {int one  getIntFromChar(str[0]);one  one  24;int two  getIntFromChar(str[1]);two  two  16;int three  getIntFromChar(str[2]);three  three  8;int four  getIntFromChar(str[3]);return one | two | three | four;
}/*** 把一个4字节的数的第一、二、三、四个字节取出* 入进一个4个元素的整型数组里面。*/
static void splitIntToArray(int num, int array[4]) {int one  num  24;array[0]  one  0x000000ff;int two  num  16;array[1]  two  0x000000ff;int three  num  8;array[2]  three  0x000000ff;array[3]  num  0x000000ff;
}/*** 将数组中的元素循环左移step位*/
static void leftLoop4int(int array[4], int step) {int temp[4];for(int i  0; i  4; i)temp[i]  array[i];int index  step % 4  0 ? 0 : step % 4;for(int i  0; i  4; i){array[i]  temp[index];index;index  index % 4;}
}/*** 把数组中的第一、二、三和四元素分别作为* 4字节整型的第一、二、三和四字节合并成一个4字节整型*/
static int mergeArrayToInt(int array[4]) {int one  array[0]  24;int two  array[1]  16;int three  array[2]  8;int four  array[3];return one | two | three | four;
}/*** 常量轮值表*/
static const int Rcon[10]  { 0x01000000, 0x02000000,0x04000000, 0x08000000,0x10000000, 0x20000000,0x40000000, 0x80000000,0x1b000000, 0x36000000 };
/*** 密钥扩展中的T函数*/
static int T(int num, int round) {int numArray[4];splitIntToArray(num, numArray);leftLoop4int(numArray, 1);//字循环//字节代换for(int i  0; i  4; i)numArray[i]  getNumFromSBox(numArray[i]);int result  mergeArrayToInt(numArray);return result ^ Rcon[round];
}//密钥对应的扩展数组
static int w[44];/*** 扩展密钥结果是把w[44]中的每个元素初始化*/
static void extendKey(char *key) {for(int i  0; i  4; i)w[i]  getWordFromStr(key  i * 4);for(int i  4, j  0; i  44; i) {if( i % 4  0) {w[i]  w[i - 4] ^ T(w[i - 1], j);j;//下一轮}else {w[i]  w[i - 4] ^ w[i - 1];}}}/*** 轮密钥加*/
static void addRoundKey(int array[4][4], int round) {int warray[4];for(int i  0; i  4; i) {splitIntToArray(w[ round * 4  i], warray);for(int j  0; j  4; j) {array[j][i]  array[j][i] ^ warray[j];}}
}/*** 字节代换*/
static void subBytes(int array[4][4]){for(int i  0; i  4; i)for(int j  0; j  4; j)array[i][j]  getNumFromSBox(array[i][j]);
}/*** 行移位*/
static void shiftRows(int array[4][4]) {int rowTwo[4], rowThree[4], rowFour[4];//复制状态矩阵的第2,3,4行for(int i  0; i  4; i) {rowTwo[i]  array[1][i];rowThree[i]  array[2][i];rowFour[i]  array[3][i];}//循环左移相应的位数leftLoop4int(rowTwo, 1);leftLoop4int(rowThree, 2);leftLoop4int(rowFour, 3);//把左移后的行复制回状态矩阵中for(int i  0; i  4; i) {array[1][i]  rowTwo[i];array[2][i]  rowThree[i];array[3][i]  rowFour[i];}
}/*** 列混合要用到的矩阵*/
static const int colM[4][4]  { 2, 3, 1, 1,1, 2, 3, 1,1, 1, 2, 3,3, 1, 1, 2 };static int GFMul2(int s) {int result  s  1;int a7  result  0x00000100;if(a7 ! 0) {result  result  0x000000ff;result  result ^ 0x1b;}return result;
}static int GFMul3(int s) {return GFMul2(s) ^ s;
}static int GFMul4(int s) {return GFMul2(GFMul2(s));
}static int GFMul8(int s) {return GFMul2(GFMul4(s));
}static int GFMul9(int s) {return GFMul8(s) ^ s;
}static int GFMul11(int s) {return GFMul9(s) ^ GFMul2(s);
}static int GFMul12(int s) {return GFMul8(s) ^ GFMul4(s);
}static int GFMul13(int s) {return GFMul12(s) ^ s;
}static int GFMul14(int s) {return GFMul12(s) ^ GFMul2(s);
}/*** GF上的二元运算*/
static int GFMul(int n, int s) {int result;if(n  1)result  s;else if(n  2)result  GFMul2(s);else if(n  3)result  GFMul3(s);else if(n  0x9)result  GFMul9(s);else if(n  0xb)//11result  GFMul11(s);else if(n  0xd)//13result  GFMul13(s);else if(n  0xe)//14result  GFMul14(s);return result;
}
/*** 列混合*/
static void mixColumns(int array[4][4]) {int tempArray[4][4];for(int i  0; i  4; i)for(int j  0; j  4; j)tempArray[i][j]  array[i][j];for(int i  0; i  4; i)for(int j  0; j  4; j){array[i][j]  GFMul(colM[i][0],tempArray[0][j]) ^ GFMul(colM[i][1],tempArray[1][j]) ^ GFMul(colM[i][2],tempArray[2][j]) ^ GFMul(colM[i][3], tempArray[3][j]);}
}
/*** 把4X4数组转回字符串*/
static void convertArrayToStr(int array[4][4], char *str) {for(int i  0; i  4; i)for(int j  0; j  4; j)*str  (char)array[j][i]; 
}
/*** 检查密钥长度*/
static int checkKeyLen(int len) {if(len  16)return 1;elsereturn 0;
}/*** 参数 p: 明文的字符串数组。* 参数 plen: 明文的长度。* 参数 key: 密钥的字符串数组。*/
void aes(char *p, int plen, char *key){int keylen  strlen(key);if(plen  0 || plen % 16 ! 0) {printf(明文字符长度必须为16的倍数\n);exit(0);}if(!checkKeyLen(keylen)) {printf(密钥字符长度错误长度必须为16、24和32。当前长度为%d\n,keylen);exit(0);}extendKey(key);//扩展密钥int pArray[4][4];for(int k  0; k  plen; k  16) { convertToIntArray(p  k, pArray);addRoundKey(pArray, 0);//一开始的轮密钥加for(int i  1; i  10; i){//前9轮subBytes(pArray);//字节代换shiftRows(pArray);//行移位mixColumns(pArray);//列混合addRoundKey(pArray, i);}//第10轮subBytes(pArray);//字节代换shiftRows(pArray);//行移位addRoundKey(pArray, 10);convertArrayToStr(pArray, p  k);}
}
/*** 根据索引从逆S盒中获取值*/
static int getNumFromS1Box(int index) {int row  getLeft4Bit(index);int col  getRight4Bit(index);return S2[row][col];
}
/*** 逆字节变换*/
static void deSubBytes(int array[4][4]) {for(int i  0; i  4; i)for(int j  0; j  4; j)array[i][j]  getNumFromS1Box(array[i][j]);
}
/*** 把4个元素的数组循环右移step位*/
static void rightLoop4int(int array[4], int step) {int temp[4];for(int i  0; i  4; i)temp[i]  array[i];int index  step % 4  0 ? 0 : step % 4;index  3 - index;for(int i  3; i  0; i--) {array[i]  temp[index];index--;index  index  -1 ? 3 : index;}
}/*** 逆行移位*/
static void deShiftRows(int array[4][4]) {int rowTwo[4], rowThree[4], rowFour[4];for(int i  0; i  4; i) {rowTwo[i]  array[1][i];rowThree[i]  array[2][i];rowFour[i]  array[3][i];}rightLoop4int(rowTwo, 1);rightLoop4int(rowThree, 2);rightLoop4int(rowFour, 3);for(int i  0; i  4; i) {array[1][i]  rowTwo[i];array[2][i]  rowThree[i];array[3][i]  rowFour[i];}
}
/*** 逆列混合用到的矩阵*/
static const int deColM[4][4]  { 0xe, 0xb, 0xd, 0x9,0x9, 0xe, 0xb, 0xd,0xd, 0x9, 0xe, 0xb,0xb, 0xd, 0x9, 0xe };/*** 逆列混合*/
static void deMixColumns(int array[4][4]) {int tempArray[4][4];for(int i  0; i  4; i)for(int j  0; j  4; j)tempArray[i][j]  array[i][j];for(int i  0; i  4; i)for(int j  0; j  4; j){array[i][j]  GFMul(deColM[i][0],tempArray[0][j]) ^ GFMul(deColM[i][1],tempArray[1][j]) ^ GFMul(deColM[i][2],tempArray[2][j]) ^ GFMul(deColM[i][3], tempArray[3][j]);}
}
/*** 把两个4X4数组进行异或*/
static void addRoundTowArray(int aArray[4][4],int bArray[4][4]) {for(int i  0; i  4; i)for(int j  0; j  4; j)aArray[i][j]  aArray[i][j] ^ bArray[i][j];
}
/*** 从4个32位的密钥字中获得4X4数组* 用于进行逆列混合*/
static void getArrayFrom4W(int i, int array[4][4]) {int index  i * 4;int colOne[4], colTwo[4], colThree[4], colFour[4];splitIntToArray(w[index], colOne);splitIntToArray(w[index  1], colTwo);splitIntToArray(w[index  2], colThree);splitIntToArray(w[index  3], colFour);for(int i  0; i  4; i) {array[i][0]  colOne[i];array[i][1]  colTwo[i];array[i][2]  colThree[i];array[i][3]  colFour[i];}}/*** 参数 c: 密文的字符串数组。* 参数 clen: 密文的长度。* 参数 key: 密钥的字符串数组。*/
void deAes(char *c, int clen, char *key) {int keylen  strlen(key);if(clen  0 || clen % 16 ! 0) {printf(密文字符长度必须为16的倍数现在的长度为%d\n,clen);exit(0);}if(!checkKeyLen(keylen)) {printf(密钥字符长度错误长度必须为16、24和32。当前长度为%d\n,keylen);exit(0);}extendKey(key);//扩展密钥int cArray[4][4];for(int k  0; k  clen; k  16) {convertToIntArray(c  k, cArray);addRoundKey(cArray, 10);int wArray[4][4];for(int i  9; i  1; i--) {deSubBytes(cArray);deShiftRows(cArray);deMixColumns(cArray);getArrayFrom4W(i, wArray);deMixColumns(wArray);addRoundTowArray(cArray, wArray);}deSubBytes(cArray);deShiftRows(cArray);addRoundKey(cArray, 0);convertArrayToStr(cArray, c  k);}
}
main.c
#include stdio.h
#include unistd.h
#include string.h
#include stdlib.h#include aes.h#define MAXLEN 1024void getString(char *str, int len){int slen  read(0, str, len);for(int i  0; i  slen; i,str){if(*str  \n){*str  \0;break;}}
}void printASCCI(char *str, int len) {int c;for(int i  0; i  len; i) {c  (int)*str;c  c  0x000000ff;printf(0x%x , c);}printf(\n);
}/*** 从标准输入中读取用户输入的字符串*/
void readPlainText(char *str, int *len) {int plen;while(1) {getString(str, MAXLEN);plen  strlen(str);if(plen ! 0  plen % 16  0) {printf(你输入的明文为%s\n, str);break;}else{printf(明文字符长度必须为16的倍数,现在的长度为%d\n, plen);}}*len  plen;
}
/*** 把字符串写进文件*/
void writeStrToFile(char *str, int len, char *fileName) {FILE *fp;fp  fopen(fileName, wb);for(int i  0; i  len; i)putc(str[i], fp);fclose(fp);
}void aesStrToFile(char *key) {char p[MAXLEN];int plen;printf(请输入你的明文明文字符长度必须为16的倍数\n);readPlainText(p,plen);printf(进行AES加密..................\n);aes(p, plen, key);//AES加密printf(加密完后的明文的ASCCI为\n);printASCCI(p, plen);char fileName[64];printf(请输入你想要写进的文件名比如test.txt:\n);if(scanf(%s, fileName)  1) {    writeStrToFile(p, plen, fileName);printf(已经将密文写进%s中了,可以在运行该程序的当前目录中找到它。\n, fileName);}
}
/*** 从文件中读取字符串*/
int readStrFromFile(char *fileName, char *str) {FILE *fp  fopen(fileName, rb);if(fp  NULL) {printf(打开文件出错请确认文件存在当前目录下\n);exit(0);}int i;for(i  0; i  MAXLEN  (str[i]  getc(fp)) ! EOF; i);if(i  MAXLEN) {printf(解密文件过大\n);exit(0);}str[i]  \0;fclose(fp);return i;
}void deAesFile(char *key) {char fileName[64];char c[MAXLEN];//密文字符串printf(请输入要解密的文件名该文件必须和本程序在同一个目录\n);if(scanf(%s, fileName)  1) {int clen  readStrFromFile(fileName, c);printf(开始解密.........\n);deAes(c, clen, key);printf(解密后的明文ASCII为\n);printASCCI(c, clen);printf(明文为%s\n, c);writeStrToFile(c,clen,fileName);printf(现在可以打开%s来查看解密后的密文了\n,fileName);}
}void aesFile(char *key) {char fileName[64];char fileP[MAXLEN];printf(请输入要加密的文件名该文件必须和本程序在同一个目录\n);if(scanf(%s, fileName)  1) {readStrFromFile(fileName, fileP);int plen  strlen(fileP);printf(开始加密.........\n);printf(加密前文件中字符的ASCII为\n);printASCCI(fileP, plen);aes(fileP, plen, key);//开始加密printf(加密后的密文ASCII为\n);printASCCI(fileP, plen);writeStrToFile(fileP,plen,fileName);printf(已经将加密后的密文写进%s中了\n,fileName);}
}int main(int argc, char const *argv[]) {char key[17];printf(请输入16个字符的密钥\n);int klen;while(1){getString(key,17);klen  strlen(key);if(klen ! 16){printf(请输入16个字符的密钥,当前密钥的长度为%d\n,klen);}else{printf(你输入的密钥为%s\n,key);break;}}printf(输入s表示要加密输入的字符串,并将加密后的内容写入到文件\n);printf(请输入要功能选项并按回车输入f表示要加密文件\n);printf(输入p表示要解密文件\n);char c;if(scanf(%s,c)  1) {if(c  s)aesStrToFile(key);//用AES加密字符串并将字符串写进文件中else if(c  p)deAesFile(key);//把文件中的密文解密并写回文件中else if(c  f)//用AES加密文件aesFile(key);}return 0;
}通过下面的gcc命令来编译运行
gcc -o aes aes.c main.c
相关文章: