ExFPE.FF3_1 (ex_fpe v0.1.0)

Copy Markdown View Source

The FF3-1 format-preserving encryption mode.

No longer NIST-approved

NIST removed the entire FF3 family (FF3 and FF3-1) in SP 800-38Gr1 2pd (Second Public Draft, February 2025): Beyne's linear cryptanalysis (CRYPTO 2021) found a weakness in the tweak schedule that affects both FF3 and FF3-1 but not FF1. FF1 is now the only approved FPE mode.

FF3-1 is retained here for interoperability with existing data, but new applications should prefer ExFPE.FF1 (the :ff1 mode, which is the default).

Use it through the ExFPE facade: ExFPE.new(key, :ff3_1, radix_or_alphabet), then ExFPE.encrypt!/3 / ExFPE.decrypt!/3. See ExFPE for the full how-to-use guide (contexts, alphabets, tweaks). This module documents what is specific to FF3-1: its fixed 7-byte tweak and its length constraints.

This implementation conforms, as best as possible, to Draft SP 800-38G Rev. 1 (the first draft, in which FF3-1 was still specified), as published by NIST in their Cryptographic Standards.

No official test vectors for FF3-1 exist as of the time of writing; many of the ones used in this library's test suite were copied almost verbatim from ubiq-fpe-go, an implementation of the FF1 and FF3-1 algorithms in Go.

Length constraints

Numerical strings under FF3-1 are subject to minimum and maximum lengths. These constraints depend on the radix.

iex> key = :crypto.strong_rand_bytes(32)
iex> {:ok, ctx} = ExFPE.new(key, :ff3_1,_radix = 10)
iex> %{min_length: 6, max_length: 56} = ExFPE.FF3_1.constraints(ctx.algorithm)

iex> key = :crypto.strong_rand_bytes(32)
iex> {:ok, ctx} = ExFPE.new(key, :ff3_1,_radix = 16)
iex> %{min_length: 5, max_length: 48} = ExFPE.FF3_1.constraints(ctx.algorithm)

iex> key = :crypto.strong_rand_bytes(32)
iex> {:ok, ctx} = ExFPE.new(key, :ff3_1,_radix = 2)
iex> %{min_length: 20, max_length: 192} = ExFPE.FF3_1.constraints(ctx.algorithm)

min_length is required because, for any given radix, short enough numerical strings encompass too few possible values, rendering encryption ineffective under adversarial conditions. In other words: their domain is too small.

max_length may be there - pure layman speculation - as an incentive for people to use regular crypto when working with large enough numbers. I didn't find the exact reasoning for it.

Tweak

FF3-1 uses a fixed 7-byte (56-bit) tweak. See ExFPE for the general role of tweaks in FPE, and Appendix C (page 20) of the reference document for the specifics.

iex> byte_size(<<0::56>>)
7

Summary

Types

radix()

@type radix() :: 2..65535

tweak()

@type tweak() :: <<_::56>>