Skip to main content

hc_256/
lib.rs

1#![no_std]
2#![doc = include_str!("../README.md")]
3#![doc(
4    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
5    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
6)]
7#![cfg_attr(docsrs, feature(doc_cfg))]
8#![forbid(unsafe_code)]
9#![warn(missing_docs, rust_2018_idioms)]
10
11pub use cipher;
12
13use cipher::{
14    AlgorithmName, Block, BlockSizeUser, IvSizeUser, KeyIvInit, KeySizeUser, ParBlocksSizeUser,
15    StreamCipherBackend, StreamCipherClosure, StreamCipherCore, StreamCipherCoreWrapper,
16    consts::{U1, U4, U32},
17};
18use core::fmt;
19
20#[cfg(feature = "zeroize")]
21use cipher::zeroize::{Zeroize, ZeroizeOnDrop};
22
23const TABLE_SIZE: usize = 1024;
24const TABLE_MASK: usize = TABLE_SIZE - 1;
25const INIT_SIZE: usize = 2660;
26const KEY_BITS: usize = 256;
27const KEY_WORDS: usize = KEY_BITS / 32;
28const IV_BITS: usize = 256;
29const IV_WORDS: usize = IV_BITS / 32;
30
31/// HC-256 stream cipher key.
32pub type Key = cipher::Key<Hc256Core>;
33
34/// HC-256 stream cipher initialization vector.
35pub type Iv = cipher::Iv<Hc256Core>;
36
37/// The HC-256 stream cipher.
38pub type Hc256 = StreamCipherCoreWrapper<Hc256Core>;
39
40/// Core state of the HC-256 stream cipher.
41pub struct Hc256Core {
42    ptable: [u32; TABLE_SIZE],
43    qtable: [u32; TABLE_SIZE],
44    idx: u32,
45}
46
47impl BlockSizeUser for Hc256Core {
48    type BlockSize = U4;
49}
50
51impl KeySizeUser for Hc256Core {
52    type KeySize = U32;
53}
54
55impl IvSizeUser for Hc256Core {
56    type IvSize = U32;
57}
58
59impl KeyIvInit for Hc256Core {
60    fn new(key: &Key, iv: &Iv) -> Self {
61        fn f1(x: u32) -> u32 {
62            x.rotate_right(7) ^ x.rotate_right(18) ^ (x >> 3)
63        }
64
65        fn f2(x: u32) -> u32 {
66            x.rotate_right(17) ^ x.rotate_right(19) ^ (x >> 10)
67        }
68
69        let mut out = Self {
70            ptable: [0; TABLE_SIZE],
71            qtable: [0; TABLE_SIZE],
72            idx: 0,
73        };
74        let mut data = [0; INIT_SIZE];
75
76        for i in 0..KEY_WORDS {
77            data[i] = key[4 * i] as u32 & 0xff
78                | ((key[(4 * i) + 1] as u32 & 0xff) << 8)
79                | ((key[(4 * i) + 2] as u32 & 0xff) << 16)
80                | ((key[(4 * i) + 3] as u32 & 0xff) << 24);
81        }
82
83        for i in 0..IV_WORDS {
84            data[i + KEY_WORDS] = iv[4 * i] as u32 & 0xff
85                | ((iv[(4 * i) + 1] as u32 & 0xff) << 8)
86                | ((iv[(4 * i) + 2] as u32 & 0xff) << 16)
87                | ((iv[(4 * i) + 3] as u32 & 0xff) << 24);
88        }
89
90        for i in IV_WORDS + KEY_WORDS..INIT_SIZE {
91            data[i] = f2(data[i - 2])
92                .wrapping_add(data[i - 7])
93                .wrapping_add(f1(data[i - 15]))
94                .wrapping_add(data[i - 16])
95                .wrapping_add(i as u32);
96        }
97
98        out.ptable[..TABLE_SIZE].clone_from_slice(&data[512..(TABLE_SIZE + 512)]);
99        out.qtable[..TABLE_SIZE].clone_from_slice(&data[1536..(TABLE_SIZE + 1536)]);
100
101        out.idx = 0;
102
103        for _ in 0..4096 {
104            out.gen_word();
105        }
106
107        out
108    }
109}
110
111impl StreamCipherCore for Hc256Core {
112    #[inline(always)]
113    fn remaining_blocks(&self) -> Option<usize> {
114        None
115    }
116
117    fn process_with_backend(&mut self, f: impl StreamCipherClosure<BlockSize = Self::BlockSize>) {
118        f.call(&mut Backend(self));
119    }
120}
121
122impl AlgorithmName for Hc256Core {
123    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
124        f.write_str("Hc256")
125    }
126}
127
128impl fmt::Debug for Hc256Core {
129    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130        f.write_str("Hc256Core { ... }")
131    }
132}
133
134impl Hc256Core {
135    #[inline]
136    fn g1(&self, x: u32, y: u32) -> u32 {
137        (x.rotate_right(10) ^ y.rotate_right(23))
138            .wrapping_add(self.qtable[(x ^ y) as usize & TABLE_MASK])
139    }
140
141    #[inline]
142    fn g2(&self, x: u32, y: u32) -> u32 {
143        (x.rotate_right(10) ^ y.rotate_right(23))
144            .wrapping_add(self.ptable[(x ^ y) as usize & TABLE_MASK])
145    }
146
147    #[inline]
148    fn h1(&self, x: u32) -> u32 {
149        self.qtable[(x & 0xff) as usize]
150            .wrapping_add(self.qtable[(256 + ((x >> 8) & 0xff)) as usize])
151            .wrapping_add(self.qtable[(512 + ((x >> 16) & 0xff)) as usize])
152            .wrapping_add(self.qtable[(768 + ((x >> 24) & 0xff)) as usize])
153    }
154
155    #[inline]
156    fn h2(&self, x: u32) -> u32 {
157        self.ptable[(x & 0xff) as usize]
158            .wrapping_add(self.ptable[(256 + ((x >> 8) & 0xff)) as usize])
159            .wrapping_add(self.ptable[(512 + ((x >> 16) & 0xff)) as usize])
160            .wrapping_add(self.ptable[(768 + ((x >> 24) & 0xff)) as usize])
161    }
162
163    fn gen_word(&mut self) -> u32 {
164        let i = self.idx as usize;
165        let j = self.idx as usize & TABLE_MASK;
166
167        self.idx = (self.idx + 1) & (2048 - 1);
168
169        if i < 1024 {
170            self.ptable[j] = self.ptable[j]
171                .wrapping_add(self.ptable[j.wrapping_sub(10) & TABLE_MASK])
172                .wrapping_add(self.g1(
173                    self.ptable[j.wrapping_sub(3) & TABLE_MASK],
174                    self.ptable[j.wrapping_sub(1023) & TABLE_MASK],
175                ));
176
177            self.h1(self.ptable[j.wrapping_sub(12) & TABLE_MASK]) ^ self.ptable[j]
178        } else {
179            self.qtable[j] = self.qtable[j]
180                .wrapping_add(self.qtable[j.wrapping_sub(10) & TABLE_MASK])
181                .wrapping_add(self.g2(
182                    self.qtable[j.wrapping_sub(3) & TABLE_MASK],
183                    self.qtable[j.wrapping_sub(1023) & TABLE_MASK],
184                ));
185
186            self.h2(self.qtable[j.wrapping_sub(12) & TABLE_MASK]) ^ self.qtable[j]
187        }
188    }
189}
190
191#[cfg(feature = "zeroize")]
192impl Drop for Hc256Core {
193    fn drop(&mut self) {
194        self.ptable.zeroize();
195        self.qtable.zeroize();
196        self.idx.zeroize();
197    }
198}
199
200#[cfg(feature = "zeroize")]
201impl ZeroizeOnDrop for Hc256Core {}
202
203struct Backend<'a>(&'a mut Hc256Core);
204
205impl BlockSizeUser for Backend<'_> {
206    type BlockSize = <Hc256Core as BlockSizeUser>::BlockSize;
207}
208
209impl ParBlocksSizeUser for Backend<'_> {
210    type ParBlocksSize = U1;
211}
212
213impl StreamCipherBackend for Backend<'_> {
214    #[inline(always)]
215    fn gen_ks_block(&mut self, block: &mut Block<Self>) {
216        block.copy_from_slice(&self.0.gen_word().to_le_bytes());
217    }
218}