/rust/registry/src/index.crates.io-1949cf8c6b5b557f/blowfish-0.9.1/src/lib.rs
Line | Count | Source |
1 | | //! Pure Rust implementation of the [Blowfish] block cipher. |
2 | | //! |
3 | | //! # ⚠️ Security Warning: Hazmat! |
4 | | //! |
5 | | //! This crate implements only the low-level block cipher function, and is intended |
6 | | //! for use for implementing higher-level constructions *only*. It is NOT |
7 | | //! intended for direct use in applications. |
8 | | //! |
9 | | //! USE AT YOUR OWN RISK! |
10 | | //! |
11 | | //! [Blowfish]: https://en.wikipedia.org/wiki/Blowfish_(cipher) |
12 | | |
13 | | #![no_std] |
14 | | #![doc( |
15 | | html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", |
16 | | html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg", |
17 | | html_root_url = "https://docs.rs/blowfish/0.9.1" |
18 | | )] |
19 | | #![deny(unsafe_code)] |
20 | | #![cfg_attr(docsrs, feature(doc_cfg))] |
21 | | #![warn(missing_docs, rust_2018_idioms)] |
22 | | |
23 | | pub use cipher; |
24 | | |
25 | | use byteorder::{ByteOrder, BE, LE}; |
26 | | use cipher::{ |
27 | | consts::{U56, U8}, |
28 | | AlgorithmName, BlockCipher, InvalidLength, Key, KeyInit, KeySizeUser, |
29 | | }; |
30 | | use core::fmt; |
31 | | use core::marker::PhantomData; |
32 | | |
33 | | #[cfg(feature = "zeroize")] |
34 | | use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; |
35 | | |
36 | | mod consts; |
37 | | |
38 | | /// Blowfish variant which uses Little Endian byte order read/writes.s. |
39 | | pub type BlowfishLE = Blowfish<LE>; |
40 | | |
41 | | /// Blowfish block cipher instance. |
42 | | #[derive(Clone)] |
43 | | pub struct Blowfish<T: ByteOrder = BE> { |
44 | | s: [[u32; 256]; 4], |
45 | | p: [u32; 18], |
46 | | _pd: PhantomData<T>, |
47 | | } |
48 | | |
49 | 0 | fn next_u32_wrap(buf: &[u8], offset: &mut usize) -> u32 { |
50 | 0 | let mut v = 0; |
51 | 0 | for _ in 0..4 { |
52 | 0 | if *offset >= buf.len() { |
53 | 0 | *offset = 0; |
54 | 0 | } |
55 | 0 | v = (v << 8) | buf[*offset] as u32; |
56 | 0 | *offset += 1; |
57 | | } |
58 | 0 | v |
59 | 0 | } |
60 | | |
61 | | impl<T: ByteOrder> Blowfish<T> { |
62 | 0 | fn init_state() -> Blowfish<T> { |
63 | 0 | Blowfish { |
64 | 0 | p: consts::P, |
65 | 0 | s: consts::S, |
66 | 0 | _pd: PhantomData, |
67 | 0 | } |
68 | 0 | } |
69 | | |
70 | 0 | fn expand_key(&mut self, key: &[u8]) { |
71 | 0 | let mut key_pos = 0; |
72 | 0 | for i in 0..18 { |
73 | 0 | self.p[i] ^= next_u32_wrap(key, &mut key_pos); |
74 | 0 | } |
75 | 0 | let mut lr = [0u32; 2]; |
76 | 0 | for i in 0..9 { |
77 | 0 | lr = self.encrypt(lr); |
78 | 0 | self.p[2 * i] = lr[0]; |
79 | 0 | self.p[2 * i + 1] = lr[1]; |
80 | 0 | } |
81 | 0 | for i in 0..4 { |
82 | 0 | for j in 0..128 { |
83 | 0 | lr = self.encrypt(lr); |
84 | 0 | self.s[i][2 * j] = lr[0]; |
85 | 0 | self.s[i][2 * j + 1] = lr[1]; |
86 | 0 | } |
87 | | } |
88 | 0 | } |
89 | | |
90 | | #[allow(clippy::many_single_char_names)] |
91 | 0 | fn round_function(&self, x: u32) -> u32 { |
92 | 0 | let a = self.s[0][(x >> 24) as usize]; |
93 | 0 | let b = self.s[1][((x >> 16) & 0xff) as usize]; |
94 | 0 | let c = self.s[2][((x >> 8) & 0xff) as usize]; |
95 | 0 | let d = self.s[3][(x & 0xff) as usize]; |
96 | 0 | (a.wrapping_add(b) ^ c).wrapping_add(d) |
97 | 0 | } |
98 | | |
99 | 0 | fn encrypt(&self, [mut l, mut r]: [u32; 2]) -> [u32; 2] { |
100 | 0 | for i in 0..8 { |
101 | 0 | l ^= self.p[2 * i]; |
102 | 0 | r ^= self.round_function(l); |
103 | 0 | r ^= self.p[2 * i + 1]; |
104 | 0 | l ^= self.round_function(r); |
105 | 0 | } |
106 | 0 | l ^= self.p[16]; |
107 | 0 | r ^= self.p[17]; |
108 | 0 | [r, l] |
109 | 0 | } |
110 | | |
111 | 0 | fn decrypt(&self, [mut l, mut r]: [u32; 2]) -> [u32; 2] { |
112 | 0 | for i in (1..9).rev() { |
113 | 0 | l ^= self.p[2 * i + 1]; |
114 | 0 | r ^= self.round_function(l); |
115 | 0 | r ^= self.p[2 * i]; |
116 | 0 | l ^= self.round_function(r); |
117 | 0 | } |
118 | 0 | l ^= self.p[1]; |
119 | 0 | r ^= self.p[0]; |
120 | 0 | [r, l] |
121 | 0 | } |
122 | | } |
123 | | |
124 | | impl<T: ByteOrder> BlockCipher for Blowfish<T> {} |
125 | | |
126 | | impl<T: ByteOrder> KeySizeUser for Blowfish<T> { |
127 | | type KeySize = U56; |
128 | | } |
129 | | |
130 | | impl<T: ByteOrder> KeyInit for Blowfish<T> { |
131 | 0 | fn new(key: &Key<Self>) -> Self { |
132 | 0 | Self::new_from_slice(&key[..]).unwrap() |
133 | 0 | } |
134 | | |
135 | 0 | fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> { |
136 | 0 | if key.len() < 4 || key.len() > 56 { |
137 | 0 | return Err(InvalidLength); |
138 | 0 | } |
139 | 0 | let mut blowfish = Blowfish::init_state(); |
140 | 0 | blowfish.expand_key(key); |
141 | 0 | Ok(blowfish) |
142 | 0 | } |
143 | | } |
144 | | |
145 | | impl fmt::Debug for Blowfish<BE> { |
146 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
147 | 0 | f.write_str("Blowfish<BE> { ... }") |
148 | 0 | } |
149 | | } |
150 | | |
151 | | impl AlgorithmName for Blowfish<BE> { |
152 | 0 | fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { |
153 | 0 | f.write_str("Blowfish<BE>") |
154 | 0 | } |
155 | | } |
156 | | |
157 | | impl fmt::Debug for Blowfish<LE> { |
158 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
159 | 0 | f.write_str("Blowfish<LE> { ... }") |
160 | 0 | } |
161 | | } |
162 | | |
163 | | impl AlgorithmName for Blowfish<LE> { |
164 | 0 | fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { |
165 | 0 | f.write_str("Blowfish<LE>") |
166 | 0 | } |
167 | | } |
168 | | |
169 | | #[cfg(feature = "zeroize")] |
170 | | #[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] |
171 | | impl<T: ByteOrder> Drop for Blowfish<T> { |
172 | | fn drop(&mut self) { |
173 | | self.s.zeroize(); |
174 | | self.p.zeroize(); |
175 | | } |
176 | | } |
177 | | |
178 | | #[cfg(feature = "zeroize")] |
179 | | #[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] |
180 | | impl<T: ByteOrder> ZeroizeOnDrop for Blowfish<T> {} |
181 | | |
182 | | cipher::impl_simple_block_encdec!( |
183 | | <T: ByteOrder> Blowfish, U8, cipher, block, |
184 | | encrypt: { |
185 | | let mut b = [0u32; 2]; |
186 | | T::read_u32_into(block.get_in(), &mut b); |
187 | | b = cipher.encrypt(b); |
188 | | T::write_u32_into(&b, block.get_out()); |
189 | | } |
190 | | decrypt: { |
191 | | let mut b = [0u32; 2]; |
192 | | T::read_u32_into(block.get_in(), &mut b); |
193 | | b = cipher.decrypt(b); |
194 | | T::write_u32_into(&b, block.get_out()); |
195 | | } |
196 | | ); |
197 | | |
198 | | /// Bcrypt extension of blowfish |
199 | | #[cfg(feature = "bcrypt")] |
200 | | impl Blowfish<BE> { |
201 | | /// Salted expand key |
202 | 0 | pub fn salted_expand_key(&mut self, salt: &[u8], key: &[u8]) { |
203 | 0 | let mut key_pos = 0; |
204 | 0 | for i in 0..18 { |
205 | 0 | self.p[i] ^= next_u32_wrap(key, &mut key_pos); |
206 | 0 | } |
207 | 0 | let mut lr = [0u32; 2]; |
208 | 0 | let mut salt_pos = 0; |
209 | 0 | for i in 0..9 { |
210 | 0 | lr[0] ^= next_u32_wrap(salt, &mut salt_pos); |
211 | 0 | lr[1] ^= next_u32_wrap(salt, &mut salt_pos); |
212 | 0 | lr = self.encrypt(lr); |
213 | 0 |
|
214 | 0 | self.p[2 * i] = lr[0]; |
215 | 0 | self.p[2 * i + 1] = lr[1]; |
216 | 0 | } |
217 | 0 | for i in 0..4 { |
218 | 0 | for j in 0..64 { |
219 | 0 | lr[0] ^= next_u32_wrap(salt, &mut salt_pos); |
220 | 0 | lr[1] ^= next_u32_wrap(salt, &mut salt_pos); |
221 | 0 | lr = self.encrypt(lr); |
222 | 0 |
|
223 | 0 | self.s[i][4 * j] = lr[0]; |
224 | 0 | self.s[i][4 * j + 1] = lr[1]; |
225 | 0 |
|
226 | 0 | lr[0] ^= next_u32_wrap(salt, &mut salt_pos); |
227 | 0 | lr[1] ^= next_u32_wrap(salt, &mut salt_pos); |
228 | 0 | lr = self.encrypt(lr); |
229 | 0 |
|
230 | 0 | self.s[i][4 * j + 2] = lr[0]; |
231 | 0 | self.s[i][4 * j + 3] = lr[1]; |
232 | 0 | } |
233 | | } |
234 | 0 | } |
235 | | |
236 | | /// Init state |
237 | 0 | pub fn bc_init_state() -> Blowfish<BE> { |
238 | 0 | Blowfish::init_state() |
239 | 0 | } |
240 | | |
241 | | /// Encrypt |
242 | 0 | pub fn bc_encrypt(&self, lr: [u32; 2]) -> [u32; 2] { |
243 | 0 | self.encrypt(lr) |
244 | 0 | } |
245 | | |
246 | | /// Expand key |
247 | 0 | pub fn bc_expand_key(&mut self, key: &[u8]) { |
248 | 0 | self.expand_key(key) |
249 | 0 | } |
250 | | } |