AES(Advanced Encryption Standard,高级加密标准)是一种对称加密算法,由美国国家标准与技术研究院(NIST)于2001年正式确立。作为DES(数据加密标准)的替代方案,AES具有更高的安全性和效率,现已成为全球广泛使用的加密标准。

AES算法常被用于数据加密传输与个人数据保密。有很多加密工具使用的就是AES-256,比如AES 加密/解密 - 锤子在线工具(在线加解密)和UltrAES - 高性能AES-256文件加密工具(由个人开发的开源加密小工具)。

一、AES算法概述

1.加密模式

AES支持多种加密模式,包括EBC,CFB、OFB和CBC,第一种和后三种的本质区别在于有无初始向量(IV),EBC作为最基本的加密方式,没有使用向量,所以也是最脆弱且容易破解的一种。后三者在加密过程中使用了IV向量,使得加密后的数据更难以破解,能有效防止数据遭窃取和攻击。

2.密钥长度

AES-CBC根据密钥长度,对应不同的加密轮数。参数对应如下:

算法名称密钥长度分组大小初始向量(IV)长度加密轮数
AES-128128位(16字节)128位(16字节)128位(16字节)10轮
AES-192192位(24字节)128位(16字节)128位(16字节)12轮
AES-256256位(32字节)128位(16字节)128位(16字节)14轮

可以很明显地看出,只有密钥长度和加密轮数发生了变化,其余的参数不变。密钥长度越长,加密轮数越多,加密强度就越高,也越安全,但随之而来的代价是更长的加解密时间和更大的算力消耗(测试数据见下一节:性能对比)。

3.性能对比

不同的算法会有不同的性能表现。本人在Intel Core i7-1165G7处理器环境下测试了三种算法,数据如下:

算法密钥长度加密速度(MB/S)
AES-128128位(16字节)约350
AES-256256位(32字节)约285
3DES168位(21字节)约45

可以看出AES确实要比DES快许多;而且随着密钥长度增加和安全性增高,速度有一定下降幅度。

二、详细原理

讲完大致,就要到底层逻辑原理了(数学不好慎入)。废话不多说,直接上硬菜!

1.大致步骤

AES加密算法大致分为以下步骤:

  1. 密钥扩展(Key Expansion):将原始密钥根据加密轮数生成多个轮密钥,比如AES-256,将32位的原始密钥,根据轮数14,生成14个轮密钥,每个轮密钥128位。
  2. 初始轮(Initial Round):仅执行AddRoundKey操作。
  3. 主轮(Main Rounds):重复执行SubBytes、ShiftRows、MixColumns、AddRoundKey(共13轮)。
  4. 最终轮(Final Round):执行SubBytes、ShiftRows、AddRoundKey(省略MixColumns)。

输入数据被组织为4×4字节矩阵(称为状态矩阵),每个元素是8位字节。加密在有限域GF(2^8)上进行,使用不可约多项式$m(x) = x^8 + x^4 + x^3 + x + 1$

2.底层逻辑

(1) 密钥扩展

密钥扩展将256位密钥扩展为14个128位轮密钥。过程涉及:

  • 将密钥分成8个32位字($w_0$$w_7$)。
  • 使用递归函数生成后续字:
    • 对于$i \geq 8$,计算$w_i = w_{i-8} \oplus g(w_{i-1}, i)$,其中$g$是变换函数。
    • $g$函数包括字节循环移位、S盒替换(SubBytes)和轮常量异或。
    • 轮常量$Rcon[i]$定义为$Rcon[i] = (RC[i], 0, 0, 0)$,其中$RC[i]$$GF(2^8)$中的元素:  RC[i] = x^{i-1} \mod m(x) 例如,RC[1] = 1$RC[2] = x$
(2) 加密轮次操作

