找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

5405

积分

0

好友

696

主题
发表于 2 小时前 | 查看: 4| 回复: 0

上篇文章 介绍了 AES加密 的原理,本篇通过代码来进一步熟悉 AES 加密的具体过程。代码采用 C 语言编程,先通过纯 C 代码实现 AES 过程,再通过成熟的 OpenSSL 加密库提供的 AES 加密接口,对比验证纯 C 代码的结果,最后通过第三方网站的 AES 加密,进一步验证代码实现的加密结果是否一致。

1 纯C代码实现

1.1 一些常量

定义AES的密钥位数、加密的轮数、S-box表、轮常量表等。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

// AES常量定义
#define AES_BLOCK_SIZE 16
#define Nb 4  // 状态矩阵的列数(Number of columns in the block)
#define Nk 4  // 128位密钥的字数(Number of 32-bit words in the 128-bit key)
#define Nr 10 // 128位密钥的轮数(Number of rounds)

// 轮常量
static const uint32_t Rcon[10] = 
{
  0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
  0x20000000, 0x40000000, 0x80000000, 0x1b000000, 0x36000000
};

// S-box
static const uint8_t Sbox[256] = 
{
  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
};

1.2 密钥扩展

AES 的原始密钥(种子密钥)通过特定算法扩展为多轮子密钥(如 AES-128 需扩展为 11 个子密钥,包含初始密钥和 10 轮密钥)。

扩展过程是按列进行扩展,其计算过程主要分为两大类:

  • 列索引是4的倍数:计算过程稍复杂,过程包括:
    • 旋转字节
    • 字节代换(S-box查表)
    • 轮常量异或
    • 计算扩展密钥(i-4列的值与i-1列变换后的值,进行异或运算)
  • 列索引不是4的倍数:计算过程稍简单,只需要:
    • 计算扩展密钥(i-4列的值与i-1列,进行异或运算)

AES密钥扩展过程示意图

对应的代码如下:

// 密钥扩展:同步调整w数组访问顺序(w[字节序号][字序号])
static void KeyExpansion(uint8_t key[16], uint8_t w[4][Nb*(Nr+1)])
{
  int i, j;
  uint8_t temp[4];

  // 初始化种子密钥  
  for (i = 0; i < Nk; i++) 
      {
          for (j = 0; j < 4; j++) 
              {
                  w[j][i] = key[i*4 + j];
              }
          }

  printf("-------------------------------\n");
  printf("                  (0)(1)(2)(3)\n");
  for (i = 0; i < Nk; i++) 
      {
          // w[4][Nb*(Nr+1)按空间分布打印,最左侧的4x4数据,即0~4每行的列索引都是:0 1 2 3
          printf("[%s] [%d] %02X %02X %02X %02X\n", __func__, i/4, w[i][0], w[i][1], w[i][2], w[i][3]);        
      }

  // 扩展轮密钥(NK=4, Nb*(Nr+1) = 4×(10+1) = 44)
  for (i = Nk; i < Nb*(Nr+1); i++) 
      {
          // 先取前一列的数据
          for (j = 0; j < 4; j++) 
              {
                  temp[j] = w[j][i-1];
              }   

          // 列的编号是4的倍数
          if (i % Nk == 0) 
              {
                  printf("-------------------------------\n");
                  if (i == Nk)
                      {
                          printf("[%s] calc column:(%d) get data from column(%d): %02X %02X %02X %02X\n", __func__, Nk, i-1, temp[0], temp[1], temp[2], temp[3]);
                      }

                  // [1]旋转字节
                  uint8_t t = temp[0];
                  temp[0] = temp[1];
                  temp[1] = temp[2];
                  temp[2] = temp[3];
                  temp[3] = t;

                  if (i == Nk)
                      {
                          printf("[%s] calc column:(%d) step<1> after rotate: %02X %02X %02X %02X\n", __func__, Nk, temp[0], temp[1], temp[2], temp[3]);
                      }

                  // [2]字节代换(S-box查表)
                  for (j = 0; j < 4; j++) 
                      {
                          temp[j] = Sbox[temp[j]];
                      }

                  if (i == Nk)
                      {
                          printf("[%s] calc column:(%d) step<2> after S-box: %02X %02X %02X %02X\n", __func__, Nk, temp[0], temp[1], temp[2], temp[3]);
                      }

                  // [3]轮常量异或
                  temp[0] ^= (Rcon[i/Nk - 1] >> 24) & 0xff;
                  if (i == Nk)
                      {
                          printf("[%s] calc column:(%d) step<3> after Rcon: %02X %02X %02X %02X\n", __func__, Nk, temp[0], temp[1], temp[2], temp[3]);
                      }

              }

          // 计算扩展密钥
          for (j = 0; j < 4; j++) 
              {
                  w[j][i] = w[j][i - Nk] ^ temp[j];
              }

          if (i == Nk)
              {
                  printf("[%s] calc column:(%d) step<4> after XOR with cloumn(%d): %02X %02X %02X %02X\n", __func__, Nk, i - Nk, w[0][i], w[1][i], w[2][i], w[3][i]);
              }

          // 这里每次计算的是1列,每计算完4列后打印一下(i = 7,11,15,19,23,27,31,35,39,43)
          if (0 == (i+1) % 4)
              {
                  printf("                 (%d)(%d)(%d)(%d)\n", i-3, i-2, i-1, i);
                  // w[4][Nb*(Nr+1)按空间分布打印,从左起的第n块的4x4数据,0~4每行的列索引都是:n*4+0 n*4+1 n*4+2 n*4+3, 这里n=i/4
                  for (j = 0; j < 4; j++) 
                      {
                          printf("[%s] [%d] %02X %02X %02X %02X\n", __func__, 
                                  i/4, w[j][(i/4)*4 + 0], w[j][(i/4)*4 + 1], w[j][(i/4)*4 + 2], w[j][(i/4)*4 + 3]);
                      }
              }
      }

  //再次打印w[4][Nb*(Nr+1)]
  printf("-------------------------------\n");
  printf("key 0~4:\n");
  for (i = 0; i < 4; i++) 
      {
          printf("[%s] [%02X %02X %02X %02X] [%02X %02X %02X %02X] [%02X %02X %02X %02X] [%02X %02X %02X %02X] [%02X %02X %02X %02X]\n", 
                  __func__, w[i][0], w[i][1], w[i][2], w[i][3], w[i][4], w[i][5], w[i][6], w[i][7], w[i][8], w[i][9], w[i][10], w[i][11], 
                   w[i][12], w[i][13], w[i][14], w[i][15], w[i][16], w[i][17], w[i][18], w[i][19]);
      }
  printf("key 5~9:\n");
  for (i = 0; i < 4; i++) 
      {
          printf("[%s] [%02X %02X %02X %02X] [%02X %02X %02X %02X] [%02X %02X %02X %02X] [%02X %02X %02X %02X] [%02X %02X %02X %02X]\n", 
                  __func__, w[i][20], w[i][21], w[i][22], w[i][23], w[i][24], w[i][25], w[i][26], w[i][27], w[i][28], w[i][29], w[i][30], w[i][31], 
                   w[i][32], w[i][33], w[i][34], w[i][35], w[i][36], w[i][37], w[i][38], w[i][39]);
      }
}

