Up to 12
This commit is contained in:
parent
67a0e67a44
commit
9f86bb4b27
|
@ -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"
|
14
src/bytes.rs
14
src/bytes.rs
|
@ -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)
|
||||
|
|
138
src/crypto.rs
138
src/crypto.rs
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
97
src/main.rs
97
src/main.rs
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user