opentitanlib/util/
present.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use anyhow::{Result, bail, ensure};
6use std::convert::TryInto;
7
8/// PRESENT block cipher.
9///
10/// Based on version 1.2 of the following Python implementation
11/// <https://github.com/doegox/python-cryptoplus>
12pub struct Present {
13    round_keys: Vec<u64>,
14}
15
16impl Present {
17    pub fn try_new_rounds(key: Vec<u8>, rounds: usize) -> Result<Present> {
18        ensure!(
19            (1..=254).contains(&rounds),
20            "unsupported number of rounds {}",
21            rounds
22        );
23
24        let round_keys = match key.len() {
25            10 => generate_round_keys_80(key, rounds),
26            16 => generate_round_keys_128(key, rounds),
27            _ => bail!("key length must be 80 or 128 bits"),
28        };
29
30        Ok(Present { round_keys })
31    }
32
33    /// Create a new instance of the PRESENT cipher.
34    ///
35    /// Valid key lengths are 80 and 128 bits. All other key lengths will return an error.
36    pub fn try_new(key: Vec<u8>) -> Result<Present> {
37        Self::try_new_rounds(key, 32)
38    }
39
40    /// Create a new 128-bit PRESENT cipher instance.
41    pub fn new_128(key: &[u8; 16]) -> Present {
42        Self::try_new(key.to_vec()).unwrap()
43    }
44
45    /// Create a new 80-bit PRESENT cipher instance.
46    pub fn new_80(key: &[u8; 10]) -> Present {
47        Self::try_new(key.to_vec()).unwrap()
48    }
49
50    /// Encrypt a 64-bit block.
51    pub fn encrypt_block(&self, block: u64) -> u64 {
52        let mut state = block;
53        state ^= self.round_keys[0];
54        for round_key in &self.round_keys[1..] {
55            state = s_box_layer(state);
56            state = p_box_layer(state);
57            state ^= round_key;
58        }
59        state
60    }
61
62    /// Decrypt a 64-bit block.
63    pub fn decrypt_block(&self, block: u64) -> u64 {
64        let mut state = block;
65        for round_key in self.round_keys[1..].iter().rev() {
66            state ^= round_key;
67            state = p_box_layer_dec(state);
68            state = s_box_layer_dec(state);
69        }
70        state ^ self.round_keys[0]
71    }
72}
73
74const S_BOX: [u8; 16] = [
75    0x0c, 0x05, 0x06, 0x0b, 0x09, 0x00, 0x0a, 0x0d, 0x03, 0x0e, 0x0f, 0x08, 0x04, 0x07, 0x01, 0x02,
76];
77
78const S_BOX_INV: [u8; 16] = [
79    0x05, 0x0e, 0x0f, 0x08, 0x0c, 0x01, 0x02, 0x0d, 0x0b, 0x04, 0x06, 0x03, 0x00, 0x07, 0x09, 0x0a,
80];
81
82const P_BOX: [u8; 64] = [
83    0x00, 0x10, 0x20, 0x30, 0x01, 0x11, 0x21, 0x31, 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33,
84    0x04, 0x14, 0x24, 0x34, 0x05, 0x15, 0x25, 0x35, 0x06, 0x16, 0x26, 0x36, 0x07, 0x17, 0x27, 0x37,
85    0x08, 0x18, 0x28, 0x38, 0x09, 0x19, 0x29, 0x39, 0x0a, 0x1a, 0x2a, 0x3a, 0x0b, 0x1b, 0x2b, 0x3b,
86    0x0c, 0x1c, 0x2c, 0x3c, 0x0d, 0x1d, 0x2d, 0x3d, 0x0e, 0x1e, 0x2e, 0x3e, 0x0f, 0x1f, 0x2f, 0x3f,
87];
88
89const P_BOX_INV: [u8; 64] = [
90    0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c, 0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38, 0x3c,
91    0x01, 0x05, 0x09, 0x0d, 0x11, 0x15, 0x19, 0x1d, 0x21, 0x25, 0x29, 0x2d, 0x31, 0x35, 0x39, 0x3d,
92    0x02, 0x06, 0x0a, 0x0e, 0x12, 0x16, 0x1a, 0x1e, 0x22, 0x26, 0x2a, 0x2e, 0x32, 0x36, 0x3a, 0x3e,
93    0x03, 0x07, 0x0b, 0x0f, 0x13, 0x17, 0x1b, 0x1f, 0x23, 0x27, 0x2b, 0x2f, 0x33, 0x37, 0x3b, 0x3f,
94];
95
96/// Generate the round_keys for an 80-bit key.
97fn generate_round_keys_80(key: Vec<u8>, rounds: usize) -> Vec<u64> {
98    // Pad out key so it fits in a u128 later.
99    let mut orig_key = key;
100    let mut key = vec![0u8; 6];
101    key.append(&mut orig_key);
102
103    // Convert key into a u128 for easier bit manipulation.
104    let key: &[u8; 16] = key.as_slice().try_into().unwrap();
105    let mut key = u128::from_le_bytes(*key);
106
107    let mut round_keys = Vec::new();
108    for i in 1..rounds + 1 {
109        // rawKey[0:64]
110        let round_key = (key >> 16) as u64;
111
112        // 1. Rotate bits
113        // rawKey[19:len(rawKey)]+rawKey[0:19]
114        key = (key & 0x7ffff) << 61 | key >> 19;
115
116        // 2. SBox
117        // rawKey[76:80] = S(rawKey[76:80])
118        key = (S_BOX[(key >> 76) as usize] as u128) << 76 | (key & !0u128 >> (128 - 76));
119
120        // 3. Salt
121        // rawKey[15:20] ^ i
122        key ^= (i as u128) << 15;
123
124        round_keys.push(round_key);
125    }
126
127    round_keys
128}
129
130/// Generate the round_keys for a 128-bit key.
131fn generate_round_keys_128(key: Vec<u8>, rounds: usize) -> Vec<u64> {
132    let mut round_keys = Vec::new();
133
134    // Convert key into a u128 for easier bit manipulation.
135    let key: &[u8; 16] = key.as_slice().try_into().unwrap();
136    let mut key = u128::from_le_bytes(*key);
137    for i in 1..rounds + 1 {
138        // rawKey[0:64]
139        let round_key = (key >> 64) as u64;
140
141        // 1. Rotate bits
142        key = key.rotate_left(61);
143
144        // 2. SBox
145        key = (S_BOX[(key >> 124) as usize] as u128) << 124
146            | (S_BOX[((key >> 120) & 0xF) as usize] as u128) << 120
147            | (key & (!0u128 >> 8));
148
149        // 3. Salt
150        // rawKey[62:67] ^ i
151        key ^= (i as u128) << 62;
152
153        round_keys.push(round_key);
154    }
155
156    round_keys
157}
158
159/// SBox funciton for encryption.
160fn s_box_layer(state: u64) -> u64 {
161    let mut output: u64 = 0;
162    for i in (0..64).step_by(4) {
163        output |= (S_BOX[((state >> i) & 0x0f) as usize] as u64) << i;
164    }
165    output
166}
167
168/// SBox inverse function for decryption.
169fn s_box_layer_dec(state: u64) -> u64 {
170    let mut output: u64 = 0;
171    for i in (0..64).step_by(4) {
172        output |= (S_BOX_INV[((state >> i) & 0x0f) as usize] as u64) << i;
173    }
174    output
175}
176
177/// PBox function for encryption.
178fn p_box_layer(state: u64) -> u64 {
179    let mut output: u64 = 0;
180    for (i, v) in P_BOX.iter().enumerate() {
181        output |= ((state >> i) & 0x01) << v;
182    }
183    output
184}
185
186/// PBox inverse function for decryption.
187fn p_box_layer_dec(state: u64) -> u64 {
188    let mut output: u64 = 0;
189    for (i, v) in P_BOX_INV.iter().enumerate() {
190        output |= ((state >> i) & 0x01) << v;
191    }
192    output
193}
194
195#[cfg(test)]
196mod test {
197    use super::*;
198
199    #[rustfmt::skip]
200    const ROUND_KEYS_80: [u64; 32] = [
201        0x0000000000000000, 0xc000000000000000, 0x5000180000000001, 0x60000a0003000001,
202        0xb0000c0001400062, 0x900016000180002a, 0x0001920002c00033, 0xa000a0003240005b,
203        0xd000d4001400064c, 0x30017a001a800284, 0xe01926002f400355, 0xf00a1c0324c005ed,
204        0x800d5e014380649e, 0x4017b001abc02876, 0x71926802f600357f, 0x10a1ce324d005ec7,
205        0x20d5e21439c649a8, 0xc17b041abc428730, 0xc926b82f60835781, 0x6a1cd924d705ec19,
206        0xbd5e0d439b249aea, 0x07b077abc1a8736e, 0x426ba0f60ef5783e, 0x41cda84d741ec1d5,
207        0xf5e0e839b509ae8f, 0x2b075ebc1d0736ad, 0x86ba2560ebd783ad, 0x8cdab0d744ac1d77,
208        0x1e0eb19b561ae89b, 0xd075c3c1d6336acd, 0x8ba27a0eb8783ac9, 0x6dab31744f41d700,
209    ];
210
211    #[rustfmt::skip]
212    const ROUND_KEYS_128: [u64; 32] = [
213        0x0000000000000000, 0xcc00000000000000, 0xc300000000000000, 0x5b30000000000000,
214        0x580c000000000001, 0x656cc00000000001, 0x6e60300000000001, 0xb595b30000000001,
215        0xbeb980c000000002, 0x96d656cc00000002, 0x9ffae60300000002, 0x065b595b30000002,
216        0x0f7feb980c000003, 0xac196d656cc00003, 0xa33dffae60300003, 0xd6b065b595b30003,
217        0xdf8cf7feb980c004, 0x3b5ac196d656cc04, 0x387e33dffae60304, 0xeced6b065b595b34,
218        0xe3e1f8cf7feb9809, 0x6bb3b5ac196d6569, 0xbb8f87e33dffae65, 0x80aeced6b065b590,
219        0xc1ee3e1f8cf7febf, 0x2602bb3b5ac196d0, 0xcb07b8f87e33dffc, 0x34980aeced6b065d,
220        0x8b2c1ee3e1f8cf78, 0x54d2602bb3b5ac1e, 0x4a2cb07b8f87e33a, 0x97534980aeced6b7,
221    ];
222
223    #[test]
224    fn test_generate_80() {
225        let key = vec![0u8; 10];
226        let round_keys = generate_round_keys_80(key, 32);
227        assert_eq!(round_keys, ROUND_KEYS_80);
228    }
229
230    #[test]
231    fn test_generate_128() {
232        let key = vec![0u8; 16];
233        let round_keys = generate_round_keys_128(key, 32);
234        assert_eq!(round_keys, ROUND_KEYS_128);
235    }
236
237    #[test]
238    fn test_enc_80() -> Result<()> {
239        let cipher = Present::try_new(vec![0; 10])?;
240        assert_eq!(cipher.encrypt_block(0), 0x5579c1387b228445);
241        Ok(())
242    }
243
244    #[test]
245    fn test_dec_80() -> Result<()> {
246        let cipher = Present::try_new(vec![0; 10])?;
247        assert_eq!(cipher.decrypt_block(0x5579c1387b228445), 0);
248        Ok(())
249    }
250
251    #[test]
252    fn test_enc_128() -> Result<()> {
253        let cipher = Present::try_new(vec![0; 16])?;
254        assert_eq!(cipher.encrypt_block(0), 0x96db702a2e6900af);
255        assert_eq!(cipher.encrypt_block(!0), 0x3c6019e5e5edd563);
256        let cipher = Present::try_new(vec![0xff; 16])?;
257        assert_eq!(cipher.encrypt_block(0), 0x13238c710272a5d8);
258        assert_eq!(cipher.encrypt_block(!0), 0x628d9fbd4218e5b4);
259        Ok(())
260    }
261
262    #[test]
263    fn test_dec_128() -> Result<()> {
264        let cipher = Present::try_new(vec![0; 16])?;
265        assert_eq!(cipher.decrypt_block(0x96db702a2e6900af), 0);
266        assert_eq!(cipher.decrypt_block(0x3c6019e5e5edd563), !0);
267        let cipher = Present::try_new(vec![0xff; 16])?;
268        assert_eq!(cipher.decrypt_block(0x13238c710272a5d8), 0);
269        assert_eq!(cipher.decrypt_block(0x628d9fbd4218e5b4), !0);
270        Ok(())
271    }
272}