4个版本

0.2.2 2023年12月8日
0.2.1 2023年7月24日
0.2.0 2023年7月17日
0.1.0 2023年4月26日

数据库实现中排名第74位

Download history 910/week @ 2024-03-13 1117/week @ 2024-03-20 635/week @ 2024-03-27 1459/week @ 2024-04-03 482/week @ 2024-04-10 262/week @ 2024-04-17 590/week @ 2024-04-24 809/week @ 2024-05-01 242/week @ 2024-05-08 312/week @ 2024-05-15 411/week @ 2024-05-22 340/week @ 2024-05-29 380/week @ 2024-06-05 573/week @ 2024-06-12 757/week @ 2024-06-19 991/week @ 2024-06-26

每月下载量2,728
用于cloudproof

自定义许可证

255KB
2K SLoC

格式保留加密

此库提供了用于零信任环境的格式保留加密(FPE)技术。这些技术基于FPE-FF1,该技术已在NIST:800-38G中描述。

格式保留加密 (FPE)

FPE旨在在保留明文格式(字母表)的同时加密明文。FPE-FF1是一个标准化算法,使用对称加密,但它的速度和安全性不如AES或ChaCha等标准化的对称(或公钥)加密方法。它仅应在密文容器的格式受到限制的情况下使用(例如,无法更改的固定数据库模式)。

实现

FPE实现遵循NIST对FF1的规范(可在NIST SP 800-38G规范中找到)。

代码基于在GitHub上找到的cosmian_fpe目录,该目录基于str4d/fpe。根据这篇密码分析论文的建议,已将Feistel轮数增加到18。

实现还强制要求 radix^min_len > 1_000_000。对于 AlphabetInteger FPE 功能,以下参数满足此要求

基数 示例字母表 最小文本长度
2 "01" 20
10 "01234567890" 6
16 "01234567890abcdef" 5

使用FPE

Cosmian FPE 提出了 3 个结构

  • fpe::Alphabet 用于加密文本
  • fpe::Integer 用于使用不同基数加密整数
  • fpe::Float 用于加密浮点数

加密文本

fpe::Alphabet 结构提供使用 alphabet 加密明文的选项。属于字母表的明文字符会被加密,而其他字符在密文中保持其原始位置不变。

可以使用 Alphabet::instantiate() 方法实例化一个字母表

let hexadecimal_alphabet = Alphabet::instantiate("01234567890abcdef").unwrap();

有多个预定义的字母表可用

  • 字母表::alpha()
  • 字母表::alpha_lower()
  • 字母表::alpha_upper()
  • 字母表::numeric()
  • 字母表::hexa_decimal()
  • 字母表::alpha_numeric()
  • 字母表::chinese()
  • 字母表::latin1sup()
  • 字母表::latin1sup_alphanum()

这些字母表可以使用 extend_with 方法轻松扩展

//0-9a-zA-Z
let mut alphabet = Alphabet::alphanumeric();
// add the space character
alphabet.extend_with(" ");
加密和解密字母数字文本
let key = [0_u8; 32];
let tweak = b"unique tweak";

let alphabet = Alphabet::alpha_numeric(); //0-9a-zA-Z

let ciphertext = alphabet.encrypt(&key, tweak, "alphanumeric").unwrap();
assert_eq!("jraqSuFWZmdH", ciphertext);

let plaintext = alphabet.decrypt(&key, tweak, &ciphertext).unwrap();
assert_eq!("alphanumeric", plaintext);
加密和解密信用卡号
let key = [0_u8; 32];
let tweak = b"unique tweak";

let alphabet = Alphabet::numeric(); //0-9

let ciphertext = alphabet
   .encrypt(&key, tweak, "1234-1234-1234-1234")
   .unwrap();
assert_eq!("1415-4650-5562-7272", ciphertext);

let plaintext = alphabet.decrypt(&key, tweak, &ciphertext).unwrap();
assert_eq!("1234-1234-1234-1234", plaintext);

注意:由于破折号字符不是字母表的一部分,它在加密和解密过程中被保留。

加密和解密带空格的中文文本
let key = [0_u8; 32];
let tweak = b"unique tweak";

let mut alphabet = Alphabet::chinese();
// add the space character to the alphabet
alphabet.extend_with(" ");

let ciphertext = alphabet.encrypt(&key, tweak, "天地玄黄 宇宙洪荒").unwrap();
assert_eq!("儖濣鈍媺惐墷礿截媃", ciphertext);

let plaintext = alphabet.decrypt(&key, tweak, &ciphertext).unwrap();
assert_eq!("天地玄黄 宇宙洪荒", plaintext);

注意:由于空格字符被添加到字母表中,它也被加密。

加密整数

fpe::Integer 结构提供加密介于 2(二进制)和 16(十六进制)之间的整数以及此基数的最大幂的能力。

要加密小于 u64::MAX 的十进制整数,请使用

let key = [0_u8; 32];
let tweak = b"unique tweak";

// decimal number with digits 0-9
let radix = 10_u32;
// the number of digits of the biggest number = radix^digits -1
// In this case 6 decimal digits -> 999_999
let digits = 6;

let itg = Integer::instantiate(radix, digits).unwrap();

let ciphertext = itg.encrypt(&key, tweak, 123_456_u64).unwrap();
assert_eq!(110_655_u64, ciphertext);

let plaintext = itg.decrypt(&key, tweak, ciphertext).unwrap();
assert_eq!(123_456_u64, plaintext);

还支持大无符号整数

let key = [0_u8; 32];
let tweak = b"unique tweak";

// decimal number with digits 0-9
let radix = 10_u32;
// the number of digits of the greatest number = radix^digits -1 = 10^20-1
let digits = 20;

// the value to encrypt: 10^17
let value = BigUint::from_str_radix("100000000000000000", radix).unwrap();

let itg = Integer::instantiate(radix, digits).unwrap();

let ciphertext = itg.encrypt_big(&key, tweak, &value).unwrap();
assert_eq!(
   BigUint::from_str_radix("65348521845006160218", radix).unwrap(),
   ciphertext
);

let plaintext = itg.decrypt_big(&key, tweak, &ciphertext).unwrap();
assert_eq!(
   BigUint::from_str_radix("100000000000000000", radix).unwrap(),
   plaintext
);

加密浮点数

fpe::Float 结构提供对加密类型为 f64 的浮点数的支持

let key = [0_u8; 32];
let tweak = b"unique tweak";

let flt = Float::instantiate().unwrap();
let ciphertext = flt.encrypt(&key, tweak, 123_456.789_f64).unwrap();
assert_eq!(1.170438892319619e91_f64, ciphertext);

let plaintext = flt.decrypt(&key, tweak, ciphertext).unwrap();
assert_eq!(123_456.789_f64, plaintext);

调整

Tweaks 是公共参数,应在可能的情况下随着每次加密实例的变化而变化。 TweaksNIST:800-38G: 附录 C 中描述。没有 tweak 的大小限制。

基准测试

运行快速入门

从当前目录(./crates/fpe)运行 cargo criterion

运行详细报告(Linux,MacOS)

  1. 安装 criterion 和 criterion-table

    cargo install cargo-criterion
    cargo install criterion-table
    
  2. 从项目根目录运行

    bash ./benches/benches.sh
    
  3. 基准测试随后在 ./benches/BENCHMARKS.md 中可用

依赖关系

~1.8–7.5MB
~61K SLoC