每个轮次对状态矩阵执行以下操作(状态矩阵元素记为$a_{i,j}$$0 \leq i,j \leq 3$)。

  • SubBytes(字节替换): 每个字节通过S盒(Substitution Box)非线性替换。S盒基于$GF(2^8)$上的逆运算和仿射变换:

    • 计算字节$b$的乘法逆元$b^{-1}$$GF(2^8)$中。
    • 应用仿射变换:$b' = M \cdot b^{-1} \oplus c$,其中$M$是固定矩阵,$c$是常量。
    • 例如,输入字节$x$,输出$y$满足:  y = S(x) \quad  这增加了混淆性。
  • ShiftRows(行移位): 每行字节循环左移:

    • 第0行不移位。
    • 第1行左移1字节。
    • 第2行左移2字节。
    • 第3行左移3字节。 数学上,新状态$a'{i,j} = a{i, (j + i) \mod 4}$
  • MixColumns(列混淆): 每列视为$GF(2^8)$上的多项式,乘以固定多项式$c(x) = 03x^3 + 01x^2 + 01x + 02$(系数为十六进制)。 其中乘法在$GF(2^8)$中定义,例如$02 \cdot a$等价于$a$左移后异或(如果溢出)。

  • AddRoundKey(轮密钥加): 状态矩阵与轮密钥异或: b_{i,j} = a_{i,j} \oplus k_{i,j} 其中$k_{i,j}$是当前轮密钥的对应字节。

(3) 轮次执行流程
  • 初始轮:仅AddRoundKey(使用第一个轮密钥)。
  • 主轮(1-13轮):依次执行SubBytes → ShiftRows → MixColumns → AddRoundKey。
  • 最终轮(第14轮):执行SubBytes → ShiftRows → AddRoundKey(无MixColumns)。
(4) 数学基础

AES操作在有限域$GF(2^8)$上:

  • 元素表示为字节(8位),例如$b = b_7x^7 + b_6x^6 + \cdots + b_0$
  • 加法和减法等价于异或($\oplus$)。
  • 乘法定义为多项式乘法模$m(x)$:  (a \cdot b) \mod m(x) 其中$m(x) = x^8 + x^4 + x^3 + x + 1$
(5) 解密原理

解密是加密的逆过程:

  • 逆操作:InvSubBytes、InvShiftRows、InvMixColumns。
  • 轮密钥顺序反转。
  • 数学上,InvMixColumns使用逆多项式$d(x) = 0Bx^3 + 0Dx^2 + 09x + 0E$

三、代码实现

讲完了算法和原理,就该用代码实现了。

1. Python加密库

Python并没有直接提供加密库,而直接通过底层逻辑实现又太麻烦了。在这里,我们使用Crypto作为实现基础。pip安装:

官方源(前提pip没有换过源):

pip install pycryptodome

清华源(首选):

pip install pycryptodome -i https://pypi.tuna.tsinghua.edu.cn/simple

注意:安装时用的名字是pycryptodome,不是导包用的Crypto!

出现"Successfuly installed pycryptodome"字样代表安装成功,如下图所示:

安装后,在Python Shell中导包测试:

import Crypto

没有报错则代表安装成功:

2.Python代码实现

以AES-256,mode-CBC为例,根据AES加密的步骤,写出如下函数:

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes

def encrypt_file(input_path, output_path, key):
    """加密大文件"""
    iv = get_random_bytes(AES.block_size) #随机iv
    cipher = AES.new(key, AES.MODE_CBC, iv)
    
    with open(input_path, 'rb') as fin, open(output_path, 'wb') as fout:
        fout.write(iv)  # 写入IV
        
        prev_chunk = None
        while True:
            chunk = fin.read(64 * 1024)  # 每次读取64KB
            if not chunk:
                break
            if prev_chunk is not None:
                fout.write(cipher.encrypt(prev_chunk))
            prev_chunk = chunk
        # 处理最后一个chunk并进行填充
        if prev_chunk is not None:
            padded_chunk = pad(prev_chunk, AES.block_size)
            fout.write(cipher.encrypt(padded_chunk))

def decrypt_file(input_path, output_path, key):
    """解密大文件"""
    with open(input_path, 'rb') as fin:
        iv = fin.read(AES.block_size) #提取iv
        cipher = AES.new(key, AES.MODE_CBC, iv)
        
        with open(output_path, 'wb') as fout:
            buffer = b''
            while True:
                chunk = fin.read(64 * 1024)
                if not chunk:
                    break
                decrypted = cipher.decrypt(chunk)
                buffer += decrypted
                # 写入除最后一个块外的所有完整块
                if len(buffer) > AES.block_size:
                    num_blocks = (len(buffer) - 1) // AES.block_size
                    write_bytes = num_blocks * AES.block_size
                    fout.write(buffer[:write_bytes])
                    buffer = buffer[write_bytes:]
            # 处理最后一个块并去除填充
            unpadded = unpad(buffer, AES.block_size)
            fout.write(unpadded)

