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
31pub type Key = cipher::Key<Hc256Core>;
33
34pub type Iv = cipher::Iv<Hc256Core>;
36
37pub type Hc256 = StreamCipherCoreWrapper<Hc256Core>;
39
40pub 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}