1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
mod keys;
mod tables;
mod transforms;
pub use block_cipher_trait;
pub use block_cipher_trait::generic_array;
pub use generic_array::typenum;
use block_cipher_trait::BlockCipher;
use generic_array::GenericArray;
use std::convert::TryInto;
use typenum::{U1, U16, U32};
use transforms::{apply_permutation, apply_s_hat, apply_s_hat_inv, apply_xor_table};
const PHI: u32 = 0x9e37_79b9;
const ROUNDS: usize = 32;
pub struct Serpent {
subkeys: keys::Subkeys,
}
impl Serpent {
pub fn with_binary_key(key: &[u8]) -> Option<Serpent> {
let expanded_key = keys::expand_key(key, key.len() * 8)?;
Some(Serpent {
subkeys: keys::derive_subkeys(expanded_key),
})
}
pub fn with_text_key(key: &str) -> Option<Serpent> {
let binary_key = keys::parse_text_key(key)?;
Serpent::with_binary_key(&binary_key)
}
pub fn encrypt_block(&self, block: u128) -> u128 {
let mut b_hat = apply_permutation(&tables::IP, block);
for i in 0..ROUNDS {
b_hat = do_round(i, b_hat, &self.subkeys);
}
apply_permutation(&tables::FP, b_hat)
}
pub fn decrypt_block(&self, block: u128) -> u128 {
let mut b_hat = apply_permutation(&tables::IP, block);
for i in (0..ROUNDS).rev() {
b_hat = do_round_inv(i, b_hat, &self.subkeys);
}
apply_permutation(&tables::FP, b_hat)
}
}
impl BlockCipher for Serpent {
type KeySize = U32;
type BlockSize = U16;
type ParBlocks = U1;
fn new(key: &GenericArray<u8, U32>) -> Self {
Serpent::with_binary_key(&key).unwrap()
}
fn encrypt_block(&self, block: &mut GenericArray<u8, Self::BlockSize>) {
let input = u128::from_le_bytes(block.as_slice().try_into().unwrap());
let output = self.encrypt_block(input);
block.copy_from_slice(&u128::to_le_bytes(output));
}
fn decrypt_block(&self, block: &mut GenericArray<u8, Self::BlockSize>) {
let input = u128::from_le_bytes(block.as_slice().try_into().unwrap());
let output = self.decrypt_block(input);
block.copy_from_slice(&u128::to_le_bytes(output));
}
}
fn do_round(i: usize, b_hat_i: u128, k_hat: &keys::Subkeys) -> u128 {
let xored = b_hat_i ^ k_hat[i];
let s_hat_i = apply_s_hat(i, xored);
if i <= ROUNDS - 2 {
apply_xor_table(&tables::LT, s_hat_i)
} else {
s_hat_i ^ k_hat[ROUNDS]
}
}
fn do_round_inv(i: usize, b_hat_i_plus_1: u128, k_hat: &keys::Subkeys) -> u128 {
let s_hat_i = if i <= ROUNDS - 2 {
apply_xor_table(&tables::LT_INV, b_hat_i_plus_1)
} else {
b_hat_i_plus_1 ^ k_hat[ROUNDS]
};
let xored = apply_s_hat_inv(i, s_hat_i);
xored ^ k_hat[i]
}