golang实现pyffx
更新时间:2024-01-02什么是 PyFFX?
PyFFX 是一个 Python 库,用于实现快速和安全的格式化加密和解密,是对 FFX (Format-Preserving Feistel-based Encryption) 填充模式的实现。FFX 是一种基于费斯特尔密码(Feistel Cipher)的格式保持加密方案。它能够将指定格式的明文加密为具有相同格式的密文,并保持其长度不变。这在很多数据加密场景下是很有用的。
FFX 应用场景
比如说,在金融机构工作时,你需要存储客户信用卡号或银行卡号。但非常不推荐把它明文保存于数据库中。如果这些明文数据落入了黑客手中,那么攻击者将能够获得客户的个人隐私信息。因此,使用 FFX 格式保持加密方案,在保护客户信息的前提下,可以在需要时还原卡号。
下面是一个示例代码:
package main import ( "encoding/base64" "fmt" "log" "github.com/awnumar/memguard" "github.com/awnumar/memguard/core" "github.com/awnumar/memguard/feistel" "github.com/awnumar/memguard/ptrace" ) func main() { // 初始化安全内存 if err := core.Init(); err != nil { log.Fatalln("安全内存初始化出错:", err) } // 随机密钥长度 keyLen := 32 // 256 bits // 随机生成密钥 key, err := memguard.NewBufferRandom(keyLen) if err != nil { log.Fatalln("密钥生成出错:", err) } // 输入的原始数据 original := []byte("1234-5678-9012-3456") // FFX 加密 ciphertext, err := feistel.EncryptFfx(original, key) if err != nil { log.Fatalln("FFX 加密出错:", err) } fmt.Printf("明文: %s\n", original) fmt.Printf("密文: %s\n", ciphertext) // 确保完全清除数据内存 if err = key.Destroy(); err != nil { log.Fatalln("密钥内存销毁出错:", err) } if err = ciphertext.Destroy(); err != nil { log.Fatalln("密文内存销毁出错:", err) } }
Golang 实现 PyFFX
下面我们来看看如何在 golang 中实现 PyFFX。
第一步是计算初始 Feistel 循环(Initial Feistel Rounds)数量。
func (s *ffxEncrypter) initialFeistelRounds() int { // 在 Feistel 密码的初始化轮数中,偏差应尽可能为 0 i, _ := math.Modf(float64(s.digits) / 2) if s.radix%2 == 0 { if i < 1 { return 2 } return int(i) + 1 } return int(i) + 2 }
第二步是执行 Feistel 轮数(Feistel Rounds)。
func (s *ffxEncrypter) feistelRounds(input, tweak []byte, round int, encrypt bool) ([]byte, error) { // 左右半边均分 left, right := s.split(input) // 执行 Feistel 轮数 for i := 0; i < round; i++ { // 计算轮算法 f, err := s.evaluateRound(tweak, i, encrypt) if err != nil { return nil, err } fLeft := make([]byte, len(left)) copy(fLeft, f[:len(left)]) fRight := make([]byte, len(right)) copy(fRight, f[len(left):]) // 交叉计算左右值(类似于异或加密) newLeft := make([]byte, len(left)) newRight := make([]byte, len(right)) if encrypt { for j := 0; j < len(left); j++ { newLeft[j] = fLeft[j] ^ right[j] newRight[j] = left[j] ^ fRight[j] } } else { for j := 0; j < len(left); j++ { newLeft[j] = left[j] ^ fLeft[j] newRight[j] = fRight[j] ^ right[j] } } // 取代先前的左右值 copy(left, newLeft) copy(right, newRight) } return s.concat(left, right), nil }
第三步是评估 Feistel 轮算法(Feistel Round Algorithm)。
func (s *ffxEncrypter) evaluateRound(tweak []byte, round int, encrypt bool) ([]byte, error) { // 创建用于计算 Authentication-Then-Encryption (ATE) 的 AEAD 密码 aead, err := s.AEAD(tweak) if err != nil { return nil, err } // 将轮数编码为字节 roundByte := []byte{byte(round)} nonce := s.concat(s.radixByte(), roundByte) if encrypt { // 鉴别,然后加密 (ATE) return aead.Seal(nil, nonce, s.concat(s.concat(s.leftKey, s.rightKey), nonce), nil), nil } // 解密,然后验证 (ATD) defer core.FreeBytes(roundByte) ciphertext := s.concat(s.leftKey, s.rightKey)[s.blockSize:] plaintext, err := aead.Open(nil, nonce, ciphertext, nil) if err != nil { return nil, err } return plaintext, nil }
第四步是组合返回值(Concatenation)。
func (s *ffxEncrypter) concat(left, right []byte) []byte { result := make([]byte, len(left)+len(right)) copy(result[:len(left)], left) copy(result[len(left):], right) return result }
FFX 能够将指定格式的明文加密为具有相同格式的密文,并保持其长度不变。如果您需要保护您的数据并确保其格式不被破坏,FFX 可以是一个强大的选择。