电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
厂商活动
正点原子
板卡试用
资源库
下载
文章
社区首页
文章
AES-128 ECB加密---一看就懂,图文并茂
分 享
扫描二维码分享
AES-128 ECB加密---一看就懂,图文并茂
C语言
AES128
加密
爱笑的男孩
关注
发布时间: 2019-12-30
丨
阅读: 4490
## AES是什么? AES是一个高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法。该算法为【比利时】密码学家Joan Daemen和Vincent Rijmen早期所设计的Square改良而来。 这个时候你会发现一个有趣的点:Rijndael是结合两位作者的名字而来! AES按加密方式分为:AES-128、AES-192、AES-256; 按加密模式分为:ECB、CBC、CTR、CFB、OCF。 ![aes模式](https://cf03.ickimg.com/bbsimages/201912/0d8b2c1af99d381ce8e7949aa16ccbae.png "aes模式") ## AES流程是怎么样的 ? 首先要给大家介绍几个概念: 明文:未经加密的真实原始数据(重点:珍贵) 密钥:用来给明文加密的数据(重点:珍贵) AES加密函数:经过N轮的加密流程,让明文+密钥生成一个别人看不懂的密文,传输用途!(密文重点:别人看不懂,获取了也看不懂) AES加密流程如下: ![aes解密](https://cf03.ickimg.com/bbsimages/201912/a4f42459df32d43a4bd5f8b43dcfd26a.png "aes解密") 获取密文后,如果需要进行解密,接收方需要知道相同的密钥,并经过AES解密函数解密,才能得到正确的明文。 解密流程如下: ![](https://cf03.ickimg.com/bbsimages/201912/f2c87c8abc876166213b0d51b840b965.png) AES加密函数,即是AES加密原理。那么AES-128加密原理是怎么样的呢? 首先,复习一个C语言的算法:【异或 】"^" 异或运算符"∧"它的规则是若参加运算的**两个二进位同号,则结果为0**(假);**异号则为1**(真)。即 0∧0=0,0∧1=1, 1^0=1,1∧1=0。 ![](https://cf03.ickimg.com/bbsimages/201912/2ca2dae99c5fb473d71af6bac8e66ec4.png) ## 信息安全算法【域加】和【域乘】 我们需要再了解信息安全上的两个数学知识,我们在这里称为【域加】和【域乘】 。 data = 0b(00000010) key = 0b(abcdefgh) 【域加】:两个数的运算:【域加】相当有两个数的异或; 【例子】:data+key = data^key 这个域加的算法不难理解。 【域乘】:把被乘数ke以二进制的方式展开,若最高位为0,域乘就是结果就是被乘数左移一位! 若最高位为1,将数据左移一位后,再乘数相【域加】(异或) 【例子】: if( a ==0 ) data*key = bcdefgh0 else data*key = bcdefgh0 * 00011011 ## AES-128 ECB加密步骤 ![](https://cf03.ickimg.com/bbsimages/201912/3254e763ed2e6df779336fd05a2cd9be.png) ### 1.将明文矩阵转换成状态矩阵 若16个字节明文为:abcdefghijklmnop,将他们变成状态矩阵如下。用于做字节代换。 | a | e | i | m | | ---- | ---- | ---- | ---- | | b | f | j | n | | c | g | k | o | | d | h | l | p | ### 2.字节代换 AES定义了一个S盒 | 行/列 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | | :---- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | | 0 | 0x63 | 0x7c | 0x77 | 0x7b | 0xf2 | 0x6b | 0x6f | 0xc5 | 0x30 | 0x01 | 0x67 | 0x2b | 0xfe | 0xd7 | 0xab | 0x76 | | 1 | 0xca | 0x82 | 0xc9 | 0x7d | 0xfa | 0x59 | 0x47 | 0xf0 | 0xad | 0xd4 | 0xa2 | 0xaf | 0x9c | 0xa4 | 0x72 | 0xc0 | | 2 | 0xb7 | 0xfd | 0x93 | 0x26 | 0x36 | 0x3f | 0xf7 | 0xcc | 0x34 | 0xa5 | 0xe5 | 0xf1 | 0x71 | 0xd8 | 0x31 | 0x15 | | 3 | 0x04 | 0xc7 | 0x23 | 0xc3 | 0x18 | 0x96 | 0x05 | 0x9a | 0x07 | 0x12 | 0x80 | 0xe2 | 0xeb | 0x27 | 0xb2 | 0x75 | | 4 | 0x09 | 0x83 | 0x2c | 0x1a | 0x1b | 0x6e | 0x5a | 0xa0 | 0x52 | 0x3b | 0xd6 | 0xb3 | 0x29 | 0xe3 | 0x2f | 0x84 | | 5 | 0x53 | 0xd1 | 0x00 | 0xed | 0x20 | 0xfc | 0xb1 | 0x5b | 0x6a | 0xcb | 0xbe | 0x39 | 0x4a | 0x4c | 0x58 | 0xcf | | 6 | 0xd0 | 0xef | 0xaa | 0xfb | 0x43 | 0x4d | 0x33 | 0x85 | 0x45 | 0xf9 | 0x02 | 0x7f | 0x50 | 0x3c | 0x9f | 0xa8 | | 7 | 0x51 | 0xa3 | 0x40 | 0x8f | 0x92 | 0x9d | 0x38 | 0xf5 | 0xbc | 0xb6 | 0xda | 0x21 | 0x10 | 0xff | 0xf3 | 0xd2 | | 8 | 0xcd | 0x0c | 0x13 | 0xec | 0x5f | 0x97 | 0x44 | 0x17 | 0xc4 | 0xa7 | 0x7e | 0x3d | 0x64 | 0x5d | 0x19 | 0x73 | | 9 | 0x60 | 0x81 | 0x4f | 0xdc | 0x22 | 0x2a | 0x90 | 0x88 | 0x46 | 0xee | 0xb8 | 0x14 | 0xde | 0x5e | 0x0b | 0xdb | | A | 0xe0 | 0x32 | 0x3a | 0x0a | 0x49 | 0x06 | 0x24 | 0x5c | 0xc2 | 0xd3 | 0xac | 0x62 | 0x91 | 0x95 | 0xe4 | 0x79 | | B | 0xe7 | 0xc8 | 0x37 | 0x6d | 0x8d | 0xd5 | 0x4e | 0xa9 | 0x6c | 0x56 | 0xf4 | 0xea | 0x65 | 0x7a | 0xae | 0x08 | | C | 0xba | 0x78 | 0x25 | 0x2e | 0x1c | 0xa6 | 0xb4 | 0xc6 | 0xe8 | 0xdd | 0x74 | 0x1f | 0x4b | 0xbd | 0x8b | 0x8a | | D | 0x70 | 0x3e | 0xb5 | 0x66 | 0x48 | 0x03 | 0xf6 | 0x0e | 0x61 | 0x35 | 0x57 | 0xb9 | 0x86 | 0xc1 | 0x1d | 0x9e | | E | 0xe1 | 0xf8 | 0x98 | 0x11 | 0x69 | 0xd9 | 0x8e | 0x94 | 0x9b | 0x1e | 0x87 | 0xe9 | 0xce | 0x55 | 0x28 | 0xdf | | F | 0x8c | 0xa1 | 0x89 | 0x0d | 0xbf | 0xe6 | 0x42 | 0x68 | 0x41 | 0x99 | 0x2d | 0x0f | 0xb0 | 0x54 | 0xbb | 0x16 | 状态矩阵与其中的数据一一替换。 若a为0x52,替换后就是为第0x05行和0x02列 的数据:0x00; 若a为0x21,替换后就是为第0x02行和0x01列 的数据:0xfd。 ### 3.行移位 行移位:将状态S盒替换后的状态矩阵,第一行移一位、第二行移两位、第三行移三位。 ![](https://cf03.ickimg.com/bbsimages/201912/e45a6a5efa875a9ed9a384d9ccde09df.png) ### 4.列混合 列混合是用行移位后的状态矩阵,与一个固定矩阵相域乘 : ![](https://cf03.ickimg.com/bbsimages/201912/870b18a6ac8d13ba2a8aaa1ab3faeeff.png) 固定矩阵即是: | 02 | 03 | 01 | 01 | | ---- | ---- | ---- | ---- | | 01 | 02 | 03 | 01 | | 01 | 01 | 02 | 03 | | 03 | 01 | 01 | 02 | 得到新的状态矩阵即是: ![](https://cf03.ickimg.com/bbsimages/201912/bf0804c7f5b16cf0253270178081ac87.png) 其中算法就是用信息安全里面的域加和域乘 ![](https://cf03.ickimg.com/bbsimages/201912/0596f7bcef7bfbeebb0ae74809cd6b7f.png) ### 5.轮密钥加 #### 5.1密钥状态矩阵 轮密钥加首先也要生成一个密钥状态矩阵 ![](https://cf03.ickimg.com/bbsimages/201912/1048c225cbc609da5f7a96a21039188a.png) 设密钥K为”abcdefghijklmnop”,则K0 = ‘a’,K1 = ‘b’, K2 = ‘c’,K3 = ‘d’,W[0] = “abcd”。 设初始的128位密钥为:3C A1 0B 21 57 F0 19 16 90 2E 13 80 AC C1 07 BD T是一个有点复杂的函数。 函数T由3部分组成:字循环、字节代换和轮常量异或,这3部分的作用分别如下。 a.字循环:将1个字中的4个字节循环左移1个字节。即将输入字[b0, b1, b2, b3]变换成[b1,b2,b3,b0]。 b.字节代换:对字循环的结果使用S盒进行字节代换。 c.轮常量异或:将前两步的结果同轮常量Rcon[j]进行异或,其中j表示轮数。 轮常量Rcon[j]是一个字,其值见下表。 | j | 1 | 2 | 3 | 4 | 5 | | :------ | :---------- | :---------- | :---------- | :---------- | :---------- | | Rcon[j] | 01 00 00 00 | 02 00 00 00 | 04 00 00 00 | 08 00 00 00 | 10 00 00 00 | | j | 6 | 7 | 8 | 9 | 10 | | Rcon[j] | 20 00 00 00 | 40 00 00 00 | 80 00 00 00 | 1B 00 00 00 | 36 00 00 00 | 设初始的128位密钥为: 3C A1 0B 21 57 F0 19 16 90 2E 13 80 AC C1 07 BD 那么4个初始值为: W[0] = 3C A1 0B 21 W[1] = 57 F0 19 16 W[2] = 90 2E 13 80 W[3] = AC C1 07 BD 下面求扩展的第1轮的子密钥(W[4],W[5],W[6],W[7])。 由于4是4的倍数,所以: W[4] = W[0] ⨁ T(W[3]) T(W[3])的计算步骤如下: 设初始的128位密钥为: 3C A1 0B 21 57 F0 19 16 90 2E 13 80 AC C1 07 BD 那么4个初始值为: W[0] = 3C A1 0B 21 W[1] = 57 F0 19 16 W[2] = 90 2E 13 80 W[3] = AC C1 07 BD 下面求扩展的第1轮的子密钥(W[4],W[5],W[6],W[7])。 由于4是4的倍数,所以: W[4] = W[0] ⨁ T(W[3]) T(W[3])的计算步骤如下: 1. 循环地将W[3]的元素移位:AC C1 07 BD变成C1 07 BD AC; 2. 将 C1 07 BD AC 作为S盒的输入,输出为78 C5 7A 91; 3. 将78 C5 7A 91与第一轮轮常量Rcon[1]进行异或运算,将得到79 C5 7A 91,因此,T(W[3])=79 C5 7A 91,故 W[4] = 3C A1 0B 21 ⨁ 79 C5 7A 91 = 45 64 71 B0 4. 其余的3个子密钥段的计算如下: W[5] = W[1] ⨁ W[4] = 57 F0 19 16 ⨁ 45 64 71 B0 = 12 94 68 A6 W[6] = W[2] ⨁ W[5] =90 2E 13 80 ⨁ 12 94 68 A6 = 82 BA 7B 26 W[7] = W[3] ⨁ W[6] = AC C1 07 BD ⨁ 82 BA 7B 26 = 2E 7B 7C 9B 所以,第一轮的密钥为 45 64 71 B0 12 94 68 A6 82 BA 7B 26 2E 7B 7C 9B。 #### 5.2轮密钥加 轮密钥加即是:状态矩阵与密钥矩阵【域加】,这里不做多阐述之前已经讲过!即是两个字节相异或。 ## N个循环 AES的整体结构如下图所示,加密的第1轮到第9轮的轮函数一样,包括4个操作:字节代换、行位移、列混合和轮密钥加。最后一轮迭代不执行列混合。另外,在第一轮迭代之前,先将明文和原始密钥进行一次异或加密操作。 ![](https://cf03.ickimg.com/bbsimages/201912/38ed39ea9f51261c98ab8ce2441d8272.png) C语言代码应用: 最后,代码应用:包含了C和ESP32,同时包含lib方便stm32或其他单片机移植。 ```c #include <stdio.h> /@@*aes_small.c*/ //辅助矩阵 /@@*s盒矩阵:The AES Substitution Table*/// 256 位的密匙256 位支持长度为32 个字符 static const unsigned char sbox[256]={ //static:内部变量 const:只读,不可变常量 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 unsigned char contrary_sbox[256]={ 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,//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, }; /@@*轮常量表 The key schedule rcon table*/ static const unsigned char Rcon[10]={ 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36}; //辅助函数 /@@*有限域*2乘法 The x2time() function */ static unsigned char x2time(unsigned char x) { if (x&0x80) { return (((x<<1)^0x1B)&0xFF); } return x<<1; } /@@*有限域*3乘法 The x2time() function */ static unsigned char x3time(unsigned char x) { return (x2time(x)^x); } /@@*有限域*4乘法 The x4time() function */ static unsigned char x4time(unsigned char x) { return ( x2time(x2time(x)) ); } /@@*有限域*8乘法 The x8time() function */ static unsigned char x8time(unsigned char x) { return ( x2time(x2time(x2time(x))) ); } /@@*有限域9乘法 The x9time() function */ static unsigned char x9time(unsigned char x) //9:1001 { return ( x8time(x)^x ); } /@@*有限域*B乘法 The xBtime() function */ static unsigned char xBtime(unsigned char x) //B:1011 { return ( x8time(x)^x2time(x)^x ); } /@@*有限域*D乘法 The xDtime() function */ static unsigned char xDtime(unsigned char x) //D:1101 { return ( x8time(x)^x4time(x)^x ); } /@@*有限域*E乘法 The xEtime() function */ static unsigned char xEtime(unsigned char x) //E:1110 { return ( x8time(x)^x4time(x)^x2time(x) ); } /@@****************************************************************************************************************/ /@@*第三类操作:列混合操作 MixColumns: Process the entire block*/ static void MixColumns(unsigned char *col)//列混合 { unsigned char tmp[4],xt[4]; int i; for(i=0;i<4;i++,col+=4) //col代表一列的基地址,col+4:下一列的基地址 { /@@* xt[0]=x2time(col[0]); xt[1]=x2time(col[1]); xt[2]=x2time(col[2]); xt[3]=x2time(col[3]); //xt[n]代表*2 xt[n]^col[n]代表*3 col[n]代表*1 tmp[0]=(xt[0])^(xt[1]^col[1])^col[2]^col[3]; //2 3 1 1 tmp[1]=col[0]^(xt[1])^(xt[2]^col[2])^col[3]; //1 2 3 1 tmp[2]=col[0]^col[1]^(xt[2])^(xt[3]^col[3]); //1 1 2 3 tmp[3]=(xt[0]^col[0])^col[1]^col[2]^(xt[3]); //3 1 1 2 */ tmp[0]=x2time(col[0])^x3time(col[1])^col[2]^col[3]; //2 3 1 1 tmp[1]=col[0]^x2time(col[1])^x3time(col[2])^col[3]; //1 2 3 1 tmp[2]=col[0]^col[1]^x2time(col[2])^x3time(col[3]); //1 1 2 3 tmp[3]=x3time(col[0])^col[1]^col[2]^x2time(col[3]); //3 1 1 2 //修改后的值 直接在原矩阵上修改 col[0]=tmp[0]; col[1]=tmp[1]; col[2]=tmp[2]; col[3]=tmp[3]; } } //逆向列混淆 static void Contrary_MixColumns(unsigned char *col) { unsigned char tmp[4]; unsigned char xt2[4];//colx2 unsigned char xt4[4];//colx4 unsigned char xt8[4];//colx8 int x; for(x=0;x<4;x++,col+=4) { /@@* xt2[0]=x2time(col[0]); xt2[1]=x2time(col[1]); xt2[2]=x2time(col[2]); xt2[3]=x2time(col[3]); xt4[0]=x2time(xt2[0]); xt4[1]=x2time(xt2[1]); xt4[2]=x2time(xt2[2]); xt4[3]=x2time(xt2[3]); xt8[0]=x2time(xt4[0]); xt8[1]=x2time(xt4[1]); xt8[2]=x2time(xt4[2]); xt8[3]=x2time(xt4[3]); tmp[0]=xt8[0]^xt4[0]^xt2[0]^xt8[1]^xt2[1]^col[1]^xt8[2]^xt4[2]^col[2]^xt8[3]^col[3]; tmp[1]=xt8[0]^col[0]^xt8[1]^xt4[1]^xt2[1]^xt8[2]^xt2[2]^col[2]^xt8[3]^xt4[3]^col[3]; tmp[2]=xt8[0]^xt4[0]^col[0]^xt8[1]^col[1]^xt8[2]^xt4[2]^xt2[2]^xt8[3]^xt2[3]^col[3]; tmp[3]=xt8[0]^xt2[0]^col[0]^xt8[1]^xt4[1]^col[1]^xt8[2]^col[2]^xt8[3]^xt4[3]^xt2[3]; */ tmp[0]=xEtime(col[0])^xBtime(col[1])^xDtime(col[2])^x9time(col[3]); tmp[1]=x9time(col[0])^xEtime(col[1])^xBtime(col[2])^xDtime(col[3]); tmp[2]=xDtime(col[0])^x9time(col[1])^xEtime(col[2])^xBtime(col[3]); tmp[3]=xBtime(col[0])^xDtime(col[1])^x9time(col[2])^xEtime(col[3]); col[0]=tmp[0]; col[1]=tmp[1]; col[2]=tmp[2]; col[3]=tmp[3]; } } /@@*第二类操作:行移位:行左循环移位 ShiftRows:Shifts the entire block*/ static void ShiftRows(unsigned char *col)//正向行移位 { /@@* 1 5 9 13 5 9 13 1 2 6 10 14 10 14 2 6 3 7 11 15 15 3 7 11 4 8 12 16 16 4 8 12 */ unsigned char t; /@@*1nd row*///左移1位 t=col[1];col[1]=col[5];col[5]=col[9];col[9]=col[13];col[13]=t; /@@*2rd row*///左移2位,交换2次数字来实现 t=col[2];col[2]=col[10];col[10]=t; t=col[6];col[6]=col[14];col[14]=t; /@@*3th row*///左移3位,相当于右移1次 t=col[15];col[15]=col[11];col[11]=col[7];col[7]=col[3];col[3]=t; /@@*4th row*/ //第4行不移位 } //逆向行移位 static void Contrary_ShiftRows(unsigned char *col) { unsigned char t; /@@*1nd row*/ t=col[13];col[13]=col[9];col[9]=col[5];col[5]=col[1];col[1]=t; /@@*2rd row*/ t=col[2];col[2]=col[10];col[10]=t; t=col[6];col[6]=col[14];col[14]=t; /@@*3th row*/ t=col[3];col[3]=col[7];col[7]=col[11];col[11]=col[15];col[15]=t; /@@*4th row*/ //第4行不移位 } /@@*第一类操作:s盒字节代换替换 SubBytes*/ static void SubBytes(unsigned char *col)//字节代换 { int x; for(x=0;x<16;x++) { col[x]=sbox[col[x]]; } } //逆向字节代换 static void Contrary_SubBytes(unsigned char *col) { int x; for(x=0;x<16;x++) { col[x]=contrary_sbox[col[x]]; } } /@@*第四类操作:轮密钥加 AddRoundKey*/ static void AddRoundKey(unsigned char *col,unsigned char *expansionkey,int round)//密匙加 { //扩展密钥:44*32bit =11*4* 4*8 = 16字节*11轮,每轮用16字节密钥 //第0轮,只进行一次轮密钥加 //第1-10轮,轮密钥加 int x; for(x=0;x<16;x++) //每1轮操作:4*32bit密钥 = 16个字节密钥 { col[x]^=expansionkey[(round<<4)+x]; } } /@@* AES加密总函数 10轮4类操作 Encrypt a single block with Nr Rounds(10,12,14)*/ void AesEncrypt(unsigned char *blk,unsigned char *expansionkey,int Nr)//加密一个区块 { //输入blk原文,直接在上面修改,输出blk密文 //输入skey: //输入Nr = 10轮 int round; //第1轮之前:轮密钥加 AddRoundKey(blk,expansionkey,0); //第1-9轮:4类操作:字节代换、行移位、列混合、轮密钥加 for(round=1;round<=(Nr-1);round++) { SubBytes(blk); //输入16字节数组,直接在原数组上修改 ShiftRows(blk); //输入16字节数组,直接在原数组上修改 MixColumns(blk); //输入16字节数组,直接在原数组上修改 AddRoundKey(blk,expansionkey,round); } //第10轮:不进行列混合 SubBytes(blk); ShiftRows(blk); AddRoundKey(blk,expansionkey,Nr); } //AES 解密总函数 void Contrary_AesEncrypt(unsigned char *blk,unsigned char *expansionkey,int Nr) { int x; /@@* unsigned char *contrary_key=key; for(x=0;x<11;x++,key+=16) Contrary_MixColumns(key);*/ AddRoundKey(blk,expansionkey,Nr); Contrary_ShiftRows(blk); Contrary_SubBytes(blk); for(x=(Nr-1);x>=1;x--) { AddRoundKey(blk,expansionkey,x); Contrary_MixColumns(blk); Contrary_ShiftRows(blk); Contrary_SubBytes(blk); } AddRoundKey(blk,expansionkey,0); } /@@*//密钥编排,16字节--->44列32bit密钥生成--> 11组16字节:分别用于11轮 轮密钥加运算 Schedule a secret key for use. *outkey[] must be 16*15 bytes in size *Nk==number of 32 bit words in the key,e.g.,4,6,8 *Nr==number of rounds,e.g.,10,12,14 */ void ScheduleKey(unsigned char *inkey,unsigned char *outkey,int Nk,int Nr)//安排一个保密密钥使用 { //inkey:初始16字节密钥key //outkey:11组*16字节扩展密钥expansionkey //Nk:4列 //Nr:10轮round unsigned char temp[4],t; int x,i; /@@*copy the key*/ //第0组:[0-3]直接拷贝 for(i=0;i<(4*Nk);i++) { outkey[i]=inkey[i]; } //第1-10组:[4-43] i=Nk; while(i<(4*(Nr+1))) //i=4~43 WORD 32bit的首字节地址,每一个4字节 {//1次循环生成1个字节扩展密钥,4次循环生成一个WORD //temp:4字节数组:代表一个WORD密钥 /@@*temp=w[i-1]*/ //i不是4的倍数的时候 //每个temp = 每个outkey32bit = 4字节 for(x=0;x<4;x++) temp[x]=outkey[(4*(i-1))+x]; //i:32bit的首字节地址 //i是4的倍数的时候 if(i%Nk==0) { /@@*字循环:循环左移1字节 RotWord()*/ t=temp[0];temp[0]=temp[1];temp[1]=temp[2];temp[2]=temp[3];temp[3]=t; /@@*字节代换:SubWord()*/ for(x=0;x<4;x++) { temp[x]=sbox[temp[x]]; } /@@*轮常量异或:Rcon[j]*/ temp[0]^=Rcon[(i/Nk)-1]; } //else if(Nk>6 && (i%Nk)==4) //Nk>6的算法不同,暂时用不到 //{ // /@@*SubWord*/ // for(x=0;x<4;x++) // { // temp[x]=sbox[temp[x]]; // } //} /@@*w[i] = w[i-4]^w[i-1]*/ for(x=0;x<4;x++) { outkey[(4*i)+x]=outkey[(4*(i-Nk))+x]^temp[x]; } ++i; } } void user_encrypt(unsigned char * Buffer, unsigned char * key){ unsigned char expansionkey[15*16]; ScheduleKey(key,expansionkey,4,10); AesEncrypt(Buffer,expansionkey,10); } void user_decrypt(unsigned char * Buffer, unsigned char * key){ unsigned char expansionkey[15*16]; ScheduleKey(key,expansionkey,4,10); Contrary_AesEncrypt(Buffer,expansionkey,10);//AES 解密 } int main(void){ /@@* pt:原文16字节-->密文 key:原密钥16字节 skey:密钥扩展44long sbox:s盒 */ unsigned char pt[16]={ 0X01,0X02,0X03,0X04,0X05,0X06,0X07,0X08,0X09,0X0a,0X0b,0X0c,0X0d,0X0e,0X01,0x01}; unsigned char key[17]="1234567891234567"; unsigned char expansionkey[15*16]; int i; int j; printf("Original data is: "); //输出密码文件 for (i = 0; i < 16; i++) { printf("0x%02x ", pt[i]); } printf("\n"); printf("\n"); /@@*加密*/ user_encrypt(pt, key); printf("AesEncrypt data is: "); //输出密码文件 for (i = 0; i < 16; i++) { printf("0x%02x ", pt[i]); } printf("\n"); printf("\n"); /@@*解密*/ user_decrypt(pt,key); printf("Decrypt data is: ");//将解密文件输出 for (i = 0; i < 16; i++) { printf("0x%02x ", pt[i]); } printf("\n"); printf("\n"); while(1); return 0; } ```
原创作品,未经权利人授权禁止转载。详情见
转载须知
。
举报文章
点赞
(
0
)
爱笑的男孩
关注
评论
(0)
登录后可评论,请
登录
或
注册
相关文章推荐
MK-米客方德推出工业级存储卡
Beetle ESP32 C3 蓝牙数据收发
Beetle ESP32 C3 wifi联网获取实时天气信息
开箱测评Beetle ESP32-C3 (RISC-V芯片)模块
正点原子数控电源DP100测评
DP100试用评测-----开箱+初体验
Beetle ESP32 C3环境搭建
【花雕体验】16 使用Beetle ESP32 C3控制8X32位WS2812硬屏之二
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回
我要举报该内容理由
×
广告及垃圾信息
抄袭或未经授权
其它举报理由
请输入您举报的理由(50字以内)
取消
提交