1#![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
23pub use cipher;
24
25use byteorder::{ByteOrder, BE, LE};
26use cipher::{
27 consts::{U56, U8},
28 AlgorithmName, BlockCipher, InvalidLength, Key, KeyInit, KeySizeUser,
29};
30use core::fmt;
31use core::marker::PhantomData;
32
33#[cfg(feature = "zeroize")]
34use cipher::zeroize::{Zeroize, ZeroizeOnDrop};
35
36mod consts;
37
38pub type BlowfishLE = Blowfish<LE>;
40
41#[derive(Clone)]
43pub struct Blowfish<T: ByteOrder = BE> {
44 s: [[u32; 256]; 4],
45 p: [u32; 18],
46 _pd: PhantomData<T>,
47}
48
49fn next_u32_wrap(buf: &[u8], offset: &mut usize) -> u32 {
50 let mut v = 0;
51 for _ in 0..4 {
52 if *offset >= buf.len() {
53 *offset = 0;
54 }
55 v = (v << 8) | buf[*offset] as u32;
56 *offset += 1;
57 }
58 v
59}
60
61impl<T: ByteOrder> Blowfish<T> {
62 fn init_state() -> Blowfish<T> {
63 Blowfish {
64 p: consts::P,
65 s: consts::S,
66 _pd: PhantomData,
67 }
68 }
69
70 fn expand_key(&mut self, key: &[u8]) {
71 let mut key_pos = 0;
72 for i in 0..18 {
73 self.p[i] ^= next_u32_wrap(key, &mut key_pos);
74 }
75 let mut lr = [0u32; 2];
76 for i in 0..9 {
77 lr = self.encrypt(lr);
78 self.p[2 * i] = lr[0];
79 self.p[2 * i + 1] = lr[1];
80 }
81 for i in 0..4 {
82 for j in 0..128 {
83 lr = self.encrypt(lr);
84 self.s[i][2 * j] = lr[0];
85 self.s[i][2 * j + 1] = lr[1];
86 }
87 }
88 }
89
90 #[allow(clippy::many_single_char_names)]
91 fn round_function(&self, x: u32) -> u32 {
92 let a = self.s[0][(x >> 24) as usize];
93 let b = self.s[1][((x >> 16) & 0xff) as usize];
94 let c = self.s[2][((x >> 8) & 0xff) as usize];
95 let d = self.s[3][(x & 0xff) as usize];
96 (a.wrapping_add(b) ^ c).wrapping_add(d)
97 }
98
99 fn encrypt(&self, [mut l, mut r]: [u32; 2]) -> [u32; 2] {
100 for i in 0..8 {
101 l ^= self.p[2 * i];
102 r ^= self.round_function(l);
103 r ^= self.p[2 * i + 1];
104 l ^= self.round_function(r);
105 }
106 l ^= self.p[16];
107 r ^= self.p[17];
108 [r, l]
109 }
110
111 fn decrypt(&self, [mut l, mut r]: [u32; 2]) -> [u32; 2] {
112 for i in (1..9).rev() {
113 l ^= self.p[2 * i + 1];
114 r ^= self.round_function(l);
115 r ^= self.p[2 * i];
116 l ^= self.round_function(r);
117 }
118 l ^= self.p[1];
119 r ^= self.p[0];
120 [r, l]
121 }
122}
123
124impl<T: ByteOrder> BlockCipher for Blowfish<T> {}
125
126impl<T: ByteOrder> KeySizeUser for Blowfish<T> {
127 type KeySize = U56;
128}
129
130impl<T: ByteOrder> KeyInit for Blowfish<T> {
131 fn new(key: &Key<Self>) -> Self {
132 Self::new_from_slice(&key[..]).unwrap()
133 }
134
135 fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> {
136 if key.len() < 4 || key.len() > 56 {
137 return Err(InvalidLength);
138 }
139 let mut blowfish = Blowfish::init_state();
140 blowfish.expand_key(key);
141 Ok(blowfish)
142 }
143}
144
145impl fmt::Debug for Blowfish<BE> {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 f.write_str("Blowfish<BE> { ... }")
148 }
149}
150
151impl AlgorithmName for Blowfish<BE> {
152 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 f.write_str("Blowfish<BE>")
154 }
155}
156
157impl fmt::Debug for Blowfish<LE> {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 f.write_str("Blowfish<LE> { ... }")
160 }
161}
162
163impl AlgorithmName for Blowfish<LE> {
164 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
165 f.write_str("Blowfish<LE>")
166 }
167}
168
169#[cfg(feature = "zeroize")]
170#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
171impl<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")))]
180impl<T: ByteOrder> ZeroizeOnDrop for Blowfish<T> {}
181
182cipher::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#[cfg(feature = "bcrypt")]
200impl Blowfish<BE> {
201 pub fn salted_expand_key(&mut self, salt: &[u8], key: &[u8]) {
203 let mut key_pos = 0;
204 for i in 0..18 {
205 self.p[i] ^= next_u32_wrap(key, &mut key_pos);
206 }
207 let mut lr = [0u32; 2];
208 let mut salt_pos = 0;
209 for i in 0..9 {
210 lr[0] ^= next_u32_wrap(salt, &mut salt_pos);
211 lr[1] ^= next_u32_wrap(salt, &mut salt_pos);
212 lr = self.encrypt(lr);
213
214 self.p[2 * i] = lr[0];
215 self.p[2 * i + 1] = lr[1];
216 }
217 for i in 0..4 {
218 for j in 0..64 {
219 lr[0] ^= next_u32_wrap(salt, &mut salt_pos);
220 lr[1] ^= next_u32_wrap(salt, &mut salt_pos);
221 lr = self.encrypt(lr);
222
223 self.s[i][4 * j] = lr[0];
224 self.s[i][4 * j + 1] = lr[1];
225
226 lr[0] ^= next_u32_wrap(salt, &mut salt_pos);
227 lr[1] ^= next_u32_wrap(salt, &mut salt_pos);
228 lr = self.encrypt(lr);
229
230 self.s[i][4 * j + 2] = lr[0];
231 self.s[i][4 * j + 3] = lr[1];
232 }
233 }
234 }
235
236 pub fn bc_init_state() -> Blowfish<BE> {
238 Blowfish::init_state()
239 }
240
241 pub fn bc_encrypt(&self, lr: [u32; 2]) -> [u32; 2] {
243 self.encrypt(lr)
244 }
245
246 pub fn bc_expand_key(&mut self, key: &[u8]) {
248 self.expand_key(key)
249 }
250}