kisaseed/
lib.rs

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
16/// 1024-bit SEED key.
17pub type Key = GenericArray<u32, U32>;
18
19/// 128-bit SEED block.
20pub 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);