c语言编程笔录

首页 >   > 笔记大全

笔记大全

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 可以是一个强大的选择。