为了便于观察密钥扩展的结果,在代码中对变换后的结果进行打印。

对上篇示例的密钥扩展的运行结果为:

  • 第0个是种子密钥
  • 第1个扩展密钥打印出每一步准换的中间结果
  • 后面的是2~10轮扩展密钥
  • 最后再统一打印出所有的扩展密钥
-------------------------------
                  (0)(1)(2)(3)
[KeyExpansion] [0] 55 74 64 C3
[KeyExpansion] [0] 2A A1 6C B1
[KeyExpansion] [0] E1 BB 4D 73
[KeyExpansion] [0] 84 1F 64 9C
-------------------------------
[KeyExpansion] calc column:(4) get data from column(3): C3 B1 73 9C
[KeyExpansion] calc column:(4) step<1> after rotate: B1 73 9C C3
[KeyExpansion] calc column:(4) step<2> after S-box: C8 8F DE 2E
[KeyExpansion] calc column:(4) step<3> after Rcon: C9 8F DE 2E
[KeyExpansion] calc column:(4) step<4> after XOR with cloumn(0): 9C A5 3F AA
                 (4)(5)(6)(7)
[KeyExpansion] [1] 9C E8 8C 4F
[KeyExpansion] [1] A5 04 68 D9
[KeyExpansion] [1] 3F 84 C9 BA
[KeyExpansion] [1] AA B5 D1 4D
-------------------------------
                 (8)(9)(10)(11)
[KeyExpansion] [2] AB 43 CF 80
[KeyExpansion] [2] 51 55 3D E4
[KeyExpansion] [2] DC 58 91 2B
[KeyExpansion] [2] 2E 9B 4A 07
-------------------------------
                 (12)(13)(14)(15)
[KeyExpansion] [3] C6 85 4A CA
[KeyExpansion] [3] A0 F5 C8 2C
[KeyExpansion] [3] 19 41 D0 FB
[KeyExpansion] [3] E3 78 32 35
-------------------------------
                 (16)(17)(18)(19)
[KeyExpansion] [4] BF 3A 70 BA
[KeyExpansion] [4] AF 5A 92 BE
[KeyExpansion] [4] 8F CE 1E E5
[KeyExpansion] [4] 97 EF DD E8
-------------------------------
                 (20)(21)(22)(23)
[KeyExpansion] [5] 01 3B 4B F1
[KeyExpansion] [5] 76 2C BE 00
[KeyExpansion] [5] 14 DA C4 21
[KeyExpansion] [5] 63 8C 51 B9
-------------------------------
                 (24)(25)(26)(27)
[KeyExpansion] [6] 42 79 32 C3
[KeyExpansion] [6] 8B A7 19 19
[KeyExpansion] [6] 42 98 5C 7D
[KeyExpansion] [6] C2 4E 1F A6
-------------------------------
                 (28)(29)(30)(31)
[KeyExpansion] [7] D6 AF 9D 5E
[KeyExpansion] [7] 74 D3 CA D3
[KeyExpansion] [7] 66 FE A2 DF
[KeyExpansion] [7] EC A2 BD 1B
-------------------------------
                 (32)(33)(34)(35)
[KeyExpansion] [8] 30 9F 02 5C
[KeyExpansion] [8] EA 39 F3 20
[KeyExpansion] [8] C9 37 95 4A
[KeyExpansion] [8] B4 16 AB B0
-------------------------------
                 (36)(37)(38)(39)
[KeyExpansion] [9] 9C 03 01 5D
[KeyExpansion] [9] 3C 05 F6 D6
[KeyExpansion] [9] 2E 19 8C C6
[KeyExpansion] [9] FE E8 43 F3
-------------------------------
                 (40)(41)(42)(43)
[KeyExpansion] [10] 5C 5F 5E 03
[KeyExpansion] [10] 88 8D 7B AD
[KeyExpansion] [10] 23 3A B6 70
[KeyExpansion] [10] B2 5A 19 EA
-------------------------------
key 0~4:
[KeyExpansion] [55 74 64 C3] [9C E8 8C 4F] [AB 43 CF 80] [C6 85 4A CA] [BF 3A 70 BA]
[KeyExpansion] [2A A1 6C B1] [A5 04 68 D9] [51 55 3D E4] [A0 F5 C8 2C] [AF 5A 92 BE]
[KeyExpansion] [E1 BB 4D 73] [3F 84 C9 BA] [DC 58 91 2B] [19 41 D0 FB] [8F CE 1E E5]
[KeyExpansion] [84 1F 64 9C] [AA B5 D1 4D] [2E 9B 4A 07] [E3 78 32 35] [97 EF DD E8]
key 5~9:
[KeyExpansion] [01 3B 4B F1] [42 79 32 C3] [D6 AF 9D 5E] [30 9F 02 5C] [9C 03 01 5D]
[KeyExpansion] [76 2C BE 00] [8B A7 19 19] [74 D3 CA D3] [EA 39 F3 20] [3C 05 F6 D6]
[KeyExpansion] [14 DA C4 21] [42 98 5C 7D] [66 FE A2 DF] [C9 37 95 4A] [2E 19 8C C6]
[KeyExpansion] [63 8C 51 B9] [C2 4E 1F A6] [EC A2 BD 1B] [B4 16 AB B0] [FE E8 43 F3]

