小易说IT 小易说IT

Python AES 代码示例(AES-256-CBC,推荐)

依赖:cryptography,跨平台安全库,不要用 pycrypto(已废弃)

pip install cryptography
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
import os
import base64

def aes_encrypt(plain_text: str, key: bytes) -> str:
    # CBC模式必须随机IV,16字节
    iv = os.urandom(16)
    cipher = Cipher(algorithms.AES(key), modes.CBC(iv))
    encryptor = cipher.encryptor()

    # PKCS7填充
    padder = padding.PKCS7(128).padder()
    padded_data = padder.update(plain_text.encode("utf-8")) + padder.finalize()
    cipher_data = encryptor.update(padded_data) + encryptor.finalize()

    # IV放在密文前面一起返回,解密时拆分
    return base64.b64encode(iv + cipher_data).decode("utf-8")


def aes_decrypt(cipher_b64: str, key: bytes) -> str:
    raw = base64.b64decode(cipher_b64)
    iv = raw[:16]
    cipher_data = raw[16:]

    cipher = Cipher(algorithms.AES(key), modes.CBC(iv))
    decryptor = cipher.decryptor()
    padded_plain = decryptor.update(cipher_data) + decryptor.finalize()

    unpadder = padding.PKCS7(128).unpadder()
    plain_data = unpadder.update(padded_plain) + unpadder.finalize()
    return plain_data.decode("utf-8")


if __name__ == "__main__":
    # 密钥长度说明:
    # AES-128 → 16字节
    # AES-192 → 24字节
    # AES-256 → 32字节(下面这个)
    key = os.urandom(32)
    print(f"密钥(base64): {base64.b64encode(key).decode()}")

    src = "Hello AES 测试中文"
    enc = aes_encrypt(src, key)
    print(f"加密后: {enc}")
    dec = aes_decrypt(enc, key)
    print(f"解密后: {dec}")

Java 版本(SpringBoot 常用,和上面互通)

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class AesUtil {
    private static final String ALGORITHM = "AES/CBC/PKCS5Padding";

    public static String encrypt(String plainText, byte[] key) throws Exception {
        byte[] iv = new byte[16];
        java.security.SecureRandom.getInstanceStrong().nextBytes(iv);
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
        byte[] enc = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));

        byte[] result = new byte[iv.length + enc.length];
        System.arraycopy(iv, 0, result, 0, iv.length);
        System.arraycopy(enc, 0, result, iv.length, enc.length);
        return Base64.getEncoder().encodeToString(result);
    }

    public static String decrypt(String b64, byte[] key) throws Exception {
        byte[] raw = Base64.getDecoder().decode(b64);
        byte[] iv = new byte[16];
        byte[] cipherData = new byte[raw.length - 16];
        System.arraycopy(raw, 0, iv, 0, 16);
        System.arraycopy(raw, 16, cipherData, 0, cipherData.length);

        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
        return new String(cipher.doFinal(cipherData), StandardCharsets.UTF_8);
    }

    public static void main(String[] args) throws Exception {
        // 这里key要和python的32字节一致
        byte[] key = new byte[32];
        java.security.SecureRandom.getInstanceStrong().nextBytes(key);
        String enc = encrypt("Hello AES 测试中文", key);
        System.out.println(enc);
        System.out.println(decrypt(enc, key));
    }
}

⚠️ 重要安全提醒

  1. 不要硬编码密钥;生产密钥用密钥管理服务(KMS)

  2. CBC 模式没有完整性校验,敏感场景推荐 AES-GCM(自带 auth tag,防篡改)

  3. IV 必须每次加密随机,不能固定

  4. 传输 / 存储一律 base64,不要直接存二进制