blowfish/
lib.rs

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
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
38/// Blowfish variant which uses Little Endian byte order read/writes.s.
39pub type BlowfishLE = Blowfish<LE>;
40
41/// Blowfish block cipher instance.
42#[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/// Bcrypt extension of blowfish
199#[cfg(feature = "bcrypt")]
200impl Blowfish<BE> {
201    /// Salted expand key
202    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    /// Init state
237    pub fn bc_init_state() -> Blowfish<BE> {
238        Blowfish::init_state()
239    }
240
241    /// Encrypt
242    pub fn bc_encrypt(&self, lr: [u32; 2]) -> [u32; 2] {
243        self.encrypt(lr)
244    }
245
246    /// Expand key
247    pub fn bc_expand_key(&mut self, key: &[u8]) {
248        self.expand_key(key)
249    }
250}