1.3 变换过程

变换过程有4个:

  • 字节代换(SubBytes)
  • 行移位(ShiftRows)
  • 列混淆(MixColumns)
  • 轮密钥加(AddRoundKey)

AES的加密过程就是使用这4个变换来实现的:

AES加密算法流程

这4个过程分别封装成对应的函数。

1.3.1 字节代换

字节代换,就是使用S-box表进行映射。

S-box是一个固定的表格,16行x16列:

AES S-box表

在轮加密中,就是要对4x4矩阵中的每一个数据都进行S-box的映射替换:

// 字节代换
static void SubBytes(uint8_t state[4][4])
{
  int i, j;
  for (i = 0; i < 4; i++) 
      {
          for (j = 0; j < 4; j++) 
              {
                  state[i][j] = Sbox[state[i][j]];
              }
      }

  static int n=0;
  if (n++ == 0)
      {
          // 按按空间分布打印
          printf("           (0)(1)(2)(3)\n");
          for (i = 0; i < 4; i++) 
              {
                  printf("[%s] %02X %02X %02X %02X\n", __func__, state[i][0], state[i][1], state[i][2], state[i][3]);
              }  
      }
}

为了便于观察字节代换的结果,在代码中对变换后的结果进行打印,代码里 if (n++ == 0) 是为了只打印第1轮的轮密钥加的结果。

对上篇示例的第1轮的字节代换的运行结果为:

           (0)(1)(2)(3)
[SubBytes] 05 6F C9 A9
[SubBytes] 6E 64 01 1C
[SubBytes] 97 0E D0 F0
[SubBytes] F8 51 F0 D9

1.3.2 行移位

行移位,其过程可理解为:

  • 第1行数据不动
  • 第2行左移1位,然后左边多出的1位数据再移动到右边
  • 第3行左移2位,然后左边多出的2位数据再移动到右边
  • 第4行左移3位,然后左边多出的3位数据再移动到右边

AES轮函数字节代换与行移位过程

对应的代码如下:

// 行移位
static void ShiftRows(uint8_t state[4][4])
{
  uint8_t temp;

  // 第二行左移1位
  temp = state[1][0];
  state[1][0] = state[1][1];
  state[1][1] = state[1][2];
  state[1][2] = state[1][3];
  state[1][3] = temp;

  // 第三行左移2位
  temp = state[2][0];
  state[2][0] = state[2][2];
  state[2][2] = temp;
  temp = state[2][1];
  state[2][1] = state[2][3];
  state[2][3] = temp;

  // 第四行左移3位
  temp = state[3][0];
  state[3][0] = state[3][3];
  state[3][3] = state[3][2];
  state[3][2] = state[3][1];
  state[3][1] = temp;

  static int n=0;
  if (n++ == 0)
      {
          // 按按空间分布打印
          printf("           (0)(1)(2)(3)\n");
          for (int i = 0; i < 4; i++) 
              {
                  printf("[%s] %02X %02X %02X %02X\n", __func__, state[i][0], state[i][1], state[i][2], state[i][3]);
              }  
      }
}

为了便于观察行移位的结果,在代码中对变换后的结果进行打印,代码里 if (n++ == 0) 是为了只打印第1轮的轮密钥加的结果。

对上篇示例的第1轮的行移位的运行结果为:

           (0)(1)(2)(3)
[ShiftRows] 05 6F C9 A9
[ShiftRows] 64 01 1C 6E
[ShiftRows] D0 F0 97 0E
[ShiftRows] D9 F8 51 F0

1.3.3 列混淆

列混淆,是对4x4的数据再左乘一个列混淆的固定矩形。

列混淆的过程,和矩阵乘积运算是类似的,都是行列的数据先相乘再相加,不同点是:

  • 相乘的运算,是有限域(2的8次方内)的相乘
  • 相加的运算,替换为二进制的异或运算

列混淆矩阵乘法原理

有限域的相乘运算的具体过程如下:

  • 先转换为2进制进行计算
  • AES的列混淆,与加密数据相乘的数据只有1、2、3这3种情况
    • 与1相乘,不变
    • 与2相乘,如果数据最高位是0,乘2就是左移一位,仍在有限域内;如果最高位是1,左移1位后会溢出,需要再与0x1B(AES中规定的不可约多项式的16进制表示)异或
    • 与3相乘,先将3拆为1与2的异或,最终转换为先与2相乘,再与自身异或

下面的xtime函数实现了有限域GF(2^8)上的乘法(乘以2)

  • 通过对x左移1位(x<<1)实现乘2
  • 将x右移7位并与1进行与操作,判断最高位是否为1(((x >> 7) & 1
  • 如果最高位是1,需要再与0x1B进行异或
// 有限域GF(2^8)上的乘法(乘以2)
static uint8_t xtime(uint8_t x)
{
  return (x << 1) ^ (((x >> 7) & 1) * 0x1b);
}

列混淆的固定矩形中的数据,体现在MixColumns每一行的运算中,例如 state[0][i] = xtime(a) ^ (xtime(b) ^ b) ^ c ^ d; 对应的就是 2*a ^ 3*b ^ 1*c ^ 1^d,也就是列混淆矩阵第一行的 2 3 1 1

// 列混淆
static void MixColumns(uint8_t state[4][4])
{
  int i;
  uint8_t a, b, c, d;
  for (i = 0; i < 4; i++) 
      {
          a = state[0][i];
          b = state[1][i];
          c = state[2][i];
          d = state[3][i];

          state[0][i] = xtime(a) ^ (xtime(b) ^ b) ^ c ^ d;
          state[1][i] = a ^ xtime(b) ^ (xtime(c) ^ c) ^ d;
          state[2][i] = a ^ b ^ xtime(c) ^ (xtime(d) ^ d);
          state[3][i] = (xtime(a) ^ a) ^ b ^ c ^ xtime(d);
      }

  static int n=0;
  if (n++ == 0)
      {
          // 按按空间分布打印
          printf("           (0)(1)(2)(3)\n");
          for (i = 0; i < 4; i++) 
              {
                  printf("[%s] %02X %02X %02X %02X\n", __func__, state[i][0], state[i][1], state[i][2], state[i][3]);
              }  
      }
}

为了便于观察列混淆的结果,在代码中对变换后的结果进行打印,代码里 if (n++ == 0) 是为了只打印第1轮的轮密钥加的结果。

对上篇示例的第1轮的列混淆的运行结果为:

           (0)(1)(2)(3)
[MixColumns] AF D5 6B 05
[MixColumns] 7F 9E 02 97
[MixColumns] AA 86 13 D0
[MixColumns] 12 AB 69 7B

1.3.4 轮密钥加

轮密钥加的过程,是数据矩阵和密钥矩阵进行异或的过程。

轮密钥加操作示意图

C代码实现,异或操作是使用 ^ 运算符:

// 轮密钥加:同步调整w数组访问顺序(w[字节序号][字序号])
static void AddRoundKey(uint8_t state[4][4], uint8_t w[4][Nb*(Nr+1)], int round)
{
  int i, j;
  for (i = 0; i < 4; i++) 
      {
          for (j = 0; j < 4; j++) 
              {
                  state[i][j] ^= w[i][round*Nb + j];
              }
      }

  static int n=0;
  if (n++ == 1)
      {
          // 按按空间分布打印
          printf("           (0)(1)(2)(3)\n");
          for (i = 0; i < 4; i++) 
              {
                  printf("[%s] %02X %02X %02X %02X\n", __func__, state[i][0], state[i][1], state[i][2], state[i][3]);
              }  
      }
}

为了便于观察轮密钥加的结果,在代码中对变换后的结果进行打印,代码里 if (n++ == 1) 是为了只打印第1轮的轮密钥加的结果(因为初始变换时会先用到一次种子密钥加,所以这里不是判断的循环次数0)。

对上篇示例的第1轮的轮密钥加的运行结果为:

           (0)(1)(2)(3)
[SubBytes] 05 6F C9 A9
[SubBytes] 6E 64 01 1C
[SubBytes] 97 0E D0 F0
[SubBytes] F8 51 F0 D9

1.4 加密

AES的加密过程按顺序可梳理为:

  • 密钥扩展:将种子密钥扩展出10轮密钥
  • 对明文进行初始变换(种子密钥加)
  • 进行1~9轮的变换,每轮包括
    • 字节代码
    • 行移位
    • 类混淆
    • 轮密钥加(使用1~9轮的扩展密钥)
  • 进行最后1轮的变换,具体为:
    • 字节代码
    • 行移位
    • 轮密钥加(使用第10轮的扩展密钥)

AES加密算法流程

对一个数据块进行加密,对应的代码如下:

// AES单块加密:w数组定义改为[4][Nb*(Nr+1)]
static void aes_encrypt_block(uint8_t plaintext[16], uint8_t key[16], uint8_t ciphertext[16])
{
  uint8_t state[4][4];
  uint8_t w[4][Nb*(Nr+1)]; // 核心修改:维度改为4×(4×11)=4×44
  int i, j, round;

  // 打印明文
  for (i = 0; i < 4; i++) 
      {
          // plaintext[16]按列优先打印,即每行的索引:0 4 8 12; 1 5 9 13; 2 6 10 14; 3 7 11 15
          printf("[%s] plaintext[%d] %02X %02X %02X %02X\n", __func__, i, plaintext[i], plaintext[i + 1*4], plaintext[i + 2*4], plaintext[i + 3*4]);
      }

  // 密钥扩展
  KeyExpansion(key, w);

  // 初始化状态矩阵(列优先)
  for (i = 0; i < 4; i++) 
      {
          for (j = 0; j < 4; j++) 
              {
                  state[j][i] = plaintext[i*4 + j];
              }
      }

  for (i = 0; i < 4; i++) 
      {
          printf("[%s] init state[%d] %02X %02X %02X %02X\n", __func__, i, state[i][0], state[i][1], state[i][2], state[i][3]);
      }

  // 初始轮密钥加
  AddRoundKey(state, w, 0);
  printf("---------------------------------------------\n");
  for (i = 0; i < 4; i++) 
      {
          printf("[%s] first round key state[%d] %02X %02X %02X %02X\n", __func__, i, state[i][0], state[i][1], state[i][2], state[i][3]);
      }

  // 主加密循环
  for (round = 1; round < Nr; round++) 
      {
          SubBytes(state);
          ShiftRows(state);
          MixColumns(state);
          AddRoundKey(state, w, round);

          printf("---------------------------------------------\n");
          for (i = 0; i < 4; i++) 
              {
                  printf("[%s] round<%d> state[%d] %02X %02X %02X %02X\n", __func__, round, i, state[i][0], state[i][1], state[i][2], state[i][3]);
              }
      }

  // 最后一轮(无列混合)
  SubBytes(state);
  ShiftRows(state);
  AddRoundKey(state, w, Nr);
  printf("---------------------------------------------\n");
  for (i = 0; i < 4; i++) 
      {
          printf("[%s] last round state[%d] %02X %02X %02X %02X\n", __func__, i, state[i][0], state[i][1], state[i][2], state[i][3]);
      }
  printf("---------------------------------------------\n");

  // 从状态矩阵导出密文
  for (i = 0; i < 4; i++) 
      {
          for (j = 0; j < 4; j++) 
              {
                  ciphertext[i*4 + j] = state[j][i];
              }
          printf("[%s] ciphertext[%d] %02X %02X %02X %02X\n", __func__, i, ciphertext[i*4 + 0], ciphertext[i*4 + 1], ciphertext[i*4 + 2], ciphertext[i*4 + 3]);
      }
}

为便于观察结果,对中间过程增加打印。

对上篇示例的运行结果为:

[aes_encrypt_block] plaintext[0] 63 72 76 74
[aes_encrypt_block] plaintext[1] 6F 2D 65 75
[aes_encrypt_block] plaintext[2] 64 6C 2D 64
[aes_encrypt_block] plaintext[3] 65 6F 73 79

[aes_encrypt_block] init state[0] 63 72 76 74
[aes_encrypt_block] init state[1] 6F 2D 65 75
[aes_encrypt_block] init state[2] 64 6C 2D 64
[aes_encrypt_block] init state[3] 65 6F 73 79
---------------------------------------------
[aes_encrypt_block] first round key state[0] 36 06 12 B7
[aes_encrypt_block] first round key state[1] 45 8C 09 C4
[aes_encrypt_block] first round key state[2] 85 D7 60 17
[aes_encrypt_block] first round key state[3] E1 70 17 E5
---------------------------------------------
[aes_encrypt_block] round<1> state[0] 33 3D E7 4A
[aes_encrypt_block] round<1> state[1] DA 9A 6A 4E
[aes_encrypt_block] round<1> state[2] 95 02 DA 6A
[aes_encrypt_block] round<1> state[3] B8 1E B8 36
---------------------------------------------
[aes_encrypt_block] round<2> state[0] B7 65 D5 D5
[aes_encrypt_block] round<2> state[1] 05 1C FB 69
[aes_encrypt_block] round<2> state[2] 06 CD E8 F0
[aes_encrypt_block] round<2> state[3] 95 2A 0C 9E
---------------------------------------------
[aes_encrypt_block] round<3> state[0] A0 A8 D6 32
[aes_encrypt_block] round<3> state[1] 97 03 76 DB
[aes_encrypt_block] round<3> state[2] 1C 7E C0 EB
[aes_encrypt_block] round<3> state[3] 12 78 70 01
---------------------------------------------
[aes_encrypt_block] round<4> state[0] 2F CD 77 DD
[aes_encrypt_block] round<4> state[1] 10 01 0E C9
[aes_encrypt_block] round<4> state[2] FF BD AD 40
[aes_encrypt_block] round<4> state[3] 95 EA 9A 54
---------------------------------------------
[aes_encrypt_block] round<5> state[0] 1A 9F 57 EF
[aes_encrypt_block] round<5> state[1] 1F ED 57 78
[aes_encrypt_block] round<5> state[2] 2C A0 52 0D
[aes_encrypt_block] round<5> state[3] F5 A6 8B 3A
---------------------------------------------
[aes_encrypt_block] round<6> state[0] 62 08 0E E0
[aes_encrypt_block] round<6> state[1] 03 4E 96 5B
[aes_encrypt_block] round<6> state[2] 2E 9C 35 FE
[aes_encrypt_block] round<6> state[3] 71 63 77 86
---------------------------------------------
[aes_encrypt_block] round<7> state[0] 3A 7C 51 21
[aes_encrypt_block] round<7> state[1] 65 AD BB 48
[aes_encrypt_block] round<7> state[2] 18 CD 44 E6
[aes_encrypt_block] round<7> state[3] 38 84 BE 77
---------------------------------------------
[aes_encrypt_block] round<8> state[0] 61 13 BF 79
[aes_encrypt_block] round<8> state[1] 83 68 35 35
[aes_encrypt_block] round<8> state[2] EE C3 B6 72
[aes_encrypt_block] round<8> state[3] 50 4C 82 1B
---------------------------------------------
[aes_encrypt_block] round<9> state[0] 77 4B B1 38
[aes_encrypt_block] round<9> state[1] 24 DC 98 C2
[aes_encrypt_block] round<9> state[2] F2 87 39 F5
[aes_encrypt_block] round<9> state[3] 9A 1F B7 D6
---------------------------------------------
[aes_encrypt_block] last round state[0] A9 EC 96 04
[aes_encrypt_block] last round state[1] 0E CB 5E 9B
[aes_encrypt_block] last round state[2] 31 DC 3F 67
[aes_encrypt_block] last round state[3] 44 E2 D9 43
---------------------------------------------
[aes_encrypt_block] ciphertext[0] A9 0E 31 44
[aes_encrypt_block] ciphertext[1] EC CB DC E2
[aes_encrypt_block] ciphertext[2] 96 5E 3F D9
[aes_encrypt_block] ciphertext[3] 04 9B 67 43

因为明文可能不是16的整数被,需要对数据进行分块与补充,然后循环对每一块数据进行加密:

// AES-ECB模式加密(多块处理)
static void aes_encrypt_ecb(uint8_t *plaintext, int plaintext_len, uint8_t *key, uint8_t *ciphertext, int *ciphertext_len)
{
  int i, blocks;
  uint8_t block[AES_BLOCK_SIZE];

  *ciphertext_len = ((plaintext_len + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;

  for (i = 0, blocks = 0; i < plaintext_len; i += AES_BLOCK_SIZE, blocks++) 
      {
          memset(block, 0, AES_BLOCK_SIZE);
          int copy_len = (plaintext_len - i) < AES_BLOCK_SIZE ? (plaintext_len - i) : AES_BLOCK_SIZE;
          memcpy(block, plaintext + i, copy_len);

          // 最后一块不足16字节时填充(PKCS#7)
          if (i + AES_BLOCK_SIZE > plaintext_len) 
              {
                  int pad_len = AES_BLOCK_SIZE - copy_len;
                  memset(block + copy_len, pad_len, pad_len);
              }

          aes_encrypt_block(block, key, ciphertext + blocks * AES_BLOCK_SIZE);
      }
}

1.5 主函数

主函数如下,plaintext为要加密的明文,key是自定义的密钥,可以是16进制的形式,也可以是字符串的形式。

为了便于观察最终的加密结果,这里将最终的结果以16进制的形式打印出来。

// 二进制转十六进制
static void bin_to_hex(uint8_t *bin, int bin_len, char *hex)
{
  int i;
  for (i = 0; i < bin_len; i++) 
      {
          sprintf(hex + 2*i, "%02X", bin[i]);
      }
  hex[2*bin_len] = '\0';
}

int main()
{
  // 16字节明文
  uint8_t plaintext[] = "coder-love-study";
  // 128位密钥(二选一启用)
#if 1
  uint8_t key[] = {
      0x55, 0x2A, 0xE1, 0x84,
      0x74, 0xA1, 0xBB, 0x1F,
      0x64, 0x6C, 0x4D, 0x64,
      0xC3, 0xB1, 0x73, 0x9C
      };
#else
  uint8_t key[] = "0123456789abcdef";
#endif
  int plaintext_len = strlen((char *)plaintext);
  int ciphertext_len;

  // 计算密文内存大小
  int num_blocks = (plaintext_len + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE;
  int padded_length = num_blocks * AES_BLOCK_SIZE;
  uint8_t *ciphertext = malloc(padded_length);
  char *hex_ciphertext = malloc(2 * padded_length + 1);

  if (!ciphertext || !hex_ciphertext) 
      {
          fprintf(stderr, "内存分配失败\n");
          return 1;
      }

  // 执行ECB加密
  aes_encrypt_ecb(plaintext, plaintext_len, key, ciphertext, &ciphertext_len);

  // 转换为十六进制输出
  bin_to_hex(ciphertext, ciphertext_len, hex_ciphertext);
  printf("原始字符串: %s\n", plaintext);
  printf("AES加密后 (十六进制): %s\n", hex_ciphertext);

  // 释放内存
  free(ciphertext);
  free(hex_ciphertext);

  return 0;
}

对上篇示例的完整的运行结果为:

[aes_encrypt_block] plaintext[0] 63 72 76 74
[aes_encrypt_block] plaintext[1] 6F 2D 65 75
[aes_encrypt_block] plaintext[2] 64 6C 2D 64
[aes_encrypt_block] plaintext[3] 65 6F 73 79
-------------------------------
                  (0)(1)(2)(3)
[KeyExpansion] [0] 55 74 64 C3
[KeyExpansion] [0] 2A A1 6C B1
[KeyExpansion] [0] E1 BB 4D 73
[KeyExpansion] [0] 84 1F 64 9C
-------------------------------
[KeyExpansion] calc column:(4) get data from column(3): C3 B1 73 9C
[KeyExpansion] calc column:(4) step<1> after rotate: B1 73 9C C3
[KeyExpansion] calc column:(4) step<2> after S-box: C8 8F DE 2E
[KeyExpansion] calc column:(4) step<3> after Rcon: C9 8F DE 2E
[KeyExpansion] calc column:(4) step<4> after XOR with cloumn(0): 9C A5 3F AA
                 (4)(5)(6)(7)
[KeyExpansion] [1] 9C E8 8C 4F
[KeyExpansion] [1] A5 04 68 D9
[KeyExpansion] [1] 3F 84 C9 BA
[KeyExpansion] [1] AA B5 D1 4D
-------------------------------
                 (8)(9)(10)(11)
[KeyExpansion] [2] AB 43 CF 80
[KeyExpansion] [2] 51 55 3D E4
[KeyExpansion] [2] DC 58 91 2B
[KeyExpansion] [2] 2E 9B 4A 07
-------------------------------
                 (12)(13)(14)(15)
[KeyExpansion] [3] C6 85 4A CA
[KeyExpansion] [3] A0 F5 C8 2C
[KeyExpansion] [3] 19 41 D0 FB
[KeyExpansion] [3] E3 78 32 35
-------------------------------
                 (16)(17)(18)(19)
[KeyExpansion] [4] BF 3A 70 BA
[KeyExpansion] [4] AF 5A 92 BE
[KeyExpansion] [4] 8F CE 1E E5
[KeyExpansion] [4] 97 EF DD E8
-------------------------------
                 (20)(21)(22)(23)
[KeyExpansion] [5] 01 3B 4B F1
[KeyExpansion] [5] 76 2C BE 00
[KeyExpansion] [5] 14 DA C4 21
[KeyExpansion] [5] 63 8C 51 B9
-------------------------------
                 (24)(25)(26)(27)
[KeyExpansion] [6] 42 79 32 C3
[KeyExpansion] [6] 8B A7 19 19
[KeyExpansion] [6] 42 98 5C 7D
[KeyExpansion] [6] C2 4E 1F A6
-------------------------------
                 (28)(29)(30)(31)
[KeyExpansion] [7] D6 AF 9D 5E
[KeyExpansion] [7] 74 D3 CA D3
[KeyExpansion] [7] 66 FE A2 DF
[KeyExpansion] [7] EC A2 BD 1B
-------------------------------
                 (32)(33)(34)(35)
[KeyExpansion] [8] 30 9F 02 5C
[KeyExpansion] [8] EA 39 F3 20
[KeyExpansion] [8] C9 37 95 4A
[KeyExpansion] [8] B4 16 AB B0
-------------------------------
                 (36)(37)(38)(39)
[KeyExpansion] [9] 9C 03 01 5D
[KeyExpansion] [9] 3C 05 F6 D6
[KeyExpansion] [9] 2E 19 8C C6
[KeyExpansion] [9] FE E8 43 F3
-------------------------------
                 (40)(41)(42)(43)
[KeyExpansion] [10] 5C 5F 5E 03
[KeyExpansion] [10] 88 8D 7B AD
[KeyExpansion] [10] 23 3A B6 70
[KeyExpansion] [10] B2 5A 19 EA
-------------------------------
key 0~4:
[KeyExpansion] [55 74 64 C3] [9C E8 8C 4F] [AB 43 CF 80] [C6 85 4A CA] [BF 3A 70 BA]
[KeyExpansion] [2A A1 6C B1] [A5 04 68 D9] [51 55 3D E4] [A0 F5 C8 2C] [AF 5A 92 BE]
[KeyExpansion] [E1 BB 4D 73] [3F 84 C9 BA] [DC 58 91 2B] [19 41 D0 FB] [8F CE 1E E5]
[KeyExpansion] [84 1F 64 9C] [AA B5 D1 4D] [2E 9B 4A 07] [E3 78 32 35] [97 EF DD E8]
key 5~9:
[KeyExpansion] [01 3B 4B F1] [42 79 32 C3] [D6 AF 9D 5E] [30 9F 02 5C] [9C 03 01 5D]
[KeyExpansion] [76 2C BE 00] [8B A7 19 19] [74 D3 CA D3] [EA 39 F3 20] [3C 05 F6 D6]
[KeyExpansion] [14 DA C4 21] [42 98 5C 7D] [66 FE A2 DF] [C9 37 95 4A] [2E 19 8C C6]
[KeyExpansion] [63 8C 51 B9] [C2 4E 1F A6] [EC A2 BD 1B] [B4 16 AB B0] [FE E8 43 F3]
[aes_encrypt_block] init state[0] 63 72 76 74
[aes_encrypt_block] init state[1] 6F 2D 65 75
[aes_encrypt_block] init state[2] 64 6C 2D 64
[aes_encrypt_block] init state[3] 65 6F 73 79
---------------------------------------------
[aes_encrypt_block] first round key state[0] 36 06 12 B7
[aes_encrypt_block] first round key state[1] 45 8C 09 C4
[aes_encrypt_block] first round key state[2] 85 D7 60 17
[aes_encrypt_block] first round key state[3] E1 70 17 E5
           (0)(1)(2)(3)
[SubBytes] 05 6F C9 A9
[SubBytes] 6E 64 01 1C
[SubBytes] 97 0E D0 F0
[SubBytes] F8 51 F0 D9
           (0)(1)(2)(3)
[ShiftRows] 05 6F C9 A9
[ShiftRows] 64 01 1C 6E
[ShiftRows] D0 F0 97 0E
[ShiftRows] D9 F8 51 F0
           (0)(1)(2)(3)
[MixColumns] AF D5 6B 05
[MixColumns] 7F 9E 02 97
[MixColumns] AA 86 13 D0
[MixColumns] 12 AB 69 7B
           (0)(1)(2)(3)
[AddRoundKey] 33 3D E7 4A
[AddRoundKey] DA 9A 6A 4E
[AddRoundKey] 95 02 DA 6A
[AddRoundKey] B8 1E B8 36
---------------------------------------------
[aes_encrypt_block] round<1> state[0] 33 3D E7 4A
[aes_encrypt_block] round<1> state[1] DA 9A 6A 4E
[aes_encrypt_block] round<1> state[2] 95 02 DA 6A
[aes_encrypt_block] round<1> state[3] B8 1E B8 36
---------------------------------------------
[aes_encrypt_block] round<2> state[0] B7 65 D5 D5
[aes_encrypt_block] round<2> state[1] 05 1C FB 69
[aes_encrypt_block] round<2> state[2] 06 CD E8 F0
[aes_encrypt_block] round<2> state[3] 95 2A 0C 9E
---------------------------------------------
[aes_encrypt_block] round<3> state[0] A0 A8 D6 32
[aes_encrypt_block] round<3> state[1] 97 03 76 DB
[aes_encrypt_block] round<3> state[2] 1C 7E C0 EB
[aes_encrypt_block] round<3> state[3] 12 78 70 01
---------------------------------------------
[aes_encrypt_block] round<4> state[0] 2F CD 77 DD
[aes_encrypt_block] round<4> state[1] 10 01 0E C9
[aes_encrypt_block] round<4> state[2] FF BD AD 40
[aes_encrypt_block] round<4> state[3] 95 EA 9A 54
---------------------------------------------
[aes_encrypt_block] round<5> state[0] 1A 9F 57 EF
[aes_encrypt_block] round<5> state[1] 1F ED 57 78
[aes_encrypt_block] round<5> state[2] 2C A0 52 0D
[aes_encrypt_block] round<5> state[3] F5 A6 8B 3A
---------------------------------------------
[aes_encrypt_block] round<6> state[0] 62 08 0E E0
[aes_encrypt_block] round<6> state[1] 03 4E 96 5B
[aes_encrypt_block] round<6> state[2] 2E 9C 35 FE
[aes_encrypt_block] round<6> state[3] 71 63 77 86
---------------------------------------------
[aes_encrypt_block] round<7> state[0] 3A 7C 51 21
[aes_encrypt_block] round<7> state[1] 65 AD BB 48
[aes_encrypt_block] round<7> state[2] 18 CD 44 E6
[aes_encrypt_block] round<7> state[3] 38 84 BE 77
---------------------------------------------
[aes_encrypt_block] round<8> state[0] 61 13 BF 79
[aes_encrypt_block] round<8> state[1] 83 68 35 35
[aes_encrypt_block] round<8> state[2] EE C3 B6 72
[aes_encrypt_block] round<8> state[3] 50 4C 82 1B
---------------------------------------------
[aes_encrypt_block] round<9> state[0] 77 4B B1 38
[aes_encrypt_block] round<9> state[1] 24 DC 98 C2
[aes_encrypt_block] round<9> state[2] F2 87 39 F5
[aes_encrypt_block] round<9> state[3] 9A 1F B7 D6
---------------------------------------------
[aes_encrypt_block] last round state[0] A9 EC 96 04
[aes_encrypt_block] last round state[1] 0E CB 5E 9B
[aes_encrypt_block] last round state[2] 31 DC 3F 67
[aes_encrypt_block] last round state[3] 44 E2 D9 43
---------------------------------------------
[aes_encrypt_block] ciphertext[0] A9 0E 31 44
[aes_encrypt_block] ciphertext[1] EC CB DC E2
[aes_encrypt_block] ciphertext[2] 96 5E 3F D9
[aes_encrypt_block] ciphertext[3] 04 9B 67 43
原始字符串: coder-love-study
AES加密后 (十六进制): A90E3144ECCBDCE2965E3FD9049B6743

上述对“coder-love-study”加密使用密钥是代码中自定义的16进制的密钥,也就是上篇文章中的示例。

如果是使用字符串密钥"0123456789abcdef",运行结果为:

原始字符串: coder-love-study
AES加密后 (十六进制): AC6DB039F1930CD6D291766FB35886CB

2 openssl库验证

2.1 API函数

2.1.1 AES_set_encrypt_key

AES_set_encrypt_key 是 OpenSSL 库中用于设置 AES 加密密钥的函数,主要作用是将用户提供的原始密钥(明文密钥)扩展为 AES 加密所需的轮密钥(Round Keys),供后续的加密操作使用。函数原型为:

int AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);

参数:

  • userKey:指向用户提供的原始密钥数据的指针(字节数组)
  • bits:密钥的长度(以比特为单位),必须是 AES 支持的密钥长度:128192256
  • key:指向 AES_KEY 结构体的指针,用于存储扩展后的轮密钥(输出参数)

返回值:

  • 成功时返回 0
  • 失败时返回非 0(通常是因为密钥长度 bits 不合法,如不是 128/192/256)

2.1.2 AES_ecb_encrypt

AES_ecb_encrypt 是 OpenSSL 库中用于执行 AES 加密或解密的函数,采用 ECB(电子密码本)模式。ECB 是 AES 最简单的分组密码模式。

void AES_ecb_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key, const int enc);

参数:

  • in:指向输入数据的指针(字节数组)。AES 处理固定长度的分组(128 位,即 16 字节),因此 in 必须指向一个 16 字节的缓冲区
  • out:指向输出数据的指针(字节数组),用于存储加密 / 解密后的结果,同样需要预先分配 16 字节的空间
  • key:指向 AES_KEY 结构体的指针,该结构体需提前通过 AES_set_encrypt_key(加密)或 AES_set_decrypt_key(解密)初始化,包含扩展后的轮密钥
  • enc:操作模式标志:
    • AES_ENCRYPT:执行加密操作
    • AES_DECRYPT:执行解密操作

2.2 代码实现

2.2.1 AES加密

主要就是调用两个API接口

  • AES_set_encrypt_key:输入种子密钥得到扩展密钥
  • AES_ecb_encrypt:对分块的数据进行加密
// AES-ECB加密函数
int aes_encrypt_ecb(const unsigned char *plaintext, size_t plaintext_len, 
                    const unsigned char *key, size_t key_len,
                    unsigned char **ciphertext, size_t *ciphertext_len)
{
  // 分配密文内存
  *ciphertext_len = plaintext_len;
  *ciphertext = (unsigned char *)malloc(*ciphertext_len);

  // 设置秘钥
  AES_KEY aes_key;
  if (AES_set_encrypt_key(key, key_len * 8, &aes_key) < 0) 
      {
          fprintf(stderr, "无法设置加密密钥\n");
          free(*ciphertext);
          *ciphertext = NULL;
          return -1;
      }

  // 分块加密
  for (size_t i = 0; i < plaintext_len; i += AES_BLOCK_SIZE) 
      {
          AES_ecb_encrypt(plaintext + i, *ciphertext + i, &aes_key, AES_ENCRYPT);
      }

  return 0;
}

2.2.2 填充函数

明文数据长度若不是16的倍数,需要进行数据填充

// 自定义填充函数 - 仅当长度不是16的倍数时填充
int custom_pad(const unsigned char *data, size_t data_len, size_t block_size, 
               unsigned char **padded_data, size_t *padded_len)
{
  // 计算填充长度
  size_t pad_len = (data_len % block_size == 0) ? 0 : (block_size - (data_len % block_size));
  *padded_len = data_len + pad_len;

  // 分配内存
  *padded_data = (unsigned char *)malloc(*padded_len);

  // 复制原始数据并添加填充
  memcpy(*padded_data, data, data_len);
  if (pad_len > 0) 
      {
          memset(*padded_data + data_len, (int)pad_len, pad_len);
      }

  return 0;
}

2.2.3 主函数

// gcc test4.c -o test4 -lcrypto
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/aes.h>

// 二进制转十六进制
int bin_to_hex(const unsigned char *bin, size_t bin_len, char **hex)
{
  if (!bin || !hex) 
      {
          fprintf(stderr, "bin_to_hex: 无效参数\n");
          return -1;
      }

  // 计算所需缓冲区大小
  size_t hex_len = bin_len * 2 + 1;
  *hex = (char *)malloc(hex_len);
  if (!*hex) 
      {
          fprintf(stderr, "bin_to_hex: 内存分配失败\n");
          return -1;
      }

  for (size_t i = 0; i < bin_len; i++) 
      {
          snprintf(*hex + 2*i, 3, "%02x", bin[i]);
      }
  (*hex)[bin_len * 2] = '\0';

  return 0;
}

int main()
{
  // 16字节明文示例(与纯C实现保持一致)
  const unsigned char plaintext[] = "coder-love-study"; // 正好16字节 
  // 128位密钥 (任意16字节十六进制密钥)
  const unsigned char key[] = {
      0x55, 0x2A, 0xE1, 0x84,
      0x74, 0xA1, 0xBB, 0x1F,
      0x64, 0x6C, 0x4D, 0x64,
      0xC3, 0xB1, 0x73, 0x9C
      };

  const size_t key_len = sizeof(key);

  // 初始化变量
  size_t plaintext_len = strlen((const char *)plaintext);
  unsigned char *padded_plaintext = NULL;
  size_t padded_len = 0;
  unsigned char *ciphertext = NULL;
  size_t ciphertext_len = 0;
  char *hex_ciphertext = NULL;

  printf("原始字符串: %s\n", plaintext);
  printf("原始长度: %zu 字节\n", plaintext_len);

  // 自定义填充 - 16字节时不额外填充
  custom_pad(plaintext, plaintext_len, AES_BLOCK_SIZE, &padded_plaintext, &padded_len);
  printf("处理后长度: %zu 字节\n", padded_len);

  // 执行加密
  aes_encrypt_ecb(padded_plaintext, padded_len, key, key_len, &ciphertext, &ciphertext_len);

  // 转换为十六进制
  bin_to_hex(ciphertext, ciphertext_len, &hex_ciphertext);

  // 输出结果
  printf("加密结果: %s\n", hex_ciphertext);

cleanup:
  // 释放内存
  free(padded_plaintext);
  free(ciphertext);
  free(hex_ciphertext);

  return 0;
}

运行结果:

原始字符串: coder-love-study
原始长度: 16 字节
处理后长度: 16 字节
加密结果: a90e3144eccbdce2965e3fd9049b6743

可以看到,使用openssl库的AES加密的API接口进行加密结果,与纯C代码实现的加密,结果是一样的。

3 第三方加密网站验证

找了一个第三方的加密工具

https://tool.lvtao.net/aes

这里密钥只能输入字符串,不能按16进制输入,那就验证一下纯C代码中使用"0123456789abcdef"密钥对“coder-love-study”进行加密

在线AES加密解密工具验证结果

可以看到,最终的加密结果,和上面纯C代码的加密结果是一样的。

4 总结

本篇介绍了AES加密的具体代码实现过程,包括纯C代码实现AES加密,以及使用openssl库的API接口实现AES加密,最后通过第3方工具的加密结果,验证代码的加密结果的正确性。如果你对加密算法或 C 语言实战有更多疑问,欢迎常来 云栈社区 交流探讨。




上一篇:嵌入式C语言手写Key-Value数据库:二进制文件存储与CRUD实战
下一篇:C语言cJSON实战:读写JSON文件与动态修改字段
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-8-3 05:19 , Processed in 1.311058 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表