1use std::io::{Cursor, Write};
5
6mod constants;
7use constants::{BLOWFISH_P, BLOWFISH_S};
8
9const ROUNDS: usize = 16;
10const KEYBITS: u32 = 64u32 >> 3;
11
12pub struct Blowfish {
27 p: [u32; 18],
28 s: [[u32; 256]; 4],
29}
30
31impl Blowfish {
32 pub fn new(key: &[u8]) -> Blowfish {
34 let mut s = Self {
35 p: BLOWFISH_P,
36 s: BLOWFISH_S,
37 };
38
39 let mut j = 0usize;
40 for i in 0..ROUNDS + 2 {
41 let mut data = 0u32;
42 for _ in 0..4 {
43 data = (data << 8) | (key[j] as u32);
44 j += 1;
45
46 if j >= (KEYBITS as usize) {
47 j = 0;
48 }
49 }
50
51 s.p[i] ^= data;
52 }
53
54 let mut l = 0u32;
55 let mut r = 0u32;
56
57 for i in (0..18).step_by(2) {
58 let (l_new, r_new) = s.encrypt_pair(l, r);
59 s.p[i] = l_new;
60 s.p[i + 1] = r_new;
61
62 l = l_new;
63 r = r_new;
64 }
65
66 for i in 0..4 {
67 for j in (0..256).step_by(2) {
68 let (l_new, r_new) = s.encrypt_pair(l, r);
69 s.s[i][j] = l_new;
70 s.s[i][j + 1] = r_new;
71
72 l = l_new;
73 r = r_new;
74 }
75 }
76
77 s
78 }
79
80 pub fn encrypt(&self, data: &[u8]) -> Option<Vec<u8>> {
82 let padded_data = Blowfish::pad_buffer(data);
83
84 let mut cursor = Cursor::new(Vec::with_capacity(padded_data.len()));
85
86 for i in (0..padded_data.len()).step_by(8) {
87 let l_bytes: [u8; 4] = padded_data[i..i + 4].try_into().ok()?;
88 let r_bytes: [u8; 4] = padded_data[i + 4..i + 8].try_into().ok()?;
89
90 let (l, r) =
91 self.encrypt_pair(u32::from_le_bytes(l_bytes), u32::from_le_bytes(r_bytes));
92
93 cursor.write_all(u32::to_le_bytes(l).as_slice()).ok()?;
94 cursor.write_all(u32::to_le_bytes(r).as_slice()).ok()?;
95 }
96
97 Some(cursor.into_inner())
98 }
99
100 fn pad_buffer(data: &[u8]) -> Vec<u8> {
101 let mut padded_length = data.len();
102 if data.len() % 8 != 0 {
103 padded_length = data.len() + (8 - (data.len() % 8));
104 }
105
106 let mut vec = vec![0; padded_length];
107 vec[..data.len()].clone_from_slice(data);
108
109 vec
110 }
111
112 pub fn decrypt(&self, data: &[u8]) -> Option<Vec<u8>> {
115 let padded_data = Blowfish::pad_buffer(data);
116
117 let mut buffer = Vec::with_capacity(padded_data.len());
118 let mut cursor = Cursor::new(&mut buffer);
119
120 for i in (0..padded_data.len()).step_by(8) {
121 let l_bytes: [u8; 4] = padded_data[i..i + 4].try_into().ok()?;
122 let r_bytes: [u8; 4] = padded_data[i + 4..i + 8].try_into().ok()?;
123
124 let (l, r) =
125 self.decrypt_pair(u32::from_le_bytes(l_bytes), u32::from_le_bytes(r_bytes));
126
127 cursor.write_all(u32::to_le_bytes(l).as_slice()).ok()?;
128 cursor.write_all(u32::to_le_bytes(r).as_slice()).ok()?;
129 }
130
131 Some(buffer)
132 }
133
134 fn f(&self, x: u32) -> u32 {
136 let a = self.s[0][(x >> 24) as usize];
137 let b = self.s[1][((x >> 16) & 0xFF) as usize];
138 let c = self.s[2][((x >> 8) & 0xFF) as usize];
139 let d = self.s[3][(x & 0xFF) as usize];
140
141 (a.wrapping_add(b) ^ c).wrapping_add(d)
142 }
143
144 fn encrypt_pair(&self, mut l: u32, mut r: u32) -> (u32, u32) {
145 for i in (0..ROUNDS).step_by(2) {
146 l ^= self.p[i];
147 r ^= self.f(l);
148 r ^= self.p[i + 1];
149 l ^= self.f(r);
150 }
151
152 (r ^ self.p[17], l ^ self.p[16])
153 }
154
155 fn decrypt_pair(&self, mut l: u32, mut r: u32) -> (u32, u32) {
156 for i in (2..ROUNDS + 1).step_by(2).rev() {
157 l ^= self.p[i + 1];
158 r ^= self.f(l);
159 r ^= self.p[i];
160 l ^= self.f(r);
161 }
162
163 (r ^ self.p[0], l ^ self.p[1])
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170
171 #[test]
172 fn test_encrypt_decrypt() {
173 let blowfish = Blowfish::new(b"test_case");
174
175 let expected_encrypted = [
176 63, 149, 97, 229, 5, 35, 46, 128, 194, 107, 69, 132, 85, 202, 2, 126,
177 ];
178
179 assert_eq!(
180 blowfish.encrypt(b"hello, world!").unwrap(),
181 expected_encrypted
182 );
183 assert_eq!(
184 String::from_utf8(blowfish.decrypt(&expected_encrypted).unwrap()).unwrap(),
185 "hello, world!\0\0\0"
186 );
187 }
188}