依赖:
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));
}
}
⚠️ 重要安全提醒
不要硬编码密钥;生产密钥用密钥管理服务(KMS)
CBC 模式没有完整性校验,敏感场景推荐 AES-GCM(自带 auth tag,防篡改)
IV 必须每次加密随机,不能固定
传输 / 存储一律 base64,不要直接存二进制