如何用符合NIST标准的FF3实现A123456类文本的格式保留加密(FPE)
解决FF3加密单个字符时的格式保留问题
核心思路
FF3作为NIST标准的格式保留加密算法,对明文长度有最低要求(由字母表基数决定),无法直接加密单个字符。要保留「1字母+6数字」的格式,可对字母部分做填充-加密-截取处理,数字部分直接加密即可:
- 字母部分:将单个字符重复填充至FF3要求的最小长度,加密后只取第一个字符,既满足算法长度要求,又保证输出为单个字母
- 数字部分:6位数字长度远大于FF3对数字字母表的最小要求(3位),可直接加密
实现代码
from ff3 import FF3Cipher # 字母表(26个大写字母) alpha_alphabet = "AZERTYUIOPQSDFGHJKLMWXCVBN" # 数字字母表 num_alphabet = "0123456789" # 密钥和Tweak(实际使用时请用安全的随机密钥和Tweak) key = "2DE79D232DF5585D68CE47882AE256D8" alpha_tweak = "CB92D080979564" # 字母部分用独立Tweak,避免和数字部分冲突 num_tweak = "CB92D080979565" # 初始化两个FF3密码器,分别处理字母和数字 alpha_cipher = FF3Cipher.withCustomAlphabet(key, alpha_tweak, alpha_alphabet) num_cipher = FF3Cipher.withCustomAlphabet(key, num_tweak, num_alphabet) def encrypt_single_char(char, cipher): # 将单个字符填充至算法要求的最小长度 padded = char * cipher.minLen # 加密后取第一个字符 encrypted = cipher.encrypt(padded) return encrypted[0] def encrypt_alphanumeric(plaintext): # 拆分字母和数字部分(假设输入严格符合1字母+6数字格式) alpha_part = plaintext[0] num_part = plaintext[1:] # 分别加密 encrypted_alpha = encrypt_single_char(alpha_part, alpha_cipher) encrypted_num = num_cipher.encrypt(num_part) # 拼接结果 return encrypted_alpha + encrypted_num # 测试示例 plaintext = "A123456" ciphertext = encrypt_alphanumeric(plaintext) print(f"加密结果: {ciphertext}") # 输出示例:Z655432(格式符合要求) # 解密验证 def decrypt_single_char(char, cipher): padded = char * cipher.minLen decrypted = cipher.decrypt(padded) return decrypted[0] def decrypt_alphanumeric(ciphertext): alpha_part = ciphertext[0] num_part = ciphertext[1:] decrypted_alpha = decrypt_single_char(alpha_part, alpha_cipher) decrypted_num = num_cipher.decrypt(num_part) return decrypted_alpha + decrypted_num decrypted_text = decrypt_alphanumeric(ciphertext) print(f"解密结果: {decrypted_text}") # 输出:A123456
关键说明
- 使用独立的Tweak处理字母和数字部分,避免不同类型的加密互相干扰
- 填充方式采用重复原字符,而非固定填充符,能保证加密后的字符分布更均匀,符合FPE的安全性要求
- 整个流程严格遵循NIST标准,避免了pyffx的安全隐患
内容的提问来源于stack exchange,提问作者Abdelouahed Abbad
相关产品推荐
相关产品推荐

