Finish challenge 25 and update License
parent
5158c16d56
commit
1eb76f52b1
28
LICENSE
28
LICENSE
|
@ -1,11 +1,25 @@
|
||||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
GLWT(Good Luck With That) Public License
|
||||||
Version 2, December 2004
|
Copyright (c) Everyone, except Author
|
||||||
|
|
||||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
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
|
The author has absolutely no clue what the code in this project does.
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
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.
|
||||||
|
|
|
@ -148,11 +148,7 @@ impl Bytes {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn xor(Bytes(a): &Bytes, Bytes(b): &Bytes) -> Bytes {
|
pub fn xor(Bytes(a): &Bytes, Bytes(b): &Bytes) -> Bytes {
|
||||||
Bytes(
|
Bytes(crate::utils::xor(a, b))
|
||||||
Iterator::zip(a.iter(), b.iter())
|
|
||||||
.map(|z| *(z.0) ^ *(z.1))
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn xor_byte(Bytes(a): &Bytes, byte: u8) -> Bytes {
|
pub fn xor_byte(Bytes(a): &Bytes, byte: u8) -> Bytes {
|
||||||
|
|
10
src/cbc.rs
10
src/cbc.rs
|
@ -1,12 +1,6 @@
|
||||||
use crate::bytes::Bytes;
|
use crate::bytes::Bytes;
|
||||||
use openssl::symm;
|
use openssl::symm;
|
||||||
|
|
||||||
fn xor(a: &[u8], b: &[u8]) -> Vec<u8> {
|
|
||||||
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<u8> {
|
pub fn enrypt_aes_128_ecb_block(key: &[u8], data: &[u8]) -> Vec<u8> {
|
||||||
let cipher_type = symm::Cipher::aes_128_ecb();
|
let cipher_type = symm::Cipher::aes_128_ecb();
|
||||||
let block_size = cipher_type.block_size();
|
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<u8> = vec![];
|
let mut result: Vec<u8> = vec![];
|
||||||
let mut prev_cipher: Vec<u8> = iv.to_vec(); // first xor input is IV
|
let mut prev_cipher: Vec<u8> = iv.to_vec(); // first xor input is IV
|
||||||
for data in data.chunks(block_size) {
|
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);
|
let mut cipher = enrypt_aes_128_ecb_block(key, &xored);
|
||||||
prev_cipher = cipher.to_vec(); // cipher is input for next xor
|
prev_cipher = cipher.to_vec(); // cipher is input for next xor
|
||||||
result.append(&mut cipher);
|
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<u8> = iv.to_vec(); // first xor input is IV
|
let mut prev_cipher: Vec<u8> = iv.to_vec(); // first xor input is IV
|
||||||
for cipher in data.chunks(block_size) {
|
for cipher in data.chunks(block_size) {
|
||||||
let xored = decrypt_aes_128_ecb_block(key, &cipher);
|
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());
|
result.extend(data.to_vec());
|
||||||
prev_cipher = cipher.to_vec();
|
prev_cipher = cipher.to_vec();
|
||||||
}
|
}
|
||||||
|
|
11
src/ctr.rs
11
src/ctr.rs
|
@ -1,13 +1,6 @@
|
||||||
use crate::bytes::Bytes;
|
use crate::bytes::Bytes;
|
||||||
use crate::cbc;
|
|
||||||
use openssl::symm;
|
use openssl::symm;
|
||||||
|
|
||||||
fn xor(a: &Vec<u8>, b: &Vec<u8>) -> Vec<u8> {
|
|
||||||
Iterator::zip(a.iter(), b.iter())
|
|
||||||
.map(|z| *(z.0) ^ *(z.1))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn encrypt(key: &Bytes, nonce: u64, data: &Bytes) -> Bytes {
|
pub fn encrypt(key: &Bytes, nonce: u64, data: &Bytes) -> Bytes {
|
||||||
decrypt(key, nonce, data)
|
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) {
|
for cipher in data.chunks(block_size) {
|
||||||
let mut keyinput = nonce.to_le_bytes().to_vec();
|
let mut keyinput = nonce.to_le_bytes().to_vec();
|
||||||
keyinput.append(&mut counter.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 keystream = crate::cbc::enrypt_aes_128_ecb_block(key, &keyinput);
|
||||||
let mut data = xor(&keystream, &cipher.to_vec());
|
let mut data = crate::utils::xor(&keystream, &cipher.to_vec());
|
||||||
result.append(&mut data);
|
result.append(&mut data);
|
||||||
counter += 1;
|
counter += 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,8 @@ fn main() {
|
||||||
set3::challenge23();
|
set3::challenge23();
|
||||||
set3::challenge24();
|
set3::challenge24();
|
||||||
set4::challenge25();
|
set4::challenge25();
|
||||||
|
set4::challenge26();
|
||||||
} else {
|
} else {
|
||||||
set4::challenge25();
|
set4::challenge26();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
44
src/set4.rs
44
src/set4.rs
|
@ -1,9 +1,47 @@
|
||||||
use crate::{bytes::Bytes, utils};
|
use crate::{bytes::Bytes, ctr, utils};
|
||||||
|
|
||||||
pub fn challenge25() {
|
pub fn challenge25() {
|
||||||
let cipher = utils::read_base64("data/25.txt");
|
let cipher = utils::read_base64("data/25.txt");
|
||||||
let key = Bytes::from_utf8("YELLOW SUBMARINE");
|
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<u8>) -> 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");
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,3 +39,9 @@ pub fn read_hex_lines(path: &str) -> Vec<Bytes> {
|
||||||
.map(|line| Bytes::from_hex(&line.unwrap()))
|
.map(|line| Bytes::from_hex(&line.unwrap()))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn xor(a: &[u8], b: &[u8]) -> Vec<u8> {
|
||||||
|
Iterator::zip(a.iter(), b.iter())
|
||||||
|
.map(|z| *(z.0) ^ *(z.1))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue