Created
August 28, 2017 14:12
-
-
Save bennofs/dc8d3a845bca0f5888192b50c19e669f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::fmt; | |
use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign}; | |
macro_rules! forward_ref_binop { | |
($imp:ident, $method:ident, $imp_assign:ident, $method_assign:ident, $u:ty) => { | |
impl $imp<$u> for $u { | |
type Output = $u; | |
fn $method(mut self, other: $u) -> $u { | |
self.$method_assign(other); | |
self | |
} | |
} | |
impl<'a> $imp<$u> for &'a $u { | |
type Output = <$u as $imp<$u>>::Output; | |
#[inline] | |
fn $method(self, other: $u) -> <$u as $imp<$u>>::Output { | |
$imp::$method(*self, other) | |
} | |
} | |
impl<'a> $imp<&'a $u> for $u { | |
type Output = <$u as $imp<$u>>::Output; | |
#[inline] | |
fn $method(self, other: &'a $u) -> <$u as $imp<$u>>::Output { | |
$imp::$method(self, *other) | |
} | |
} | |
impl<'a, 'b> $imp<&'a $u> for &'b $u { | |
type Output = <$u as $imp<$u>>::Output; | |
#[inline] | |
fn $method(self, other: &'a $u) -> <$u as $imp<$u>>::Output { | |
$imp::$method(*self, *other) | |
} | |
} | |
impl<'a> $imp_assign<&'a $u> for $u { | |
fn $method_assign(&mut self, other: &'a $u) { | |
self.$method_assign(*other); | |
} | |
} | |
impl<'a> $imp_assign<&'a mut $u> for $u { | |
fn $method_assign(&mut self, other: &'a mut $u) { | |
self.$method_assign(*other); | |
} | |
} | |
impl<'a, 'b> $imp_assign<&'a mut $u> for &'b mut $u { | |
fn $method_assign(&mut self, other: &'a mut $u) { | |
(*self).$method_assign(*other); | |
} | |
} | |
impl<'a> $imp_assign<$u> for &'a mut $u { | |
fn $method_assign(&mut self, other: $u) { | |
(*self).$method_assign(other); | |
} | |
} | |
} | |
} | |
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] | |
pub struct G8(pub u8); | |
impl fmt::Debug for G8 { | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
write!(f, "G8({:#02x})", self.0) | |
} | |
} | |
impl fmt::Display for G8 { | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
write!(f, "{:#02x}", self.0) | |
} | |
} | |
impl From<u8> for G8 { | |
fn from(v: u8) -> G8 { G8(v) } | |
} | |
impl From<G8> for u8 { | |
fn from(v: G8) -> u8 { v.0 } | |
} | |
impl AddAssign for G8 { | |
fn add_assign(&mut self, other: G8) { | |
self.0 ^= other.0; | |
} | |
} | |
forward_ref_binop! { Add, add, AddAssign, add_assign, G8 } | |
impl SubAssign for G8 { | |
fn sub_assign(&mut self, other: G8) { | |
self.0 ^= other.0; | |
} | |
} | |
forward_ref_binop! { Sub, sub, SubAssign, sub_assign, G8 } | |
const EXP_TABLE: [u8; 256] = [ | |
0x01, 0x03, 0x05, 0x0f, 0x11, 0x33, 0x55, 0xff, 0x1a, 0x2e, 0x72, 0x96, 0xa1, 0xf8, 0x13, 0x35, | |
0x5f, 0xe1, 0x38, 0x48, 0xd8, 0x73, 0x95, 0xa4, 0xf7, 0x02, 0x06, 0x0a, 0x1e, 0x22, 0x66, 0xaa, | |
0xe5, 0x34, 0x5c, 0xe4, 0x37, 0x59, 0xeb, 0x26, 0x6a, 0xbe, 0xd9, 0x70, 0x90, 0xab, 0xe6, 0x31, | |
0x53, 0xf5, 0x04, 0x0c, 0x14, 0x3c, 0x44, 0xcc, 0x4f, 0xd1, 0x68, 0xb8, 0xd3, 0x6e, 0xb2, 0xcd, | |
0x4c, 0xd4, 0x67, 0xa9, 0xe0, 0x3b, 0x4d, 0xd7, 0x62, 0xa6, 0xf1, 0x08, 0x18, 0x28, 0x78, 0x88, | |
0x83, 0x9e, 0xb9, 0xd0, 0x6b, 0xbd, 0xdc, 0x7f, 0x81, 0x98, 0xb3, 0xce, 0x49, 0xdb, 0x76, 0x9a, | |
0xb5, 0xc4, 0x57, 0xf9, 0x10, 0x30, 0x50, 0xf0, 0x0b, 0x1d, 0x27, 0x69, 0xbb, 0xd6, 0x61, 0xa3, | |
0xfe, 0x19, 0x2b, 0x7d, 0x87, 0x92, 0xad, 0xec, 0x2f, 0x71, 0x93, 0xae, 0xe9, 0x20, 0x60, 0xa0, | |
0xfb, 0x16, 0x3a, 0x4e, 0xd2, 0x6d, 0xb7, 0xc2, 0x5d, 0xe7, 0x32, 0x56, 0xfa, 0x15, 0x3f, 0x41, | |
0xc3, 0x5e, 0xe2, 0x3d, 0x47, 0xc9, 0x40, 0xc0, 0x5b, 0xed, 0x2c, 0x74, 0x9c, 0xbf, 0xda, 0x75, | |
0x9f, 0xba, 0xd5, 0x64, 0xac, 0xef, 0x2a, 0x7e, 0x82, 0x9d, 0xbc, 0xdf, 0x7a, 0x8e, 0x89, 0x80, | |
0x9b, 0xb6, 0xc1, 0x58, 0xe8, 0x23, 0x65, 0xaf, 0xea, 0x25, 0x6f, 0xb1, 0xc8, 0x43, 0xc5, 0x54, | |
0xfc, 0x1f, 0x21, 0x63, 0xa5, 0xf4, 0x07, 0x09, 0x1b, 0x2d, 0x77, 0x99, 0xb0, 0xcb, 0x46, 0xca, | |
0x45, 0xcf, 0x4a, 0xde, 0x79, 0x8b, 0x86, 0x91, 0xa8, 0xe3, 0x3e, 0x42, 0xc6, 0x51, 0xf3, 0x0e, | |
0x12, 0x36, 0x5a, 0xee, 0x29, 0x7b, 0x8d, 0x8c, 0x8f, 0x8a, 0x85, 0x94, 0xa7, 0xf2, 0x0d, 0x17, | |
0x39, 0x4b, 0xdd, 0x7c, 0x84, 0x97, 0xa2, 0xfd, 0x1c, 0x24, 0x6c, 0xb4, 0xc7, 0x52, 0xf6, 0x01, | |
]; | |
const LOG_TABLE: [u8; 256] = [ | |
0x00, 0x00, 0x19, 0x01, 0x32, 0x02, 0x1a, 0xc6, 0x4b, 0xc7, 0x1b, 0x68, 0x33, 0xee, 0xdf, 0x03, | |
0x64, 0x04, 0xe0, 0x0e, 0x34, 0x8d, 0x81, 0xef, 0x4c, 0x71, 0x08, 0xc8, 0xf8, 0x69, 0x1c, 0xc1, | |
0x7d, 0xc2, 0x1d, 0xb5, 0xf9, 0xb9, 0x27, 0x6a, 0x4d, 0xe4, 0xa6, 0x72, 0x9a, 0xc9, 0x09, 0x78, | |
0x65, 0x2f, 0x8a, 0x05, 0x21, 0x0f, 0xe1, 0x24, 0x12, 0xf0, 0x82, 0x45, 0x35, 0x93, 0xda, 0x8e, | |
0x96, 0x8f, 0xdb, 0xbd, 0x36, 0xd0, 0xce, 0x94, 0x13, 0x5c, 0xd2, 0xf1, 0x40, 0x46, 0x83, 0x38, | |
0x66, 0xdd, 0xfd, 0x30, 0xbf, 0x06, 0x8b, 0x62, 0xb3, 0x25, 0xe2, 0x98, 0x22, 0x88, 0x91, 0x10, | |
0x7e, 0x6e, 0x48, 0xc3, 0xa3, 0xb6, 0x1e, 0x42, 0x3a, 0x6b, 0x28, 0x54, 0xfa, 0x85, 0x3d, 0xba, | |
0x2b, 0x79, 0x0a, 0x15, 0x9b, 0x9f, 0x5e, 0xca, 0x4e, 0xd4, 0xac, 0xe5, 0xf3, 0x73, 0xa7, 0x57, | |
0xaf, 0x58, 0xa8, 0x50, 0xf4, 0xea, 0xd6, 0x74, 0x4f, 0xae, 0xe9, 0xd5, 0xe7, 0xe6, 0xad, 0xe8, | |
0x2c, 0xd7, 0x75, 0x7a, 0xeb, 0x16, 0x0b, 0xf5, 0x59, 0xcb, 0x5f, 0xb0, 0x9c, 0xa9, 0x51, 0xa0, | |
0x7f, 0x0c, 0xf6, 0x6f, 0x17, 0xc4, 0x49, 0xec, 0xd8, 0x43, 0x1f, 0x2d, 0xa4, 0x76, 0x7b, 0xb7, | |
0xcc, 0xbb, 0x3e, 0x5a, 0xfb, 0x60, 0xb1, 0x86, 0x3b, 0x52, 0xa1, 0x6c, 0xaa, 0x55, 0x29, 0x9d, | |
0x97, 0xb2, 0x87, 0x90, 0x61, 0xbe, 0xdc, 0xfc, 0xbc, 0x95, 0xcf, 0xcd, 0x37, 0x3f, 0x5b, 0xd1, | |
0x53, 0x39, 0x84, 0x3c, 0x41, 0xa2, 0x6d, 0x47, 0x14, 0x2a, 0x9e, 0x5d, 0x56, 0xf2, 0xd3, 0xab, | |
0x44, 0x11, 0x92, 0xd9, 0x23, 0x20, 0x2e, 0x89, 0xb4, 0x7c, 0xb8, 0x26, 0x77, 0x99, 0xe3, 0xa5, | |
0x67, 0x4a, 0xed, 0xde, 0xc5, 0x31, 0xfe, 0x18, 0x0d, 0x63, 0x8c, 0x80, 0xc0, 0xf7, 0x70, 0x07, | |
]; | |
impl MulAssign for G8 { | |
fn mul_assign(&mut self, other: G8) { | |
if self.0 == 0 || other.0 == 0 { | |
self.0 = 0; | |
return | |
} | |
let a = LOG_TABLE[self.0 as usize] as usize; | |
let b = LOG_TABLE[other.0 as usize] as usize; | |
let exp = (a + b) % 0xFF; | |
self.0 = EXP_TABLE[exp]; | |
} | |
} | |
forward_ref_binop! { Mul, mul, MulAssign, mul_assign, G8 } | |
impl DivAssign for G8 { | |
fn div_assign(&mut self, other: G8) { | |
if self.0 == 0 { | |
self.0 = 0; | |
return | |
} | |
if other.0 == 0 { | |
panic!("division by zero"); | |
} | |
let a = LOG_TABLE[self.0 as usize] as isize; | |
let b = LOG_TABLE[other.0 as usize] as isize; | |
let exp = ((a - b) + 0xFF) % 0xFF; | |
self.0 = EXP_TABLE[exp as usize]; | |
} | |
} | |
forward_ref_binop! { Div, div, DivAssign, div_assign, G8 } | |
#[test] | |
fn test_mul() { | |
assert_eq!(G8(11) * G8(0), G8(0)); | |
assert_eq!(G8(11) * G8(1), G8(11)); | |
assert_eq!(G8(11) * G8(2), G8(0x16)); | |
assert_eq!(G8(11) * G8(3), G8(0x1d)); | |
assert_eq!(G8(11) * G8(0x10), G8(0xb0)); | |
assert_eq!(G8(11) * G8(0xff), G8(0xa3)); | |
assert_eq!(G8(13) * G8(0x02), G8(0x1a)); | |
assert_eq!(G8(13) * G8(0x10), G8(0xd0)); | |
assert_eq!(G8(13) * G8(0x22), G8(0xa1)); | |
assert_eq!(G8(13) * G8(0x23), G8(0xac)); | |
} | |
#[test] | |
fn test_div() { | |
for a in 0..256 { | |
for b in 1..256 { | |
assert_eq!((G8(a as u8) / G8(b as u8)) * G8(b as u8), G8(a as u8)); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern crate byteorder; | |
use std::str; | |
use std::iter::FromIterator; | |
use std::fs::File; | |
use std::io; | |
use std::io::prelude::*; | |
use byteorder::{LittleEndian, ReadBytesExt, ByteOrder}; | |
mod galois; | |
use galois::G8; | |
const SBOX: [u8; 256] = [ | |
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, | |
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, | |
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, | |
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, | |
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, | |
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, | |
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, | |
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, | |
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, | |
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, | |
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, | |
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, | |
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, | |
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, | |
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, | |
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16, | |
]; | |
type RoundTable<Output> = [[Output; 256]; 16]; | |
fn shift_rows(buf: &mut [u8; 16]) { | |
let copy = *buf; | |
for amount in 1..4 { | |
for i in 0..4 { | |
let current = 4 * i + amount; | |
let next = (4 * (i + amount) + amount) % 16; | |
buf[current] = copy[next]; | |
} | |
} | |
} | |
fn inv_shift_rows(buf: &mut [u8; 16]) { | |
let copy = *buf; | |
for amount in 1..4 { | |
for i in 0..4 { | |
let current = 4 * i + amount; | |
let next = (4 * (i + amount) + amount) % 16; | |
buf[next] = copy[current]; | |
} | |
} | |
} | |
struct WhiteBox { | |
round_tables: [RoundTable<u32>; 9], | |
final_table: RoundTable<u8>, | |
} | |
fn print_hex(buf: &[u8]) { | |
for byte in buf { | |
print!("{:02x} ", byte); | |
} | |
println!(""); | |
} | |
impl WhiteBox { | |
fn lookup_mixcolum_term(&self, round: usize, index: usize, byte: u8) -> u32 { | |
self.round_tables[round][index][byte as usize] | |
} | |
fn process_column(&self, round: usize, col: usize, data: &mut [u8]) { | |
let base = col * 4; | |
let t1 = self.lookup_mixcolum_term(round, base + 0, data[0]); | |
let t2 = self.lookup_mixcolum_term(round, base + 1, data[1]); | |
let t3 = self.lookup_mixcolum_term(round, base + 2, data[2]); | |
let t4 = self.lookup_mixcolum_term(round, base + 3, data[3]); | |
let result = t1 ^ t2 ^ t3 ^ t4; | |
LittleEndian::write_u32(data, result); | |
} | |
fn normal_round(&self, round: usize, buf: &mut [u8; 16]) { | |
shift_rows(buf); | |
for col in 0..4 { | |
self.process_column(round, col, &mut buf[col*4..]); | |
} | |
} | |
fn final_round(&self, buf: &mut [u8; 16]) { | |
shift_rows(buf); | |
for i in 0..16 { | |
buf[i] = self.final_table[i][buf[i] as usize]; | |
} | |
} | |
fn encrypt(&self, buf: &mut [u8; 16]) { | |
for round in 0..9 { | |
self.normal_round(round, buf); | |
} | |
self.final_round(buf); | |
} | |
fn self_test(&self) { | |
let mut buf = [0; 16]; | |
buf.copy_from_slice("0123456789abcdef".as_bytes()); | |
self.encrypt(&mut buf); | |
let expected = [0xe2, 0xce, 0xa3, 0x58, 0x25, 0x82, 0x6c, 0x8c, 0x5d, 0x3e, 0x7d, 0x6c, 0xea, 0x9d, 0x98, 0xf1]; | |
if buf != expected { | |
print_hex(&buf); | |
print_hex(&expected); | |
panic!("self test failed"); | |
} | |
} | |
fn single_mixcolumn_component(&self, i: usize, x1: u8, x2: u8) -> G8 { | |
let table = self.round_tables[0][i]; | |
G8((table[x1 as usize] & 0xFF) as u8) + G8((table[x2 as usize] & 0xFF) as u8) | |
} | |
fn brute(&self) -> [u8; 16] { | |
fn expected_component(k: u8, x1: u8, x2: u8) -> G8 { | |
G8(SBOX[(x1 ^ k) as usize]) + G8(SBOX[(x2 ^ k) as usize]) | |
} | |
let mut r = [0; 16]; | |
for i in 0..16 { | |
let mut possibilities: Vec<u8> = Vec::from_iter(0..255); | |
possibilities.push(255); | |
let v1 = self.single_mixcolumn_component(i, 0, 1); | |
let mut x1 = 0; | |
let mut x2 = 2; | |
println!("{}", i); | |
while possibilities.len() > 1 { | |
let to_try = possibilities.split_off(0); | |
let v2 = self.single_mixcolumn_component(i, x1, x2);; | |
for k in to_try { | |
let f1 = expected_component(k, 0, 1); | |
let f2 = expected_component(k, x1, x2); | |
if f1 == G8(0) || f2 == G8(0) || v1/f1 == v2/f2 { | |
possibilities.push(k);; | |
} | |
} | |
x2 = match x2.checked_add(1) { | |
Some(n) => n, | |
None => { | |
x1 += 1; | |
x1 + 1 | |
} | |
} | |
} | |
r[i] = possibilities[0]; | |
} | |
inv_shift_rows(&mut r); | |
r | |
} | |
} | |
fn read_round_tables<R: Read>(mut source: R) -> io::Result<[RoundTable<u32>; 9]> { | |
let mut tables = [[[0; 256]; 16]; 9]; | |
for round in 0..9 { | |
for index in 0..16 { | |
source.read_u32_into::<LittleEndian>(&mut tables[round][index])?; | |
} | |
} | |
Ok(tables) | |
} | |
fn read_final_table<R: Read>(mut source: R) -> io::Result<RoundTable<u8>> { | |
let mut table = [[0; 256]; 16]; | |
for index in 0..16 { | |
source.read_exact(&mut table[index])?; | |
} | |
Ok(table) | |
} | |
fn main() { | |
let round_tables = read_round_tables(File::open("data/6661c0.dump").unwrap()).unwrap(); | |
let final_table = read_final_table(File::open("data/6651c0.dump").unwrap()).unwrap(); | |
let white_box = WhiteBox { round_tables: round_tables, final_table: final_table }; | |
white_box.self_test(); | |
let solution = white_box.brute(); | |
print_hex(&solution); | |
println!("{}", str::from_utf8(&solution).unwrap()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment