fxfs_crypto/
ff1.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::UnwrappedKey;
6use aes::cipher::generic_array::GenericArray;
7use aes::cipher::{BlockEncrypt, KeyInit};
8use aes::Aes256;
9use byteorder::{BigEndian, ByteOrder};
10
11// This is a heavily specialized version of ff1 encryption as described in:
12// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38G.pdf.  This implementation
13// encrypts and decrypts a u32 without a tweak. It uses radix 2.
14pub struct Ff1 {
15    initial_block: [u8; 16],
16    cipher: Aes256,
17}
18
19impl Ff1 {
20    pub fn new(key: &UnwrappedKey) -> Self {
21        let cipher = Aes256::new(GenericArray::from_slice(key.key()));
22        // See step 5 from the specification. radix = 2, u = 16, n = 32.
23        let mut initial_block = [1, 2, 1, 0, 0, 2, 10, 16, 0, 0, 0, 32, 0, 0, 0, 0];
24        cipher.encrypt_block(GenericArray::from_mut_slice(&mut initial_block));
25        // initial_block is now PRF(P).
26        Self { initial_block, cipher }
27    }
28
29    pub fn encrypt(&self, data: u32) -> u32 {
30        // This makes assumptions that the endianness will never change, which is probably true.
31        let mut a = (data >> 16) as u16;
32        let mut b = data as u16;
33
34        // ff1 uses 10 rounds.
35        for i in 0..10 {
36            // initial_block is PRF(P), so now we compute PRF(P || Q).
37            let mut block = self.initial_block.clone();
38            // xor block with Q before encrypting.
39            block[13] ^= i;
40            block[14] ^= (b >> 8) as u8;
41            block[15] ^= b as u8;
42            self.cipher.encrypt_block(GenericArray::from_mut_slice(&mut block));
43            // block is now R.
44
45            // b = 2, d = 8, so S is the first 8 bytes of block.
46            let c = a.wrapping_add(BigEndian::read_u16(&block[6..8]));
47            a = b;
48            b = c;
49        }
50        (a as u32) << 16 | b as u32
51    }
52
53    // This differs from encrypt in three ways (see specification): the order of the indices is
54    // reversed, the roles of A and B are swapped and modular addition is replaced by modular
55    // subtraction.
56    pub fn decrypt(&self, data: u32) -> u32 {
57        let mut a = (data >> 16) as u16;
58        let mut b = data as u16;
59
60        for i in (0..10).rev() {
61            // initial_block is PRF(P), so now we compute PRF(P || Q).
62            let mut block = self.initial_block.clone();
63            // xor block with Q before encrypting.
64            block[13] ^= i;
65            block[14] ^= (a >> 8) as u8;
66            block[15] ^= a as u8;
67            self.cipher.encrypt_block(GenericArray::from_mut_slice(&mut block));
68            // block is now R.
69
70            // b = 2, d = 8, so S is the first 8 bytes of block.
71            let c = b.wrapping_sub(BigEndian::read_u16(&block[6..8]));
72            b = a;
73            a = c;
74        }
75        (a as u32) << 16 | b as u32
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::Ff1;
82    use crate::UnwrappedKey;
83
84    #[test]
85    fn test_ff1() {
86        // These values have been compared against the implementation in the Rust binary-ff1 crate.
87        // The rust binary-ff1 crate will produce the same results if the bits in each byte are
88        // reversed on the input and likewise on the output.
89        let ff1 = Ff1::new(&UnwrappedKey::new([0; 32]));
90        assert_eq!(ff1.encrypt(1), 0x27c9468);
91        assert_eq!(ff1.encrypt(999), 0x87a92dd5);
92        assert_eq!(ff1.encrypt(11471928), 0x70c679b1);
93        assert_eq!(ff1.encrypt(318689559), 0xdec5199a);
94
95        let ff1 = Ff1::new(&UnwrappedKey::new([
96            1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
97            0, 1, 2,
98        ]));
99        assert_eq!(ff1.encrypt(1), 0x92fac14e);
100        assert_eq!(ff1.encrypt(999), 0x6d2cd513);
101        assert_eq!(ff1.encrypt(11471928), 0xdb672d05);
102        assert_eq!(ff1.encrypt(318689559), 0x66d58b7e);
103
104        let ff1 = Ff1::new(&UnwrappedKey::new([
105            0xf8, 0x24, 0x6b, 0x2c, 0x38, 0x39, 0xfa, 0x6d, 0x98, 0xe8, 0x56, 0x17, 0x0c, 0xdd,
106            0xf4, 0xf1, 0x1b, 0xa5, 0xa6, 0xcb, 0x07, 0x06, 0x58, 0x4c, 0x2a, 0x63, 0x9d, 0x32,
107            0x22, 0x80, 0xe6, 0xf1,
108        ]));
109        assert_eq!(ff1.encrypt(1), 0xfc049c96);
110        assert_eq!(ff1.encrypt(999), 0xbe10a02a);
111        assert_eq!(ff1.encrypt(11471928), 0xe1290afd);
112        assert_eq!(ff1.encrypt(318689559), 0xf4fcf414);
113
114        for _ in 0..100 {
115            let v = rand::random();
116            assert_eq!(ff1.decrypt(ff1.encrypt(v)), v);
117        }
118    }
119}