Coverage Report

Created: 2026-03-23 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}