This is the translated version of mysto/python-fpe.
An implementation of the NIST approved FF3 and FF3-1 Format Preserving Encryption (FPE) algorithms in Python.
This package implements the FF3 algorithm for Format Preserving Encryption as described in the March 2016 NIST publication 800-38G Methods for Format-Preserving Encryption, and revised on February 28th, 2019 with a draft update for FF3-1.
Changes to minimum domain size and revised tweak length have been implemented in this package with support for both 64-bit and 56-bit tweaks. NIST has only published official test vectors for 64-bit tweaks, but draft ACVP test vectors have been used for testing FF3-1. It is expected the final NIST standard will provide updated test vectors with 56-bit tweak lengths.
go get github.com/dusty-cjh/golang-fpe
FF3 is a Feistel cipher, and Feistel ciphers are initialized with a radix representing an alphabet. The number of characters in an alphabet is called the radix. The following radix values are typical:
- radix 10: digits 0..9
- radix 36: alphanumeric 0..9, a-z
- radix 62: alphanumeric 0..9, a-z, A-Z
Special characters and international character sets, such as those found in UTF-8, are supported by specifying a custom alphabet. Also, all elements in a plaintext string share the same radix. Thus, an identification number that consists of an initial letter followed by 6 digits (e.g. A123456) cannot be correctly encrypted by FPE while preserving this convention.
Input plaintext has maximum length restrictions based upon the chosen radix (2 * floor(96/log2(radix))):
- radix 10: 56
- radix 36: 36
- radix 62: 32
To work around string length, its possible to encode longer text in chunks.
The key length must be 128, 192, or 256 bits in length. The tweak is 7 bytes (FF3-1) or 8 bytes for the origingal FF3.
As with any cryptographic package, managing and protecting the key(s) is crucial. The tweak is generally not kept secret. This package does not store the key in memory after initializing the cipher.
The example code below uses the default domain [0-9] and can help you get started.
package main
import (
"fmt"
"github.com/dusty-cjh/golang-fpe/ff3"
"log"
)
func main() {
key := "2DE79D232DF5585D68CE47882AE256D6"
tweak := "CBD09280979564"
cipher, err := ff3.NewFF3Cipher(key, tweak, 10)
if err != nil {
log.Fatalf("Failed to create FF3 cipher: %v", err)
}
plaintext := "20241101"
ciphertext, err := cipher.Encrypt(plaintext)
if err != nil {
log.Fatalf("Failed to encrypt plaintext: %v", err)
}
decrypted, err := cipher.Decrypt(ciphertext)
if err != nil {
log.Fatalf("Failed to decrypt ciphertext: %v", err)
}
fmt.Printf("%s -> %s -> %s\n", plaintext, ciphertext, decrypted)
}
Custom alphabets up to 256 characters are supported. To use an alphabet consisting of the uppercase letters A-F (radix=6), we can continue from the above code example with:
Use these environment variables:
FF3_CIPHER_KEY
FF3_CIPHER_TWEAK
FF3_CIPHER_ALPHABET
This project was built and tested with Golang1.22.3 and later versions.
This project is licensed under the terms of the Apache 2.0 license.