1#![no_std]
2use cipher::consts::{U16, U32};
3use cipher::generic_array::GenericArray;
4use cipher::{AlgorithmName, BlockCipher, InvalidLength, KeyInit, KeySizeUser};
5use core::fmt::Formatter;
6
7#[cfg(feature = "zeroize")]
8use cipher::zeroize::{Zeroize, ZeroizeOnDrop};
9
10mod consts;
11use crate::consts::{KEY_SCHEDULE, NUMBER_OF_ROUNDS};
12use consts::S_BOX;
13
14pub type UserKey = GenericArray<u8, U16>;
15
16pub type Key = GenericArray<u32, U32>;
18
19pub type Block = GenericArray<u8, U16>;
21
22enum TransformDirection {
23 Encrypt,
24 Decrypt,
25}
26
27pub struct SEED {
28 key: Key,
29}
30
31impl SEED {
32 pub fn with_key(key: Key) -> Self {
33 Self { key }
34 }
35}
36
37fn derive_key(key: UserKey) -> Key {
38 let (mut k0, mut k1, mut k2, mut k3) = divide_block(&key);
39 let mut derived = Key::default();
40
41 let mut temp;
42 for i in 0..NUMBER_OF_ROUNDS {
43 temp = k0.wrapping_add(k2).wrapping_sub(KEY_SCHEDULE[i]);
44 derived[2 * i] = get_seed_substitute(temp);
45 temp = k1.wrapping_sub(k3).wrapping_add(KEY_SCHEDULE[i]);
46 derived[2 * i + 1] = get_seed_substitute(temp);
47
48 if i % 2 == 0 {
49 temp = (k1 >> 8) | (k0 << 24);
50 k0 = (k0 >> 8) | (k1 << 24);
51 k1 = temp;
52 } else {
53 temp = (k3 << 8) | (k2 >> 24);
54 k2 = (k2 << 8) | (k3 >> 24);
55 k3 = temp;
56 }
57 }
58
59 derived
60}
61
62impl BlockCipher for SEED {}
63
64impl KeySizeUser for SEED {
65 type KeySize = U16;
66}
67
68impl KeyInit for SEED {
69 fn new(key: &cipher::Key<Self>) -> Self {
70 Self::new_from_slice(key).unwrap()
71 }
72 fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> {
73 if key.len() != 16 {
74 return Err(InvalidLength);
75 }
76
77 Ok(SEED {
78 key: derive_key(UserKey::clone_from_slice(key)),
79 })
80 }
81}
82
83#[cfg(feature = "zeroize")]
84impl Drop for SEED {
85 fn drop(&mut self) {
86 self.key.zeroize();
87 }
88}
89
90#[cfg(feature = "zeroize")]
91impl ZeroizeOnDrop for SEED {}
92
93fn transform(
94 l0: &mut u32,
95 l1: &mut u32,
96 r0: &mut u32,
97 r1: &mut u32,
98 key: Key,
99 output: &mut Block,
100 direction: TransformDirection,
101) {
102 match direction {
103 TransformDirection::Encrypt => {
104 for i in (0..=30).step_by(4) {
105 seed_round(l0, l1, *r0, *r1, &key, i);
106 seed_round(r0, r1, *l0, *l1, &key, i + 2);
107 }
108 }
109 TransformDirection::Decrypt => {
110 for i in (0..=30).rev().step_by(4) {
111 seed_round(l0, l1, *r0, *r1, &key, i);
112 seed_round(r0, r1, *l0, *l1, &key, i - 2);
113 }
114 }
115 }
116
117 unsafe {
118 let out = output[..].as_mut_ptr();
119 *(out as *mut u32) = r0.to_be();
120 *(out.offset(4) as *mut u32) = r1.to_be();
121 *(out.offset(8) as *mut u32) = l0.to_be();
122 *(out.offset(12) as *mut u32) = l1.to_be();
123 }
124}
125
126fn encrypt(block: Block, key: Key, output: &mut Block) {
127 let (mut l0, mut l1, mut r0, mut r1) = divide_block(&block);
128 transform(
129 &mut l0,
130 &mut l1,
131 &mut r0,
132 &mut r1,
133 key,
134 output,
135 TransformDirection::Encrypt,
136 );
137}
138
139fn decrypt(block: Block, key: Key, output: &mut Block) {
140 let (mut l0, mut l1, mut r0, mut r1) = divide_block(&block);
141 transform(
142 &mut l0,
143 &mut l1,
144 &mut r0,
145 &mut r1,
146 key,
147 output,
148 TransformDirection::Decrypt,
149 );
150}
151
152fn seed_round(l0: &mut u32, l1: &mut u32, r0: u32, r1: u32, key: &Key, offset: usize) {
153 let mut t0 = r0 ^ key[offset];
154 let mut t1 = r1 ^ key[offset + 1];
155 t1 ^= t0;
156
157 t1 = get_seed_substitute(t1);
158 t0 = t0.wrapping_add(t1);
159 t0 = get_seed_substitute(t0);
160 t1 = t1.wrapping_add(t0);
161 t1 = get_seed_substitute(t1);
162 t0 = t0.wrapping_add(t1);
163 *l0 ^= t0;
164 *l1 ^= t1;
165}
166
167fn get_seed_substitute(value: u32) -> u32 {
168 (0..4)
169 .map(|idx| S_BOX[idx][((value >> (idx * 8)) as u8) as usize])
170 .reduce(|acc, e| acc ^ e)
171 .unwrap()
172}
173
174fn divide_block(block: &[u8]) -> (u32, u32, u32, u32) {
175 assert_eq!(block.len(), 16);
176 (
177 u32::from_be_bytes(block[..4].try_into().unwrap()),
178 u32::from_be_bytes(block[4..8].try_into().unwrap()),
179 u32::from_be_bytes(block[8..12].try_into().unwrap()),
180 u32::from_be_bytes(block[12..16].try_into().unwrap()),
181 )
182}
183
184impl AlgorithmName for SEED {
185 fn write_alg_name(f: &mut Formatter<'_>) -> core::fmt::Result {
186 f.write_str("KISA-SEED")
187 }
188}
189
190cipher::impl_simple_block_encdec!(
191 SEED, U16, cipher, block,
192 encrypt: {
193 let mut b = block.clone_in();
194 encrypt(b, cipher.key, &mut b);
195 *block.get_out() = b;
196 }
197 decrypt: {
198 let mut b = block.clone_in();
199 decrypt(b, cipher.key, &mut b);
200 *block.get_out() = b;
201 }
202);