Up to 12
This commit is contained in:
parent
67a0e67a44
commit
9f86bb4b27
|
@ -6,6 +6,7 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
hex = "^0.3"
|
hex = "^0.3"
|
||||||
openssl = "^0.10"
|
|
||||||
base64 = "^0.2"
|
base64 = "^0.2"
|
||||||
typenum = "^1.0"
|
typenum = "^1.0"
|
||||||
|
openssl = "^0.10"
|
||||||
|
rand = "^0.7"
|
14
src/bytes.rs
14
src/bytes.rs
|
@ -149,6 +149,20 @@ impl Bytes {
|
||||||
self
|
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 {
|
pub fn pad_to_multiple(self, num: usize) -> Self {
|
||||||
let num = (num - (self.len() % num)) as u8;
|
let num = (num - (self.len() % num)) as u8;
|
||||||
self.pad(num)
|
self.pad(num)
|
||||||
|
|
138
src/crypto.rs
138
src/crypto.rs
|
@ -1,51 +1,121 @@
|
||||||
use crate::bytes::Bytes;
|
use crate::bytes::Bytes;
|
||||||
|
|
||||||
pub use openssl::symm::Mode;
|
pub use openssl::symm::{Cipher, Crypter, Mode};
|
||||||
|
|
||||||
pub struct Aes {
|
pub struct Aes {
|
||||||
key: Vec<u8>,
|
key: Vec<u8>,
|
||||||
|
pad: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Aes {
|
impl Aes {
|
||||||
const BLOCK_SIZE: usize = 16;
|
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();
|
let len = key.len();
|
||||||
if len == 16 || len == 24 || len == 32 {
|
if len == 16 || len == 24 || len == 32 {
|
||||||
return Some(Aes { key: key.to_vec() });
|
return Some(Aes {
|
||||||
|
key: key.to_vec(),
|
||||||
|
pad,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cipher(&self) -> openssl::symm::Cipher {
|
pub fn cbc(&self, data: Vec<u8>, iv: &[u8], mode: Mode) -> Option<Vec<u8>> {
|
||||||
match self.key.len() {
|
if (!self.pad) && (data.len() % Self::BLOCK_SIZE != 0) {
|
||||||
16 => Some(openssl::symm::Cipher::aes_128_ecb()),
|
return None;
|
||||||
24 => Some(openssl::symm::Cipher::aes_192_ecb()),
|
|
||||||
32 => Some(openssl::symm::Cipher::aes_256_ecb()),
|
|
||||||
_ => None,
|
|
||||||
}
|
}
|
||||||
.unwrap()
|
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 {
|
iv_.clone_from_slice(iv);
|
||||||
let cipher = self.cipher();
|
let mut iv = iv_;
|
||||||
openssl::symm::Crypter::new(cipher, mode, &self.key, None).unwrap()
|
|
||||||
|
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>> {
|
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;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut crypter = self.crypter(mode);
|
let mut crypter = self.crypter(mode);
|
||||||
let mut output_buffer = [0u8; 2 * Self::BLOCK_SIZE];
|
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) {
|
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]);
|
chunk.copy_from_slice(&output_buffer[0..Self::BLOCK_SIZE]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let data = self.maybe_unpad(data, mode);
|
||||||
Some(data)
|
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]) {
|
fn xor(a: &mut [u8], b: &[u8]) {
|
||||||
for (l, r) in a.iter_mut().zip(b.iter()) {
|
for (l, r) in a.iter_mut().zip(b.iter()) {
|
||||||
*l = *l ^ r;
|
*l = *l ^ r;
|
||||||
|
@ -57,40 +127,4 @@ impl Aes {
|
||||||
*t = l ^ r;
|
*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())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
97
src/main.rs
97
src/main.rs
|
@ -2,8 +2,9 @@ mod bytes;
|
||||||
mod crypto;
|
mod crypto;
|
||||||
mod io;
|
mod io;
|
||||||
|
|
||||||
use bytes::Bytes;
|
use crate::bytes::Bytes;
|
||||||
use openssl::symm::Mode;
|
use openssl::symm::Mode;
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
fn q01() {
|
fn q01() {
|
||||||
println!("Running q01");
|
println!("Running q01");
|
||||||
|
@ -90,7 +91,7 @@ fn q06() {
|
||||||
|
|
||||||
let key = input.find_best_xor_cipher();
|
let key = input.find_best_xor_cipher();
|
||||||
let _output = input.xor_repeating(&key).to_string().unwrap();
|
let _output = input.xor_repeating(&key).to_string().unwrap();
|
||||||
// println!(" {}", output);
|
// println!(" {}", _output.replace("\n", "\n "));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn q07() {
|
fn q07() {
|
||||||
|
@ -100,11 +101,12 @@ fn q07() {
|
||||||
let input = Bytes::from_base64(&input);
|
let input = Bytes::from_base64(&input);
|
||||||
let key = Bytes::from_string("YELLOW SUBMARINE");
|
let key = Bytes::from_string("YELLOW SUBMARINE");
|
||||||
let _output = Bytes {
|
let _output = Bytes {
|
||||||
data: crypto::Aes::new(&key).unwrap()
|
data: crypto::Aes::new(&key, false)
|
||||||
|
.unwrap()
|
||||||
.ecb(input.into(), Mode::Decrypt)
|
.ecb(input.into(), Mode::Decrypt)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
};
|
};
|
||||||
// println!(" {}", _output.to_string().unwrap());
|
// println!(" {}", _output.to_string().unwrap().replace("\n", "\n "));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn q08() {
|
fn q08() {
|
||||||
|
@ -152,8 +154,89 @@ fn q10() {
|
||||||
let key = b"YELLOW SUBMARINE";
|
let key = b"YELLOW SUBMARINE";
|
||||||
let iv = [0u8; 16];
|
let iv = [0u8; 16];
|
||||||
|
|
||||||
let output = crypto::Aes::new(key).unwrap().cbc(input.into(), &iv, Mode::Decrypt);
|
let _output = crypto::Aes::new(key, false)
|
||||||
println!("{}", Bytes::from(output.unwrap()).to_string().unwrap());
|
.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() {
|
fn main() {
|
||||||
|
@ -167,4 +250,6 @@ fn main() {
|
||||||
q08();
|
q08();
|
||||||
q09();
|
q09();
|
||||||
q10();
|
q10();
|
||||||
|
q11();
|
||||||
|
q12();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user