encrypt_file是加密函数,decrypt_file是解密函数,两个函数都有三个参数:input_path,output_path,key;input_path是输入文件,output_path是输出文件,key是作为密钥的字节,为bytes类型。

密钥长度必须是32字节,可以通过Crypto.Random中的get_random_bytes函数实现:

key = get_random_bytes(32)

这个函数有一个参数,是生成的字节数,返回生成的随机字节。在加解密时使用:

#生成密钥
key = get_random_bytes(32)

#创建测试文件
with open("test.txt", "w") as file:
    file.write("中国智造,慧及全球!\n")
    file.write("A second line.")


#加密文件
encrypt_file("test.txt", "encrypted.bin", key)

#解密文件
decrypt_file("encrypted.bin", "decrypted.txt", key)

#解密测试
with open("decrypted.txt") as file:
    text = file.read()
    print(text)

测试结果:

测试后的目录:

出现相同结果代表成功。但是我们没办法保存生成的随机字节,这就意味着不能成功解密。所以,我们可以把密钥写入一个文件当中,方便解密。

加密时,先生成随机字节,然后写入文件:

#生成随机字节
key = get_random_bytes(32)

#写入文件
with open("key.bin", "wb") as file:
    file.write(key)

解密时,从文件读取:

#从文件读取密钥
with open("key.bin", "rb") as file:
    key = file.read()

所以,修改测试代码如下:

#生成密钥
key = get_random_bytes(32)

#写入密钥到文件
with open("key.bin", "wb") as file:
    file.write(key)

#创建测试文件
with open("test.txt", "w") as file:
    file.write("中国智造,慧及全球!\n")
    file.write("A second line.")


#加密文件
encrypt_file("test.txt", "encrypted.bin", key)

#读取密钥
with open("key.bin", "rb") as file:
    key_read = file.read()

#解密文件
decrypt_file("encrypted.bin", "decrypted.txt", key_read)

#解密测试
with open("decrypted.txt") as file:
    text = file.read()
    print(text)

得到同样的结果。

3.C++代码实现

本文中的AES实现可在Windows平台上使用AES-NI,其他平台可使用正常处理,建议在VC++中编译:
AES.h:
 

// AES.h
// Copyright (c) 2025 - 2026 金煜力
// AES-256 (CBC/ECB/CTR) 加密

#pragma once

#include <vector>
#include <cstdint>
#include <string>

// 缓冲区处理函数
struct AES_ctx;

// AES上下文初始化
void AES_init_ctx(AES_ctx* ctx, const uint8_t* key);
void AES_init_ctx_iv(AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
void AES_ctx_set_iv(AES_ctx* ctx, const uint8_t* iv);

// ECB模式
void AES_ECB_encrypt(const AES_ctx* ctx, uint8_t* buf);
void AES_ECB_decrypt(const AES_ctx* ctx, uint8_t* buf);

// CBC模式
void AES_CBC_encrypt_buffer(AES_ctx* ctx, uint8_t* buf, size_t length);
void AES_CBC_decrypt_buffer(AES_ctx* ctx, uint8_t* buf, size_t length);

// CTR模式
void AES_CTR_xcrypt_buffer(AES_ctx* ctx, uint8_t* buf, size_t length);

// 辅助函数
std::vector<uint8_t> generate_aes256_key();
void generate_secure_random(uint8_t* buffer, size_t size);

// PKCS7填充
void pkcs7_pad(std::vector<uint8_t>& data);
bool pkcs7_unpad(std::vector<uint8_t>& data);

AES.cpp:
 

// AES.cpp
// Copyright (c) 2025 - 2026 金煜力
// AES-256 (CBC/ECB/CTR) 加密 - 跨平台版本

#include "AES.h"
#include <vector>
#include <string>
#include <stdexcept>
#include <cstring>
#include <cstdint>
#include <random>
#include <algorithm>

// 平台检测
#if defined(_WIN32) || defined(_WIN64)
    #define PLATFORM_WINDOWS 1
    #include <intrin.h>
    #include <immintrin.h>
#elif defined(__linux__) || defined(__APPLE__)
    #define PLATFORM_POSIX 1
    #include <cpuid.h>
    #include <immintrin.h>
#endif

// CBC模式
#ifndef CBC
#define CBC 1
#endif

// ECB模式
#ifndef ECB
#define ECB 1
#endif

// CTR模式
#ifndef CTR
#define CTR 1
#endif

#define AES256 1

#define AES_BLOCKLEN 16 // AES块长度为16字节

#if defined(AES256) && (AES256 == 1)
#define AES_KEYLEN 32
#define AES_keyExpSize 240
#elif defined(AES192) && (AES192 == 1)
#define AES_KEYLEN 24
#define AES_keyExpSize 208
#else
#define AES_KEYLEN 16
#define AES_keyExpSize 176
#endif

struct AES_ctx
{
    uint8_t RoundKey[AES_keyExpSize];
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
    uint8_t Iv[AES_BLOCKLEN];
#endif
    // AES-NI accelerated round keys (if supported)
    bool aesni_available;
    // allocate maximum round keys for AES-256 (Nr=14 -> 15 round keys)
    __m128i enc_round_keys[15];
    __m128i dec_round_keys[15];
};

// The number of columns comprising a state in AES. This is a constant in AES. Value=4
#define Nb 4

#if defined(AES256) && (AES256 == 1)
#define Nk 8
#define Nr 14
#elif defined(AES192) && (AES192 == 1)
#define Nk 6
#define Nr 12
#else
#define Nk 4
#define Nr 10
#endif

#ifndef MULTIPLY_AS_A_FUNCTION
#define MULTIPLY_AS_A_FUNCTION 0
#endif

typedef uint8_t state_t[4][4];

// S盒
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
};

// 逆S盒
#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
static const uint8_t rsbox[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,
    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
};
#endif

// 轮常数
static const uint8_t Rcon[11] = {
    0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36
};

#define getSBoxValue(num) (sbox[(num)])
#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
#define getSBoxInvert(num) (rsbox[(num)])
#endif

// CPU AES-NI 检测(跨平台版本)
static bool cpu_supports_aesni()
{
#if PLATFORM_WINDOWS
    int cpuInfo[4] = {0};
    __cpuid(cpuInfo, 1);
    return (cpuInfo[2] & (1 << 25)) != 0; // ECX bit 25 = AESNI
#elif PLATFORM_POSIX
    unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
    __get_cpuid(1, &eax, &ebx, &ecx, &edx);
    return (ecx & (1 << 25)) != 0; // ECX bit 25 = AESNI
#else
    // 其他平台假设不支持AES-NI
    return false;
#endif
}

// 密钥扩展
static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)
{
    unsigned i, j, k;
    uint8_t tempa[4];

    for (i = 0; i < Nk; ++i)
    {
        RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
        RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
        RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
        RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
    }

    for (i = Nk; i < Nb * (Nr + 1); ++i)
    {
        {
            k = (i - 1) * 4;
            tempa[0] = RoundKey[k + 0];
            tempa[1] = RoundKey[k + 1];
            tempa[2] = RoundKey[k + 2];
            tempa[3] = RoundKey[k + 3];
        }

        if (i % Nk == 0)
        {
            {
                const uint8_t u8tmp = tempa[0];
                tempa[0] = tempa[1];
                tempa[1] = tempa[2];
                tempa[2] = tempa[3];
                tempa[3] = u8tmp;
            }

            {
                tempa[0] = getSBoxValue(tempa[0]);
                tempa[1] = getSBoxValue(tempa[1]);
                tempa[2] = getSBoxValue(tempa[2]);
                tempa[3] = getSBoxValue(tempa[3]);
            }

            tempa[0] = tempa[0] ^ Rcon[i / Nk];
        }
#if defined(AES256) && (AES256 == 1)
        if (i % Nk == 4)
        {
            tempa[0] = getSBoxValue(tempa[0]);
            tempa[1] = getSBoxValue(tempa[1]);
            tempa[2] = getSBoxValue(tempa[2]);
            tempa[3] = getSBoxValue(tempa[3]);
        }
#endif
        j = i * 4; k = (i - Nk) * 4;
        RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
        RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
        RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
        RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
    }
}

