This commit is contained in:
Lynn Ochs 2019-09-02 23:28:35 +02:00
parent 67a0e67a44
commit 9f86bb4b27
4 changed files with 193 additions and 59 deletions

View File

@ -6,6 +6,7 @@ edition = "2018"
[dependencies]
hex = "^0.3"
openssl = "^0.10"
base64 = "^0.2"
typenum = "^1.0"
openssl = "^0.10"
rand = "^0.7"

View File

@ -149,6 +149,20 @@ impl Bytes {
self
}
pub fn unpad(mut self) -> Option<Self> {
let len = self.len();
let last_byte = self.data[len-1];
let end_start = len - (last_byte as usize);
match self.data.iter().skip(end_start).all(|x| *x == last_byte) {
true => {
self.data.resize(end_start, 0u8);
Some(self)
},
false => None,
}
}
pub fn pad_to_multiple(self, num: usize) -> Self {
let num = (num - (self.len() % num)) as u8;
self.pad(num)

View File

@ -1,51 +1,121 @@
use crate::bytes::Bytes;
pub use openssl::symm::Mode;
pub use openssl::symm::{Cipher, Crypter, Mode};
pub struct Aes {
key: Vec<u8>,
pad: bool,
}
impl Aes {
const BLOCK_SIZE: usize = 16;
pub fn new(key: &[u8]) -> Option<Aes> {
pub fn new(key: &[u8], pad: bool) -> Option<Aes> {
let len = key.len();
if len == 16 || len == 24 || len == 32 {
return Some(Aes { key: key.to_vec() });
return Some(Aes {
key: key.to_vec(),
pad,
});
};
None
}
fn cipher(&self) -> openssl::symm::Cipher {
match self.key.len() {
16 => Some(openssl::symm::Cipher::aes_128_ecb()),
24 => Some(openssl::symm::Cipher::aes_192_ecb()),
32 => Some(openssl::symm::Cipher::aes_256_ecb()),
_ => None,
}
.unwrap()
pub fn cbc(&self, data: Vec<u8>, iv: &[u8], mode: Mode) -> Option<Vec<u8>> {
if (!self.pad) && (data.len() % Self::BLOCK_SIZE != 0) {
return None;
}
let mut data = self.maybe_pad(data, mode);
let mut iv_ = [0u8; Self::BLOCK_SIZE];
let mut output_buffer = [0u8; 2 * Self::BLOCK_SIZE];
fn crypter(&self, mode: openssl::symm::Mode) -> openssl::symm::Crypter {
let cipher = self.cipher();
openssl::symm::Crypter::new(cipher, mode, &self.key, None).unwrap()
iv_.clone_from_slice(iv);
let mut iv = iv_;
let mut crypter = self.crypter(mode);
for chunk in data.chunks_exact_mut(Self::BLOCK_SIZE) {
match mode {
Mode::Decrypt => {
let mut old_chunk = [0u8; Self::BLOCK_SIZE];
old_chunk.copy_from_slice(chunk);
Self::update(&mut crypter, chunk, &mut output_buffer);
Self::xor_into(&output_buffer, &iv, chunk);
iv.clone_from_slice(&old_chunk);
}
Mode::Encrypt => {
Self::xor(chunk, &iv);
Self::update(&mut crypter, chunk, &mut output_buffer);
chunk.copy_from_slice(&output_buffer[0..Self::BLOCK_SIZE]);
iv.copy_from_slice(chunk);
}
}
}
let data = self.maybe_unpad(data, mode);
Some(data.clone())
}
pub fn ecb(&self, mut data: Vec<u8>, mode: Mode) -> Option<Vec<u8>> {
if data.len() % Self::BLOCK_SIZE != 0 {
if (!self.pad) && (data.len() % Self::BLOCK_SIZE != 0) {
return None;
}
let mut crypter = self.crypter(mode);
let mut output_buffer = [0u8; 2 * Self::BLOCK_SIZE];
let mut data = self.maybe_pad(data, mode);
for chunk in data.chunks_exact_mut(Self::BLOCK_SIZE) {
crypter.update(chunk, &mut output_buffer);
Self::update(&mut crypter, chunk, &mut output_buffer);
chunk.copy_from_slice(&output_buffer[0..Self::BLOCK_SIZE]);
}
let data = self.maybe_unpad(data, mode);
Some(data)
}
fn cipher(&self) -> Cipher {
match self.key.len() {
16 => Some(Cipher::aes_128_ecb()),
24 => Some(Cipher::aes_192_ecb()),
32 => Some(Cipher::aes_256_ecb()),
_ => None,
}
.unwrap()
}
fn crypter(&self, mode: Mode) -> Crypter {
let cipher = self.cipher();
let mut crypter = Crypter::new(cipher, mode, &self.key, None).unwrap();
crypter.pad(false);
crypter
}
fn maybe_pad(&self, data: Vec<u8>, mode: Mode) -> Vec<u8> {
match (self.pad, mode) {
(true, Mode::Encrypt) => Bytes { data }.pad_to_multiple(Self::BLOCK_SIZE).into(),
_ => data,
}
}
fn maybe_unpad(&self, data: Vec<u8>, mode: Mode) -> Vec<u8> {
match (self.pad, mode) {
(true, Mode::Decrypt) => Bytes { data }.unpad().unwrap().into(),
_ => data,
}
}
fn update(crypter: &mut Crypter, chunk: &[u8], output: &mut [u8]) {
assert!(
Self::BLOCK_SIZE
== crypter
.update(chunk, output)
.expect("Error while updating crypter")
);
}
fn xor(a: &mut [u8], b: &[u8]) {
for (l, r) in a.iter_mut().zip(b.iter()) {
*l = *l ^ r;
@ -57,40 +127,4 @@ impl Aes {
*t = l ^ r;
}
}
pub fn cbc(&self, data: Vec<u8>, iv: &[u8], mode: Mode) -> Option<Vec<u8>> {
let data = crate::bytes::Bytes::from(data);
let mut data = data.pad_to_multiple(Self::BLOCK_SIZE);
let mut crypter = self.crypter(mode);
let mut iv_ = [0u8; Self::BLOCK_SIZE];
let mut output_buffer = [0u8; 2 * Self::BLOCK_SIZE];
iv_.clone_from_slice(iv);
let mut iv = iv_;
for chunk in data.chunks_exact_mut(Self::BLOCK_SIZE) {
match mode {
Mode::Decrypt => {
let mut old_chunk = [0u8; Self::BLOCK_SIZE];
old_chunk.copy_from_slice(chunk);
let len = crypter.update(chunk, &mut output_buffer);
Self::xor_into(&output_buffer, &iv, chunk);
println!("IV: {:?}\nIB: {:?}\nOB: {:?} ({:?})\n\n", iv, old_chunk, chunk, len);
iv.clone_from_slice(&old_chunk);
}
Mode::Encrypt => {
Self::xor(chunk, &iv);
crypter.update(chunk, &mut output_buffer);
chunk.copy_from_slice(&output_buffer[0..Self::BLOCK_SIZE]);
iv.copy_from_slice(chunk);
}
}
}
println!("{:?}", data);
Some(data.data.clone())
}
}

View File

@ -2,8 +2,9 @@ mod bytes;
mod crypto;
mod io;
use bytes::Bytes;
use crate::bytes::Bytes;
use openssl::symm::Mode;
use rand::Rng;
fn q01() {
println!("Running q01");
@ -90,7 +91,7 @@ fn q06() {
let key = input.find_best_xor_cipher();
let _output = input.xor_repeating(&key).to_string().unwrap();
// println!(" {}", output);
// println!(" {}", _output.replace("\n", "\n "));
}
fn q07() {
@ -100,11 +101,12 @@ fn q07() {
let input = Bytes::from_base64(&input);
let key = Bytes::from_string("YELLOW SUBMARINE");
let _output = Bytes {
data: crypto::Aes::new(&key).unwrap()
data: crypto::Aes::new(&key, false)
.unwrap()
.ecb(input.into(), Mode::Decrypt)
.unwrap(),
};
// println!(" {}", _output.to_string().unwrap());
// println!(" {}", _output.to_string().unwrap().replace("\n", "\n "));
}
fn q08() {
@ -152,8 +154,89 @@ fn q10() {
let key = b"YELLOW SUBMARINE";
let iv = [0u8; 16];
let output = crypto::Aes::new(key).unwrap().cbc(input.into(), &iv, Mode::Decrypt);
println!("{}", Bytes::from(output.unwrap()).to_string().unwrap());
let _output = crypto::Aes::new(key, false)
.unwrap()
.cbc(input.into(), &iv, Mode::Decrypt);
// println!("{}", Bytes::from(_output.unwrap()).to_string().unwrap().replace("\n", "\n "));
}
fn q11() {
println!("Running q11");
let black_box = |mut data: Vec<u8>| -> (bool, Vec<u8>) {
let mut rng = rand::thread_rng();
let dist = rand::distributions::Standard;
let key: Vec<u8> = rng.sample_iter(&dist).take(16).collect();
let iv: Vec<u8> = rng.sample_iter(&dist).take(16).collect();
let aes = crypto::Aes::new(&key, true).unwrap();
let mut start: Vec<u8> = rng.sample_iter(&dist).take(rng.gen_range(5,11)).collect();
let mut end: Vec<u8> = rng.sample_iter(&dist).take(rng.gen_range(5,11)).collect();
start.append(&mut data);
start.append(&mut end);
match rand::random() {
false => (false, aes.cbc(start, &iv, Mode::Encrypt).unwrap()),
true => (true, aes.ecb(start, Mode::Encrypt).unwrap()),
}
};
let oracle = |data: &Vec<u8>| -> bool {
data[16..32] == data[32..48]
};
for i in 0..128 {
let data = [0u8;64];
let (ecb, data) = black_box(data.to_vec());
assert!(ecb == oracle(&data));
}
}
fn q12()
{
println!("Running q12");
let key: Vec<u8> = rand::thread_rng().sample_iter(rand::distributions::Standard).take(16).collect();
let plaintext: Vec<u8> = Bytes::from_base64("Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkgaGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBqdXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUgYnkK").into();
let aes = crate::crypto::Aes::new(&key, true).unwrap();
let blackbox = |mut data: Vec<u8>| -> Vec<u8> {
data.append(&mut plaintext.clone());
aes.ecb(data, Mode::Encrypt).unwrap()
};
let starting_size = blackbox(Vec::new()).len();
let (first_increment, next_size) = (0..).map(|x:usize| (x, blackbox(std::iter::repeat(0u8).take(x).collect()).len())).find(|(i,x)| *x != starting_size).unwrap();
let block_size = next_size - starting_size;
println!(" Block size is {}", block_size);
assert!(block_size == 16);
let long_block = blackbox(std::iter::repeat(0u8).take(128).collect());
let using_ecb = long_block[48..64] == long_block[64..80];
println!(" Using ECB: {}", using_ecb);
assert!(using_ecb);
println!(" First size increment at {}", first_increment);
let data_length = starting_size - first_increment;
let mut known: Vec<u8> = Vec::with_capacity(data_length);
println!(" Data length: {}", data_length);
for byte_index in 0..data_length
{
let nulls: Vec<u8> = std::iter::repeat(0u8).take(starting_size - known.len() - 1).collect();
let target_block = &blackbox(nulls.clone())[0..starting_size];
let mut found = false;
'byteiter: for b in 0u8..=255u8 {
let this_block = &blackbox(nulls.iter().chain(known.iter()).chain(std::iter::once(&b)).cloned().take(starting_size).collect())[0..starting_size];
if this_block == target_block
{
known.push(b);
found = true;
break 'byteiter;
}
}
assert!(found);
}
// println!(" {}", String::from_utf8(known).unwrap().replace("\n", "\n "));
}
fn main() {
@ -167,4 +250,6 @@ fn main() {
q08();
q09();
q10();
q11();
q12();
}