1use base64::{Engine, engine::general_purpose};
2use log::{error, info};
3
4#[derive(Debug)]
6pub enum PadbusterError {
7 ValidationError(&'static str),
9 UnableFindByteError(u8, Box<PadbusterError>),
11 UnableDecryptByteError(Vec<u8>, u8),
13 BadPaddingError(Vec<u8>, String),
15 Unspecified(&'static str),
17}
18
19impl std::fmt::Display for PadbusterError {
20 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
21 match *self {
22 PadbusterError::ValidationError(ref s) => write!(f, "{s}"),
23 PadbusterError::UnableFindByteError(ref byte, ref origin) => {
24 write!(f, "Unable to find {byte} byte: {origin}")
25 }
26 PadbusterError::UnableDecryptByteError(ref block, ref max_retries) => write!(
27 f,
28 "Could not decrypt byte in {block:?} within maximum allowed retries ({max_retries})"
29 ),
30 PadbusterError::BadPaddingError(ref ciphertext, ref origin) => {
31 write!(f, "Bad Padding for ciphertext {ciphertext:?}: {origin}")
32 }
33 PadbusterError::Unspecified(ref s) => write!(f, "Unexpected error occured: {s}"),
34 }
35 }
36}
37
38pub struct PaddingOracle {
40 oracle: fn(Vec<u8>) -> Result<(), PadbusterError>,
41 block_size: u8,
42 max_retries: u8,
43}
44
45impl PaddingOracle {
46 pub fn new(
55 block_size: u8,
56 max_retries: u8,
57 oracle: fn(Vec<u8>) -> Result<(), PadbusterError>,
58 ) -> Self {
59 PaddingOracle {
60 oracle,
61 block_size,
62 max_retries,
63 }
64 }
65
66 pub fn encrypt(&self, plaintext: &[u8], iv: &[u8]) -> Result<Vec<u8>, PadbusterError> {
74 info!("Starting Encrypt Mode");
75
76 if plaintext.is_empty() {
77 return Err(PadbusterError::ValidationError(
78 "Cannot encrypt empty plaintext",
79 ));
80 }
81 let mut pad = ((self.block_size as usize) - (plaintext.len() % (self.block_size as usize)))
82 % (self.block_size as usize);
83 if pad == 0 {
84 pad = self.block_size as usize;
85 }
86 let mut used_iv = iv.to_owned();
87 let mut ptext = plaintext.to_owned();
88 let mut padding = vec![pad as u8; pad];
89 ptext.append(&mut padding);
90
91 info!("Attempting to encrypt {ptext:?} bytes");
92 if used_iv.is_empty() {
93 used_iv = vec![0u8; self.block_size as usize];
94 }
95 let mut encrypted = used_iv;
96 let mut block = encrypted.clone();
97
98 let mut n = ptext.len();
99 while n > 0 {
100 info!("*** Starting Block {} ***", n / (self.block_size as usize));
101 let intermediate_bytes = self.bust(&mut block)?;
102 let current_intermediate_bytes = intermediate_bytes.clone();
103
104 block = xor_data(
105 intermediate_bytes,
106 ptext[(n - (self.block_size as usize))..n].to_vec(),
107 );
108 let current_block = block.clone();
109
110 let mut current_encrypted = encrypted.clone();
111 encrypted.clone_from(&block);
112 encrypted.append(&mut current_encrypted);
113
114 info!(
115 "Block {} Results:
116 [+] New Cipher Text (HEX): {}
117 [+] Intermediate Bytes (HEX): {}",
118 n / (self.block_size as usize),
119 hex::encode(current_block),
120 hex::encode(current_intermediate_bytes)
121 );
122
123 n -= self.block_size as usize;
124 }
125
126 info!(
127 "*** Finished ***
128 [+] Encrypted value is: {}",
129 general_purpose::STANDARD.encode(&encrypted)
130 );
131
132 Ok(encrypted)
133 }
134
135 pub fn decrypt(&self, ciphertext: &[u8], iv: &[u8]) -> Result<Vec<u8>, PadbusterError> {
143 info!("Starting Decrypt Mode");
144 info!("Attempting to decrypt {ciphertext:?} bytes");
145
146 if !ciphertext.len().is_multiple_of(self.block_size as usize) {
147 return Err(PadbusterError::ValidationError(
148 "Ciphertext not of block size",
149 ));
150 }
151
152 if iv.is_empty() && ciphertext.len() < (self.block_size as usize) * 2 {
153 return Err(PadbusterError::ValidationError(
154 "Ciphertext not at least 2 * block size",
155 ));
156 }
157
158 let mut used_iv = iv.to_owned();
159 let mut ctext = ciphertext.to_owned();
160 if iv.is_empty() {
161 used_iv = ciphertext[..(self.block_size as usize)].to_vec();
162 ctext = ciphertext[(self.block_size as usize)..].to_vec();
163 }
164
165 let mut decrypted = vec![0u8; ctext.len()];
166
167 let mut n = 0;
168 while !ctext.is_empty() {
169 info!("*** Starting Block {} ***\n", n / self.block_size);
170 let mut block = ctext[0..(self.block_size as usize)].to_vec();
171 ctext = ctext[(self.block_size as usize)..].to_vec();
172 let next_iv = block.clone();
173
174 let current_block = block.clone();
175
176 let intermediate_bytes = self.bust(&mut block)?;
177 let current_intermediate_bytes = intermediate_bytes.clone();
178
179 let mut decrypted_block = xor_data(intermediate_bytes, used_iv);
180 let current_decrypted_block = decrypted_block.clone();
181 decrypted.append(&mut decrypted_block);
182
183 used_iv = next_iv;
184 n += self.block_size;
185
186 info!(
187 "Block {} Results:
188 [+] New Cipher Text (HEX): {}
189 [+] Intermediate Bytes (HEX): {}
190 [+] Plain Text: {}",
191 n / self.block_size,
192 hex::encode(current_block),
193 hex::encode(current_intermediate_bytes),
194 std::str::from_utf8(¤t_decrypted_block).unwrap()
195 );
196 }
197
198 info!(
199 "*** Finished ***
200 [+] Decrypted value (ASCII): {}
201 [+] Decrypted value (HEX): {}
202 [+] Decrypted value (Base64): {}",
203 std::str::from_utf8(&decrypted).unwrap(),
204 hex::encode(&decrypted),
205 general_purpose::STANDARD.encode(&decrypted)
206 );
207
208 Ok(decrypted)
209 }
210
211 fn try_bust(&self, block: &mut Vec<u8>) -> Result<Vec<u8>, PadbusterError> {
212 let mut intermediate_bytes = vec![0u8; self.block_size as usize];
213 let mut test_bytes = vec![0u8; self.block_size as usize];
214 test_bytes.append(block);
215
216 let mut byte_num = self.block_size;
217 while byte_num > 0 {
218 let mut try_number = 0;
219 let mut r = 255u8;
220 let mut i = r as i16;
221 while i >= 0 {
222 test_bytes[(byte_num - 1) as usize] = r;
224 r -= 1;
226
227 let oracle_test_bytes = test_bytes.clone();
231 try_number += 1;
232 if let Err(e) = (self.oracle)(oracle_test_bytes) {
233 if r == 0 {
234 return Err(PadbusterError::UnableFindByteError(byte_num, Box::new(e)));
235 }
236 if let PadbusterError::BadPaddingError(_, _) = e {
237 i -= 1;
238 continue;
239 }
240 error!("{e}");
241 return Err(e);
242 }
243
244 let current_pad_byte = self.block_size - (byte_num - 1);
245 let next_pad_byte = self.block_size - (byte_num - 1) + 1;
246 let decrypted_byte = test_bytes[(byte_num - 1) as usize] ^ current_pad_byte;
247
248 intermediate_bytes[(byte_num - 1) as usize] = decrypted_byte;
249
250 let mut k = byte_num - 1;
251 while k < self.block_size {
252 test_bytes[k as usize] ^= current_pad_byte;
255 test_bytes[k as usize] ^= next_pad_byte;
258
259 k += 1;
260 }
261 info!("[+] Success: ({try_number}/256) [Byte {byte_num}]");
262 break;
263 }
264
265 byte_num -= 1;
266 }
267
268 Ok(intermediate_bytes)
269 }
270
271 fn bust(&self, block: &mut Vec<u8>) -> Result<Vec<u8>, PadbusterError> {
272 info!("Processing block {block:?}");
273
274 for retry in 0..self.max_retries {
275 match self.try_bust(block) {
276 Ok(r) => return Ok(r),
277 Err(e) => {
278 error!(
279 "[+] Retrying {}/{} unable to bust block {:?} {}",
280 retry, self.max_retries, block, e
281 );
282 }
283 };
284 }
285 Err(PadbusterError::UnableDecryptByteError(
286 block.to_vec(),
287 self.max_retries,
288 ))
289 }
290}
291
292fn xor_data(data: Vec<u8>, key: Vec<u8>) -> Vec<u8> {
294 let mut res = vec![0u8; data.len()];
295 for (index, b) in data.iter().enumerate() {
296 res[index] = b ^ key[index % key.len()];
297 }
298 res
299}
300
301#[cfg(test)]
302mod tests {
303 use super::*;
304
305 use aes::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit, block_padding::Pkcs7};
306 use hex_literal::hex;
307
308 extern crate simple_logger;
309
310 type Aes128CbcEnc = cbc::Encryptor<aes::Aes128>;
311 type Aes128CbcDec = cbc::Decryptor<aes::Aes128>;
312
313 fn unpad(b: Vec<u8>, block_size: usize) -> Result<Vec<u8>, &'static str> {
314 if block_size == 0 {
315 return Err("Invalid block size");
316 }
317 if b.is_empty() {
318 return Err("Invalid PKCS7 data");
319 }
320 if b.len() % block_size != 0 {
321 return Err("Invalid PKCS7 data");
322 }
323 let c = b[b.len() - 1];
324 if c == 0 || c > (b.len() as u8) {
325 return Err("Invalid PKCS7 padding");
326 }
327 for i in 0..(c as usize) {
328 if b[b.len() - (c as usize) + i] != c {
329 return Err("Invalid PKCS7 padding");
330 }
331 }
332 Ok(b[..(b.len() - (c as usize))].to_vec())
333 }
334
335 fn oracle_fn(data: Vec<u8>) -> Result<(), PadbusterError> {
336 let key = hex!("000102030405060708090a0b0c0d0e0f");
338 let iv = &data[..16];
339 let ciphertext = &data[16..];
340 let mut buf = ciphertext.to_vec();
341 match Aes128CbcDec::new(&key.into(), iv.into()).decrypt_padded_mut::<Pkcs7>(&mut buf) {
342 Ok(_) => Ok(()),
343 Err(e) => Err(PadbusterError::BadPaddingError(
344 ciphertext.to_vec(),
345 format!("{}", e),
346 )),
347 }
348 }
349
350 #[test]
351 fn test_encrypt_decrypt() {
352 let _ = simple_logger::SimpleLogger::new()
353 .with_level(log::Level::Info.to_level_filter())
354 .init();
355
356 let plaintext = b"Hello world!Hello world!";
357 let current_plaintext = *plaintext;
358 let oracle = PaddingOracle::new(16, 1, oracle_fn);
359
360 let iv: Vec<u8> = [].to_vec();
361
362 let ciphertext = oracle.encrypt(&plaintext.to_vec(), &iv).unwrap();
363 let plaintext = oracle.decrypt(&ciphertext, &iv).unwrap();
364 assert_eq!(
365 current_plaintext.to_vec(),
366 unpad(plaintext[32..].to_vec(), 16).unwrap()
367 );
368 }
369
370 #[test]
371 fn test_decrypt() {
372 let _ = simple_logger::SimpleLogger::new()
373 .with_level(log::Level::Info.to_level_filter())
374 .init();
375
376 let key = hex!("000102030405060708090a0b0c0d0e0f");
377 let iv = hex!("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
378 let plaintext = b"Hello world!Hello world!";
379 let mut buffer = vec![0u8; plaintext.len() + (16 - plaintext.len() % 16) % 16];
381 let pos = plaintext.len();
383 buffer[..pos].copy_from_slice(plaintext);
384 let ciphertext = Aes128CbcEnc::new(&key.into(), &iv.into())
385 .encrypt_padded_mut::<Pkcs7>(&mut buffer, pos)
386 .unwrap();
387
388 let mut to_decrypt = iv.to_vec();
389 to_decrypt.append(&mut ciphertext.to_vec());
390
391 let iv: Vec<u8> = [].to_vec();
392 let oracle = PaddingOracle::new(16, 1, oracle_fn);
393 let decrypted = oracle.decrypt(&to_decrypt, &iv).unwrap();
394
395 assert_eq!(unpad(decrypted[32..].to_vec(), 16).unwrap(), plaintext);
396 }
397
398 #[test]
399 fn test_xor_data() {
400 let v1: Vec<u8> = vec![1, 0, 0, 1];
401 let v2: Vec<u8> = vec![1, 1];
402 let expected: Vec<u8> = vec![0, 1, 1, 0];
403
404 assert_eq!(xor_data(v1, v2), expected);
405 }
406
407 #[test]
408 fn test_aes_crypt() {
409 let key = hex!("000102030405060708090a0b0c0d0e0f");
410 let iv = hex!("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
411 let plaintext = b"Hello world!";
412 let mut buffer = vec![0u8; plaintext.len() + (16 - plaintext.len() % 16) % 16];
414 let pos = plaintext.len();
416 buffer[..pos].copy_from_slice(plaintext);
417 let ciphertext = Aes128CbcEnc::new(&key.into(), &iv.into())
418 .encrypt_padded_mut::<Pkcs7>(&mut buffer, pos)
419 .unwrap();
420
421 assert_eq!(ciphertext, hex!("1b7a4c403124ae2fb52bedc534d82fa8"));
422
423 let mut buf = ciphertext.to_vec();
425 let decrypted_ciphertext = Aes128CbcDec::new(&key.into(), &iv.into())
426 .decrypt_padded_mut::<Pkcs7>(&mut buf)
427 .unwrap();
428
429 assert_eq!(decrypted_ciphertext, plaintext);
430 }
431}