void AES_init_ctx(AES_ctx* ctx, const uint8_t* key)
{
    KeyExpansion(ctx->RoundKey, key);
    // prepare AES-NI round keys if available
    ctx->aesni_available = cpu_supports_aesni();
    if (ctx->aesni_available) {
        // load encryption round keys
        for (int i = 0; i <= Nr; ++i) {
            ctx->enc_round_keys[i] = _mm_loadu_si128((const __m128i*)(ctx->RoundKey + i * AES_BLOCKLEN));
        }
        // prepare decryption round keys
        ctx->dec_round_keys[0] = ctx->enc_round_keys[Nr];
        for (int i = 1; i < Nr; ++i) {
            ctx->dec_round_keys[i] = _mm_aesimc_si128(ctx->enc_round_keys[Nr - i]);
        }
        ctx->dec_round_keys[Nr] = ctx->enc_round_keys[0];
    }
}

#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
void AES_init_ctx_iv(AES_ctx* ctx, const uint8_t* key, const uint8_t* iv)
{
    KeyExpansion(ctx->RoundKey, key);
    memcpy(ctx->Iv, iv, AES_BLOCKLEN);
    // prepare AES-NI round keys if available
    ctx->aesni_available = cpu_supports_aesni();
    if (ctx->aesni_available) {
        for (int i = 0; i <= Nr; ++i) {
            ctx->enc_round_keys[i] = _mm_loadu_si128((const __m128i*)(ctx->RoundKey + i * AES_BLOCKLEN));
        }
        ctx->dec_round_keys[0] = ctx->enc_round_keys[Nr];
        for (int i = 1; i < Nr; ++i) {
            ctx->dec_round_keys[i] = _mm_aesimc_si128(ctx->enc_round_keys[Nr - i]);
        }
        ctx->dec_round_keys[Nr] = ctx->enc_round_keys[0];
    }
}

void AES_ctx_set_iv(AES_ctx* ctx, const uint8_t* iv)
{
    memcpy(ctx->Iv, iv, AES_BLOCKLEN);
}
#endif

// 轮密钥加
static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey)
{
    uint8_t i, j;
    for (i = 0; i < 4; ++i)
    {
        for (j = 0; j < 4; ++j)
        {
            (*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j];
        }
    }
}

// 字节替换
static void SubBytes(state_t* state)
{
    uint8_t i, j;
    for (i = 0; i < 4; ++i)
    {
        for (j = 0; j < 4; ++j)
        {
            (*state)[j][i] = getSBoxValue((*state)[j][i]);
        }
    }
}

// 行移位
static void ShiftRows(state_t* state)
{
    uint8_t temp;

    temp = (*state)[0][1];
    (*state)[0][1] = (*state)[1][1];
    (*state)[1][1] = (*state)[2][1];
    (*state)[2][1] = (*state)[3][1];
    (*state)[3][1] = temp;

    temp = (*state)[0][2];
    (*state)[0][2] = (*state)[2][2];
    (*state)[2][2] = temp;

    temp = (*state)[1][2];
    (*state)[1][2] = (*state)[3][2];
    (*state)[3][2] = temp;

    temp = (*state)[0][3];
    (*state)[0][3] = (*state)[3][3];
    (*state)[3][3] = (*state)[2][3];
    (*state)[2][3] = (*state)[1][3];
    (*state)[1][3] = temp;
}

static uint8_t xtime(uint8_t x)
{
    return ((x << 1) ^ (((x >> 7) & 1) * 0x1b));
}

// 列混合
static void MixColumns(state_t* state)
{
    uint8_t i;
    uint8_t Tmp, Tm, t;
    for (i = 0; i < 4; ++i)
    {
        t = (*state)[i][0];
        Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3];
        Tm = (*state)[i][0] ^ (*state)[i][1]; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp;
        Tm = (*state)[i][1] ^ (*state)[i][2]; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp;
        Tm = (*state)[i][2] ^ (*state)[i][3]; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp;
        Tm = (*state)[i][3] ^ t; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp;
    }
}

#if MULTIPLY_AS_A_FUNCTION
static uint8_t Multiply(uint8_t x, uint8_t y)
{
    return (((y & 1) * x) ^
        ((y >> 1 & 1) * xtime(x)) ^
        ((y >> 2 & 1) * xtime(xtime(x))) ^
        ((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^
        ((y >> 4 & 1) * xtime(xtime(xtime(xtime(x))))));
}
#else
#define Multiply(x, y)                                \
      (  ((y & 1) * x) ^                              \
      ((y>>1 & 1) * xtime(x)) ^                       \
      ((y>>2 & 1) * xtime(xtime(x))) ^                \
      ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^         \
      ((y>>4 & 1) * xtime(xtime(xtime(xtime(x))))))
#endif

#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
// 逆列混合
static void InvMixColumns(state_t* state)
{
    int i;
    uint8_t a, b, c, d;
    for (i = 0; i < 4; ++i)
    {
        a = (*state)[i][0];
        b = (*state)[i][1];
        c = (*state)[i][2];
        d = (*state)[i][3];

        (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
        (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
        (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
        (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
    }
}

// 逆字节替换
static void InvSubBytes(state_t* state)
{
    uint8_t i, j;
    for (i = 0; i < 4; ++i)
    {
        for (j = 0; j < 4; ++j)
        {
            (*state)[j][i] = getSBoxInvert((*state)[j][i]);
        }
    }
}

// 逆行移位
static void InvShiftRows(state_t* state)
{
    uint8_t temp;

    temp = (*state)[3][1];
    (*state)[3][1] = (*state)[2][1];
    (*state)[2][1] = (*state)[1][1];
    (*state)[1][1] = (*state)[0][1];
    (*state)[0][1] = temp;

    temp = (*state)[0][2];
    (*state)[0][2] = (*state)[2][2];
    (*state)[2][2] = temp;

    temp = (*state)[1][2];
    (*state)[1][2] = (*state)[3][2];
    (*state)[3][2] = temp;

    temp = (*state)[0][3];
    (*state)[0][3] = (*state)[1][3];
    (*state)[1][3] = (*state)[2][3];
    (*state)[2][3] = (*state)[3][3];
    (*state)[3][3] = temp;
}
#endif

// 加密函数(软件实现,作为回退)
static void Cipher(state_t* state, const uint8_t* RoundKey)
{
    uint8_t round = 0;

    AddRoundKey(0, state, RoundKey);

    for (round = 1; ; ++round)
    {
        SubBytes(state);
        ShiftRows(state);
        if (round == Nr) {
            break;
        }
        MixColumns(state);
        AddRoundKey(round, state, RoundKey);
    }
    AddRoundKey(Nr, state, RoundKey);
}

#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
// 解密函数(软件实现,作为回退)
static void InvCipher(state_t* state, const uint8_t* RoundKey)
{
    uint8_t round = 0;

    AddRoundKey(Nr, state, RoundKey);

    for (round = (Nr - 1); ; --round)
    {
        InvShiftRows(state);
        InvSubBytes(state);
        AddRoundKey(round, state, RoundKey);
        if (round == 0) {
            break;
        }
        InvMixColumns(state);
    }
}
#endif

// AES-NI 单块加解密器(使用已经展开成 __m128i 的轮密钥)
static inline void AESNI_encrypt_block(const AES_ctx* ctx, uint8_t* buf)
{
    if (!ctx->aesni_available) {
        Cipher((state_t*)buf, ctx->RoundKey);
        return;
    }
    __m128i m = _mm_loadu_si128((const __m128i*)buf);
    m = _mm_xor_si128(m, ctx->enc_round_keys[0]);
    for (int i = 1; i < Nr; ++i) {
        m = _mm_aesenc_si128(m, ctx->enc_round_keys[i]);
    }
    m = _mm_aesenclast_si128(m, ctx->enc_round_keys[Nr]);
    _mm_storeu_si128((__m128i*)buf, m);
}

static inline void AESNI_decrypt_block(const AES_ctx* ctx, uint8_t* buf)
{
    if (!ctx->aesni_available) {
        InvCipher((state_t*)buf, ctx->RoundKey);
        return;
    }
    __m128i m = _mm_loadu_si128((const __m128i*)buf);
    m = _mm_xor_si128(m, ctx->dec_round_keys[0]);
    for (int i = 1; i < Nr; ++i) {
        m = _mm_aesdec_si128(m, ctx->dec_round_keys[i]);
    }
    m = _mm_aesdeclast_si128(m, ctx->dec_round_keys[Nr]);
    _mm_storeu_si128((__m128i*)buf, m);
}

#if defined(ECB) && (ECB == 1)
void AES_ECB_encrypt(const AES_ctx* ctx, uint8_t* buf)
{
    AESNI_encrypt_block(ctx, buf);
}

void AES_ECB_decrypt(const AES_ctx* ctx, uint8_t* buf)
{
    AESNI_decrypt_block(ctx, buf);
}
#endif

#if defined(CBC) && (CBC == 1)
static void XorWithIv(uint8_t* buf, const uint8_t* Iv)
{
    uint8_t i;
    for (i = 0; i < AES_BLOCKLEN; ++i)
    {
        buf[i] ^= Iv[i];
    }
}

void AES_CBC_encrypt_buffer(AES_ctx* ctx, uint8_t* buf, size_t length)
{
    size_t i;
    uint8_t* Iv = ctx->Iv;
    for (i = 0; i < length; i += AES_BLOCKLEN)
    {
        XorWithIv(buf, Iv);
        AES_ECB_encrypt(ctx, buf);
        Iv = buf;
        buf += AES_BLOCKLEN;
    }
    memcpy(ctx->Iv, Iv, AES_BLOCKLEN);
}

void AES_CBC_decrypt_buffer(AES_ctx* ctx, uint8_t* buf, size_t length)
{
    size_t i;
    uint8_t storeNextIv[AES_BLOCKLEN];
    for (i = 0; i < length; i += AES_BLOCKLEN)
    {
        memcpy(storeNextIv, buf, AES_BLOCKLEN);
        AES_ECB_decrypt(ctx, buf);
        XorWithIv(buf, ctx->Iv);
        memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN);
        buf += AES_BLOCKLEN;
    }
}
#endif

#if defined(CTR) && (CTR == 1)
void AES_CTR_xcrypt_buffer(AES_ctx* ctx, uint8_t* buf, size_t length)
{
    uint8_t buffer[AES_BLOCKLEN];

    size_t i;
    int bi;
    for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi)
    {
        if (bi == AES_BLOCKLEN)
        {
            memcpy(buffer, ctx->Iv, AES_BLOCKLEN);
            // encrypt the counter block
            AES_ECB_encrypt(ctx, buffer);

            for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi)
            {
                if (ctx->Iv[bi] == 255)
                {
                    ctx->Iv[bi] = 0;
                    continue;
                }
                ctx->Iv[bi] += 1;
                break;
            }
            bi = 0;
        }

        buf[i] = (buf[i] ^ buffer[bi]);
    }
}
#endif

// 生成安全的随机数(跨平台版本)
void generate_secure_random(uint8_t* buffer, size_t size) {
    static std::random_device rd;
    static std::mt19937_64 engine(rd());
    static std::uniform_int_distribution<uint8_t> dist(0, 255);
    
    for (size_t i = 0; i < size; ++i) {
        buffer[i] = dist(engine);
    }
}

// PKCS7填充
void pkcs7_pad(std::vector<uint8_t>& data) {
    size_t pad_len = AES_BLOCKLEN - (data.size() % AES_BLOCKLEN);
    if (pad_len == 0) pad_len = AES_BLOCKLEN;
    data.insert(data.end(), pad_len, static_cast<uint8_t>(pad_len));
}

// PKCS7去除填充
bool pkcs7_unpad(std::vector<uint8_t>& data) {
    if (data.empty()) return false;

    uint8_t pad_len = data.back();
    if (pad_len == 0 || pad_len > AES_BLOCKLEN || pad_len > data.size()) {
        return false;
    }

    // 验证填充字节是否正确
    for (size_t i = data.size() - pad_len; i < data.size(); i++) {
        if (data[i] != pad_len) {
            return false;
        }
    }

    data.resize(data.size() - pad_len);
    return true;
}

// 密钥生成 (AES-256, 32字节长度)
std::vector<uint8_t> generate_aes256_key() {
    // 创建32字节的密钥缓冲区
    std::vector<uint8_t> key(32);
    // 生成随机密钥
    generate_secure_random(key.data(), key.size());
    return key;
}

该实现符合NIST FIPS 197标准,已经过严格测试。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