https://github.com/jedisct1/go-fast
A Go implementation of the FAST (Format-preserving encryption And Secure Tokenization) algorithm.
https://github.com/jedisct1/go-fast
crypto encryption fast format-preserving format-preserving-encryption fpe
Last synced: 4 months ago
JSON representation
A Go implementation of the FAST (Format-preserving encryption And Secure Tokenization) algorithm.
- Host: GitHub
- URL: https://github.com/jedisct1/go-fast
- Owner: jedisct1
- License: mit
- Created: 2025-06-17T19:55:15.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2026-03-08T21:24:32.000Z (5 months ago)
- Last Synced: 2026-04-04T02:13:50.456Z (4 months ago)
- Topics: crypto, encryption, fast, format-preserving, format-preserving-encryption, fpe
- Language: Go
- Homepage:
- Size: 107 KB
- Stars: 8
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# go-fast
A Go implementation of the FAST (Format-preserving encryption And Secure Tokenization) algorithm.
FAST is a format-preserving encryption (FPE) scheme that encrypts data while preserving its format. A 16-byte input encrypts to a 16-byte output, a sequence of decimal digits stays decimal, and so on. It supports arbitrary alphabets (radix 2--256), making it suitable both for raw byte encryption and for encrypting structured tokens like credit card numbers, API keys, or identifiers over restricted character sets.
## Features
- **Format-preserving encryption**: Output has the same length and alphabet as input
- **Arbitrary radix**: Supports alphabets from radix 2 (binary) to 256 (bytes)
- **Cross-language parity**: Produces identical ciphertext as the JavaScript and Python FAST implementations
- **Secure**: Based on AES with provable security guarantees
- **Fast**: Optimized implementation with pre-computed S-boxes and efficient diffusion
- **Deterministic**: Same plaintext + key + tweak always produces the same ciphertext
- **Tweak support**: Domain separation through optional tweak parameter
## Installation
```bash
go get github.com/jedisct1/go-fast
```
## Usage
### Basic Example
```go
package main
import (
"fmt"
"github.com/jedisct1/go-fast"
)
func main() {
// Create a new FAST cipher with a 16-byte key (AES-128)
key := []byte("0123456789abcdef")
cipher, err := fast.NewCipher(key)
if err != nil {
panic(err)
}
// Encrypt some data
plaintext := []byte("Hello, World!")
ciphertext := cipher.Encrypt(plaintext, nil)
fmt.Printf("Plaintext: %s\n", plaintext)
fmt.Printf("Ciphertext: %x\n", ciphertext)
// Decrypt it back
decrypted := cipher.Decrypt(ciphertext, nil)
fmt.Printf("Decrypted: %s\n", decrypted)
}
```
### Using Tweaks for Domain Separation
```go
// Different tweaks produce different ciphertexts for the same plaintext
data := []byte("sensitive data")
tweak1 := []byte("domain1")
tweak2 := []byte("domain2")
ciphertext1 := cipher.Encrypt(data, tweak1)
ciphertext2 := cipher.Encrypt(data, tweak2)
// ciphertext1 != ciphertext2
// Must use the same tweak to decrypt
decrypted1 := cipher.Decrypt(ciphertext1, tweak1) // ✓ Correct
decrypted2 := cipher.Decrypt(ciphertext1, tweak2) // ✗ Wrong result
```
### Key Sizes
FAST supports AES-128, AES-192, and AES-256:
```go
// AES-128 (recommended)
key128 := make([]byte, 16)
cipher128, _ := fast.NewCipher(key128)
// AES-192
key192 := make([]byte, 24)
cipher192, _ := fast.NewCipher(key192)
// AES-256
key256 := make([]byte, 32)
cipher256, _ := fast.NewCipher(key256)
```
### Arbitrary Radix (Non-Byte Alphabets)
For encrypting data over smaller alphabets -- decimal digits, hex, alphanumeric characters, base64 -- use `NewCipherFromParams` with parameters computed for the target radix and word length. Each element in the input slice must be in `[0, radix)`.
```go
package main
import (
"fmt"
"github.com/jedisct1/go-fast"
)
func main() {
key := []byte("0123456789abcdef")
// Encrypt a 16-digit number using radix 10
params, err := fast.CalculateRecommendedParams(10, 16)
if err != nil {
panic(err)
}
cipher, err := fast.NewCipherFromParams(params, key)
if err != nil {
panic(err)
}
// Input: digits 0-9 as byte values (not ASCII)
digits := []byte{4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
encrypted := cipher.Encrypt(digits, nil)
fmt.Printf("Original: %v\n", digits)
fmt.Printf("Encrypted: %v\n", encrypted) // still 16 digits, each in [0,9]
decrypted := cipher.Decrypt(encrypted, nil)
fmt.Printf("Decrypted: %v\n", decrypted)
}
```
The parameterized cipher is fixed to a single `(radix, wordLength)` pair. Create one cipher per combination and reuse it across calls. Different radixes produce completely independent S-box pools and round schedules, so a radix-10 cipher and a radix-62 cipher sharing the same key will produce unrelated outputs.
### Token Encryption
The `tokens` subpackage scans text for API keys and secrets, encrypts them in place while preserving format, and decrypts them back. It recognizes 28 built-in token patterns from GitHub, Stripe, OpenAI, AWS, Slack, SendGrid, and others.
```go
package main
import (
"fmt"
"log"
"github.com/jedisct1/go-fast/tokens"
)
func main() {
key := []byte("0123456789abcdef") // AES-128
enc, err := tokens.New(key)
if err != nil {
log.Fatal(err)
}
text := "GitHub PAT: ghp_ABCDEFghijklmnopqrstuvwxyz0123456789"
encrypted, err := enc.Encrypt(text)
if err != nil {
log.Fatal(err)
}
fmt.Println(encrypted) // "GitHub PAT: ghp_"
decrypted, err := enc.Decrypt(encrypted)
if err != nil {
log.Fatal(err)
}
fmt.Println(decrypted == text) // true
}
```
Per-call options let you filter by token type or override the tweak:
```go
// Encrypt only GitHub tokens, leave others unchanged
encrypted, _ := enc.Encrypt(text, tokens.WithTypes("github-pat"))
// Use a per-call tweak for domain separation
encrypted, _ := enc.Encrypt(text, tokens.WithCallTweak([]byte("production")))
```
`EncryptWithSpans` returns per-token metadata, and `EncryptWithMappings` returns deduplicated plaintext/ciphertext pairs. Token names, alphabets, and ordering match the JavaScript and Python FAST implementations exactly.
## Algorithm Details
FAST is based on the research paper:
> "FAST: Secure and High Performance Format-Preserving Encryption and Tokenization"
> https://eprint.iacr.org/2021/1171.pdf
### Key Properties
- **Security**: Provides 128-bit security when used with AES-128
- **Performance**: Optimized with cached S-boxes and efficient buffer management
- **Format preservation**: Input length = output length, values stay within the alphabet
- **Deterministic**: Reproducible encryption for the same inputs
- **Two construction modes**: `NewCipher(key)` for byte data of any length; `NewCipherFromParams(params, key)` for a fixed radix and word length
### Security Considerations
- Use a cryptographically secure random key
- Different applications should use different tweaks
- The same (plaintext, key, tweak) always produces the same ciphertext
- For probabilistic encryption, include random data in the tweak
## Testing
Run the comprehensive test suite:
```bash
go test -v ./...
```
For performance benchmarks:
```bash
go test -bench=. -benchtime=10s -run=^$
```
This implementation is based on the FAST specification and is provided for research and educational purposes.
## References
- [FAST Paper](https://eprint.iacr.org/2021/1171.pdf)
- [The Next Generation of Performant Data Protection: a New FPE Algorithm](https://insights.comforte.com/the-next-generation-of-performant-data-protection-a-new-fpe-algorithm)
- [Format-Preserving Encryption](https://en.wikipedia.org/wiki/Format-preserving_encryption)