diff --git a/LICENSE b/LICENSE index 7a3094a..a0f7ec4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,11 +1,25 @@ -DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -Version 2, December 2004 + GLWT(Good Luck With That) Public License + Copyright (c) Everyone, except Author -Copyright (C) 2004 Sam Hocevar +Everyone is permitted to copy, distribute, modify, merge, sell, publish, +sublicense or whatever they want with this software but at their OWN RISK. -Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. + Preamble -DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +The author has absolutely no clue what the code in this project does. +It might just work or not, there is no third option. - 0. You just DO WHAT THE FUCK YOU WANT TO. + + GOOD LUCK WITH THAT PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION, AND MODIFICATION + + 0. You just DO WHATEVER YOU WANT TO as long as you NEVER LEAVE A +TRACE TO TRACK THE AUTHOR of the original product to blame for or hold +responsible. + +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +Good luck and Godspeed. diff --git a/src/bytes.rs b/src/bytes.rs index 440ddcf..7d6d061 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -148,11 +148,7 @@ impl Bytes { } pub fn xor(Bytes(a): &Bytes, Bytes(b): &Bytes) -> Bytes { - Bytes( - Iterator::zip(a.iter(), b.iter()) - .map(|z| *(z.0) ^ *(z.1)) - .collect(), - ) + Bytes(crate::utils::xor(a, b)) } pub fn xor_byte(Bytes(a): &Bytes, byte: u8) -> Bytes { diff --git a/src/cbc.rs b/src/cbc.rs index efa51da..187add0 100644 --- a/src/cbc.rs +++ b/src/cbc.rs @@ -1,12 +1,6 @@ use crate::bytes::Bytes; use openssl::symm; -fn xor(a: &[u8], b: &[u8]) -> Vec { - Iterator::zip(a.iter(), b.iter()) - .map(|z| *(z.0) ^ *(z.1)) - .collect() -} - pub fn enrypt_aes_128_ecb_block(key: &[u8], data: &[u8]) -> Vec { let cipher_type = symm::Cipher::aes_128_ecb(); let block_size = cipher_type.block_size(); @@ -35,7 +29,7 @@ pub fn encrypt(Bytes(key): &Bytes, Bytes(iv): &Bytes, Bytes(data): &Bytes) -> By let mut result: Vec = vec![]; let mut prev_cipher: Vec = iv.to_vec(); // first xor input is IV for data in data.chunks(block_size) { - let xored = xor(&prev_cipher, data); + let xored = crate::utils::xor(&prev_cipher, data); let mut cipher = enrypt_aes_128_ecb_block(key, &xored); prev_cipher = cipher.to_vec(); // cipher is input for next xor result.append(&mut cipher); @@ -51,7 +45,7 @@ pub fn decrypt(Bytes(key): &Bytes, Bytes(iv): &Bytes, Bytes(data): &Bytes) -> By let mut prev_cipher: Vec = iv.to_vec(); // first xor input is IV for cipher in data.chunks(block_size) { let xored = decrypt_aes_128_ecb_block(key, &cipher); - let data = xor(&xored, &prev_cipher); + let data = crate::utils::xor(&xored, &prev_cipher); result.extend(data.to_vec()); prev_cipher = cipher.to_vec(); } diff --git a/src/ctr.rs b/src/ctr.rs index 603b0d4..2cba07d 100644 --- a/src/ctr.rs +++ b/src/ctr.rs @@ -1,13 +1,6 @@ use crate::bytes::Bytes; -use crate::cbc; use openssl::symm; -fn xor(a: &Vec, b: &Vec) -> Vec { - Iterator::zip(a.iter(), b.iter()) - .map(|z| *(z.0) ^ *(z.1)) - .collect() -} - pub fn encrypt(key: &Bytes, nonce: u64, data: &Bytes) -> Bytes { decrypt(key, nonce, data) } @@ -20,8 +13,8 @@ pub fn decrypt(Bytes(key): &Bytes, nonce: u64, Bytes(data): &Bytes) -> Bytes { for cipher in data.chunks(block_size) { let mut keyinput = nonce.to_le_bytes().to_vec(); keyinput.append(&mut counter.to_le_bytes().to_vec()); - let keystream = cbc::enrypt_aes_128_ecb_block(key, &keyinput); - let mut data = xor(&keystream, &cipher.to_vec()); + let keystream = crate::cbc::enrypt_aes_128_ecb_block(key, &keyinput); + let mut data = crate::utils::xor(&keystream, &cipher.to_vec()); result.append(&mut data); counter += 1; } diff --git a/src/main.rs b/src/main.rs index a01d7ab..d1861cc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,7 +40,8 @@ fn main() { set3::challenge23(); set3::challenge24(); set4::challenge25(); + set4::challenge26(); } else { - set4::challenge25(); + set4::challenge26(); } } diff --git a/src/set4.rs b/src/set4.rs index f3aeb8e..820a56f 100644 --- a/src/set4.rs +++ b/src/set4.rs @@ -1,9 +1,47 @@ -use crate::{bytes::Bytes, utils}; +use crate::{bytes::Bytes, ctr, utils}; pub fn challenge25() { let cipher = utils::read_base64("data/25.txt"); let key = Bytes::from_utf8("YELLOW SUBMARINE"); - let _cleartext = crate::ecb::decrypt(&key, &cipher); + let plaintext = crate::ecb::decrypt(&key, &cipher); - println!("[xxxx] Challenge 25: wip"); + let key = Bytes::random(16); + let nonce: u64 = 0; // otherwise edit would require the nonce too? + + // Now, write the code that allows you to "seek" into the ciphertext, + // decrypt, and re-encrypt with different plaintext. Expose this as a + // function, like, "edit(ciphertext, key, offset, newtext)". + fn edit(ciphertext: &Bytes, key: &Bytes, offset: usize, newtext: &Vec) -> Bytes { + let mut plaintext = ctr::decrypt(key, 0, ciphertext); + if offset + newtext.len() > plaintext.len() { + panic!("challenge25 - edit - out of bounds"); + } + + for i in 0..newtext.len() { + plaintext.0[offset + i] = newtext[i]; + } + ctr::encrypt(key, 0, &plaintext) + } + + // Imagine the "edit" function was exposed to attackers by means of an API + // call that didn't reveal the key or the original plaintext; the attacker + // has the ciphertext and controls the offset and "new text". Recover the + // original plaintext. + let ciphertext = ctr::encrypt(&key, nonce, &plaintext); + let newtext = vec![b'a'; ciphertext.len()]; + let cipher_newtext = edit(&ciphertext, &key, 0, &newtext); + let keystream = crate::utils::xor(&newtext, &cipher_newtext.0); + let recovered_plaintext = Bytes(crate::utils::xor(&keystream, &ciphertext.0)); + assert_eq!(plaintext, recovered_plaintext); + + println!("[okay] Challenge 25: recovered AES CTR plaintext via edit"); + + // A folkloric supposed benefit of CTR mode is the ability to easily "seek + // forward" into the ciphertext; to access byte N of the ciphertext, all you + // need to be able to do is generate byte N of the keystream. Imagine if + // you'd relied on that advice to, say, encrypt a disk. +} + +pub fn challenge26() { + println!("[xxxx] Challenge 26: TBD"); } diff --git a/src/utils.rs b/src/utils.rs index 8d4c83c..51aaf96 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -39,3 +39,9 @@ pub fn read_hex_lines(path: &str) -> Vec { .map(|line| Bytes::from_hex(&line.unwrap())) .collect() } + +pub fn xor(a: &[u8], b: &[u8]) -> Vec { + Iterator::zip(a.iter(), b.iter()) + .map(|z| *(z.0) ^ *(z.1)) + .collect() +}