├── gift.png ├── cryptagraph-logo.png ├── src ├── src │ ├── dist │ │ ├── mod.rs │ │ └── distributions.rs │ ├── search │ │ ├── mod.rs │ │ ├── prince_extra.rs │ │ ├── search_properties.rs │ │ ├── find_properties.rs │ │ └── single_round.rs │ ├── main.rs │ ├── cipher │ │ ├── tests.rs │ │ ├── mod.rs │ │ ├── qarma.rs │ │ ├── mcrypton.rs │ │ ├── epcbc96.rs │ │ ├── epcbc48.rs │ │ ├── gift64.rs │ │ ├── gift128.rs │ │ ├── des.rs │ │ ├── boron.rs │ │ ├── iceberg.rs │ │ ├── skinny64.rs │ │ ├── tc05.rs │ │ ├── present.rs │ │ ├── fly.rs │ │ ├── puffin.rs │ │ ├── led.rs │ │ ├── midori.rs │ │ ├── mibs.rs │ │ └── klein.rs │ ├── utility.rs │ ├── options.rs │ └── sbox.rs └── Cargo.toml ├── .gitignore └── utility ├── invert-permuation.py └── graph_plot.py /gift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psve/cryptagraph/HEAD/gift.png -------------------------------------------------------------------------------- /cryptagraph-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/psve/cryptagraph/HEAD/cryptagraph-logo.png -------------------------------------------------------------------------------- /src/src/dist/mod.rs: -------------------------------------------------------------------------------- 1 | //! Functions for generation correlation distributions. 2 | 3 | pub mod correlations; 4 | pub mod distributions; 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.aux 2 | *.bbl 3 | *.blg 4 | *.fdb_latexmk 5 | *.fls 6 | *.log 7 | *.out 8 | *.pdf 9 | *.synctex.gz 10 | *.masks 11 | src/target/* 12 | *.sublime-project 13 | *.sublime-workspace 14 | targets.txt 15 | -------------------------------------------------------------------------------- /src/src/search/mod.rs: -------------------------------------------------------------------------------- 1 | //! Types and functions for searching for properties of a cipher. 2 | 3 | pub mod find_properties; 4 | pub mod graph; 5 | pub mod graph_generate; 6 | pub mod patterns; 7 | pub mod prince_extra; 8 | pub mod search_properties; 9 | pub mod single_round; 10 | -------------------------------------------------------------------------------- /src/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cryptagraph" 3 | version = "1.1.0" 4 | authors = ["Philip Vejre ", "Mathias Hall-Andersen "] 5 | edition = "2018" 6 | 7 | [profile.release] 8 | incremental=true 9 | 10 | [dependencies] 11 | rand = "*" 12 | structopt = "*" 13 | structopt-derive = "*" 14 | num_cpus = "*" 15 | crossbeam-utils = "*" 16 | lazy_static = "*" 17 | fnv = "*" 18 | indexmap = "*" 19 | itertools = "*" 20 | 21 | [dev-dependencies] 22 | proptest = "0.9.4" 23 | -------------------------------------------------------------------------------- /utility/invert-permuation.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | # inverts a byte-wise described 64-bit bit-permuation 4 | 5 | size = 64 6 | lbin = bin 7 | def bin(x): 8 | return ('%%0%ds' % size) % lbin(x)[2:] 9 | 10 | with open(sys.argv[1], 'r') as f: 11 | d = f.read() 12 | p = eval(d) 13 | 14 | inv = {} 15 | for i in range(size): 16 | b = p[i / 8][1 << (i % 8)] 17 | inv[b] = 1 << i 18 | assert bin(b).count('1') == 1 19 | 20 | table = [] 21 | for off in range(0, size, 8): 22 | row = [] 23 | for inp in range(0x100): 24 | s = inp << off 25 | o = 0 26 | # decompose 27 | for k, v in inv.items(): 28 | if k & s: 29 | o |= v 30 | assert bin(inp).count('1') == bin(o).count('1') 31 | row.append(o) 32 | table.append(row) 33 | 34 | for row in table: 35 | e = map(lambda x: '0x%016x' % x, row) 36 | s = [e[i: i+8] for i in range(0, 0x100, 8)] 37 | print ' [', ', '.join(s[0]), ',' 38 | for v in s[1:-1]: 39 | print ' ', ', '.join(v), ',' 40 | print ' ', ', '.join(s[-1]), '],' 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/src/search/prince_extra.rs: -------------------------------------------------------------------------------- 1 | //! Extra functions for handling Prince-like ciphers. 2 | 3 | use fnv::FnvHashSet; 4 | 5 | use crate::cipher::*; 6 | use crate::search::graph::MultistageGraph; 7 | 8 | /// Special graph pruning for Prince-like ciphers. The last layer is also pruned with regards to the 9 | /// reflection function. 10 | pub fn prince_pruning_new(cipher: &dyn Cipher, graph: &mut MultistageGraph) { 11 | let num_stages = graph.stages(); 12 | let mut pruned = true; 13 | 14 | while pruned { 15 | pruned = false; 16 | 17 | let reflections: FnvHashSet<_> = graph 18 | .get_vertices_incoming(num_stages) 19 | .iter() 20 | .map(|&x| cipher.reflection_layer(x as u128)) 21 | .collect(); 22 | let mut remove = Vec::new(); 23 | 24 | for (&tail, heads) in graph.forward_edges() { 25 | for (&head, (stages, _)) in heads { 26 | if ((stages >> (num_stages - 1)) & 0x1) == 1 && !reflections.contains(&head) { 27 | remove.push((tail, head, 1 << (num_stages - 1))); 28 | } 29 | } 30 | } 31 | 32 | for (tail, head, stages) in remove { 33 | graph.remove_edges(tail, head, stages); 34 | pruned = true; 35 | } 36 | 37 | graph.prune(0, num_stages); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /utility/graph_plot.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | 3 | from graph_tool.all import * 4 | import csv, sys 5 | 6 | size = 1000 7 | width = int(size * 2) 8 | height = size 9 | 10 | path = sys.argv[1] 11 | vertex_data = set() 12 | edge_data = set() 13 | 14 | with open(path, "r") as f: 15 | reader = csv.reader(f) 16 | 17 | for row in reader: 18 | data = [int(x) for x in row] 19 | vertex_data.add((data[0], data[1])) 20 | vertex_data.add((data[2], data[3])) 21 | edge_data.add((data[0], data[1], data[2], data[3])) 22 | 23 | print("Data read") 24 | 25 | vertices = dict() 26 | 27 | for x in vertex_data: 28 | vertices[x] = len(vertices) 29 | 30 | stages = max([x for (x,y) in vertices.keys()]) + 1 31 | 32 | g = Graph(directed=True) 33 | 34 | for e in edge_data: 35 | f = vertices[(e[0], e[1])] 36 | t = vertices[(e[2], e[3])] 37 | g.add_edge(f, t) 38 | 39 | print("Graph generated") 40 | 41 | pos = g.new_vertex_property("vector") 42 | max_name = max([x[1] for x in vertices.keys()]) 43 | 44 | for v in vertices.keys(): 45 | x = (v[0]-1) / (stages-1) * width 46 | y = v[1] / max_name * height 47 | pos[vertices[v]] = [x, y] 48 | 49 | print("Positions generated") 50 | 51 | graph_draw(g, pos = pos, \ 52 | vertex_size = 3.5, \ 53 | output_size = (width, height), \ 54 | bg_color = [1,1,1,1], \ 55 | edge_pen_width= 0.1, \ 56 | edge_color = [0.09, 0.40, 0.549, 1.0], \ 57 | vertex_color = [0.871, 0.106, 0.106, 1.0], \ 58 | output = path+".png") 59 | -------------------------------------------------------------------------------- /src/src/main.rs: -------------------------------------------------------------------------------- 1 | //! Cryptagraph is a tool for finding linear approximations and differentials of block ciphers. 2 | 3 | #[macro_use] 4 | extern crate lazy_static; 5 | #[macro_use] 6 | extern crate structopt_derive; 7 | 8 | extern crate crossbeam_utils; 9 | extern crate fnv; 10 | extern crate indexmap; 11 | extern crate itertools; 12 | extern crate num_cpus; 13 | extern crate rand; 14 | extern crate structopt; 15 | 16 | pub mod cipher; 17 | pub mod dist; 18 | mod options; 19 | pub mod property; 20 | pub mod sbox; 21 | pub mod search; 22 | pub mod utility; 23 | 24 | use crate::cipher::*; 25 | use crate::options::CryptagraphOptions; 26 | use structopt::StructOpt; 27 | 28 | fn main() { 29 | match CryptagraphOptions::from_args() { 30 | CryptagraphOptions::Search { 31 | cipher, 32 | property_type, 33 | rounds, 34 | num_patterns, 35 | anchors, 36 | file_mask_in, 37 | file_mask_out, 38 | num_keep, 39 | file_graph, 40 | } => { 41 | let cipher = match name_to_cipher(cipher.as_ref()) { 42 | Some(c) => c, 43 | None => { 44 | println!("Cipher not supported. Check --help for supported ciphers."); 45 | return; 46 | } 47 | }; 48 | 49 | search::search_properties::search_properties( 50 | cipher.as_ref(), 51 | property_type, 52 | rounds, 53 | num_patterns, 54 | anchors, 55 | file_mask_in, 56 | file_mask_out, 57 | num_keep, 58 | file_graph, 59 | ); 60 | } 61 | CryptagraphOptions::Dist { 62 | cipher, 63 | file_mask_in, 64 | rounds, 65 | keys, 66 | masks, 67 | output, 68 | } => { 69 | let cipher = match name_to_cipher(cipher.as_ref()) { 70 | Some(c) => c, 71 | None => { 72 | println!("Cipher not supported. Check --help for supported ciphers."); 73 | return; 74 | } 75 | }; 76 | 77 | dist::distributions::get_distributions( 78 | cipher.as_ref(), 79 | &file_mask_in, 80 | rounds, 81 | keys, 82 | &masks, 83 | &output, 84 | ); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/src/cipher/tests.rs: -------------------------------------------------------------------------------- 1 | /* Macroes to help ease testing of Cipher implementations 2 | */ 3 | macro_rules! test_linear_layer { 4 | ($impl:path) => { 5 | #[test] 6 | #[allow(unused_imports)] 7 | use proptest::prelude::*; 8 | 9 | #[test] 10 | fn test_linear_layer() { 11 | let cipher = <$impl>::new(); 12 | let config = ProptestConfig { 13 | timeout : 1000, 14 | verbose : 2, 15 | max_shrink_time : 1000, 16 | .. ProptestConfig::default() 17 | }; 18 | 19 | proptest!(config, |(x : u128)| { 20 | let x = x & ((1 << cipher.size()) - 1); 21 | let y = cipher.linear_layer(x); 22 | assert!(y < (1 << cipher.size())); 23 | assert_eq!(x, cipher.linear_layer_inv(y)); 24 | }) 25 | } 26 | } 27 | } 28 | 29 | macro_rules! test_encryption_decryption { 30 | ($impl:path) => { 31 | #[test] 32 | #[allow(unused_imports)] 33 | use proptest::prelude::*; 34 | 35 | #[test] 36 | fn test_encryption_decryption() { 37 | let cipher = <$impl>::new(); 38 | let config = ProptestConfig { 39 | timeout : 1000, 40 | verbose : 2, 41 | max_shrink_time : 1000, 42 | .. ProptestConfig::default() 43 | }; 44 | 45 | proptest!(config, |(pt : u128, keys : Vec)| { 46 | let msk : u128 = (1 << cipher.size()) - 1; 47 | let keys : Vec = keys.into_iter().map(|x| x & msk).collect(); 48 | let pt = pt & msk; 49 | let ct = cipher.encrypt(pt, &keys); 50 | println!("0x{:x} -enc({:?})-> 0x{:x}", pt, keys, ct); 51 | let ppt = cipher.decrypt(ct, &keys); 52 | assert_eq!(ppt, pt); 53 | }) 54 | } 55 | } 56 | } 57 | 58 | /// Generic property-based testsuite for cipher implementation 59 | macro_rules! cipher_test_suite { 60 | ($impl:path) => { 61 | test_linear_layer!($impl); 62 | test_encryption_decryption!($impl); 63 | }; 64 | } 65 | 66 | #[allow(unused_macros)] 67 | macro_rules! cipher_testvector_encryption { 68 | ($impl:path, $tests:expr) => { 69 | #[test] 70 | fn test_encryption() { 71 | let cipher = <$impl>::new(); 72 | for (key, pt, ct) in expr.iter() { 73 | let cct = cipher.encrypt(pt); 74 | assert_eq!(pt, ct); 75 | } 76 | } 77 | }; 78 | } 79 | -------------------------------------------------------------------------------- /src/src/utility.rs: -------------------------------------------------------------------------------- 1 | //! A collection of utility functions used throughout the library. 2 | 3 | use std::io::{self, Write}; 4 | 5 | /// Finds the parity of ` ^ `, where `<_,_>` is the inner product 6 | /// over GF(2). Taken from 7 | /// [here](http://www.graphics.stanford.edu/~seander/bithacks.html#ParityMultiply). 8 | pub fn parity_masks(input: u128, output: u128, alpha: u128, beta: u128) -> u128 { 9 | let mut y = (input & alpha) | ((output & beta) << 64); 10 | 11 | y ^= y >> 1; 12 | y ^= y >> 2; 13 | y = (y & 0x1111_1111_1111_1111_1111_1111_1111_1111) 14 | .wrapping_mul(0x1111_1111_1111_1111_1111_1111_1111_1111); 15 | (y >> 124) & 1 16 | } 17 | 18 | /// Calculates the modulo 2 sum of the bits in the input. 19 | pub fn parity(input: u128) -> u128 { 20 | let mut y = input; 21 | 22 | y ^= y >> 1; 23 | y ^= y >> 2; 24 | y = (y & 0x1111_1111_1111_1111_1111_1111_1111_1111) 25 | .wrapping_mul(0x1111_1111_1111_1111_1111_1111_1111_1111); 26 | (y >> 124) & 1 27 | } 28 | 29 | static COMP_PATTERN: [u128; 4] = [ 30 | 0x0101_0101_0101_0101_0101_0101_0101_0101, 31 | 0x1111_1111_1111_1111_1111_1111_1111_1111, 32 | 0x5555_5555_5555_5555_5555_5555_5555_5555, 33 | 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff, 34 | ]; 35 | 36 | /// Compresses `x` such that if a block of 2(3-`level`) bits is non-zero, then that 37 | /// block is set to the value 1 in the output. 38 | #[inline(always)] 39 | pub fn compress(x: u128, level: usize) -> u128 { 40 | // We use bit patterns to reduce the amount of work done 41 | let mut y = x; 42 | for i in 0..(3 - level) { 43 | y = y | (y >> (1 << i)); 44 | } 45 | 46 | y & COMP_PATTERN[level] 47 | } 48 | 49 | /// A struct representing a progress bar for progress printing on the command line. 50 | pub struct ProgressBar { 51 | current_items: f64, 52 | item_size: f64, 53 | used: bool, 54 | } 55 | 56 | impl ProgressBar { 57 | /// Creates a new progress for tracking progress of `num_items` steps. 58 | pub fn new(num_items: usize) -> ProgressBar { 59 | let item_size = 100.0 / (num_items as f64); 60 | 61 | ProgressBar { 62 | current_items: 0.0, 63 | item_size, 64 | used: false, 65 | } 66 | } 67 | 68 | /// Increment the current progress of the bar. The progress bar prints if 69 | /// a new step was reached. 70 | #[inline(always)] 71 | pub fn increment(&mut self) { 72 | self.current_items += self.item_size; 73 | 74 | while self.current_items >= 1.0 { 75 | print!("="); 76 | io::stdout().flush().expect("Could not flush stdout"); 77 | self.current_items -= 1.0; 78 | } 79 | 80 | self.used = true; 81 | } 82 | } 83 | 84 | impl Drop for ProgressBar { 85 | fn drop(&mut self) { 86 | if self.used { 87 | println!(); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/src/options.rs: -------------------------------------------------------------------------------- 1 | use crate::property::PropertyType; 2 | 3 | #[derive(Clone, StructOpt)] 4 | #[structopt( 5 | name = "Cryptagraph", 6 | about = "Search for linear and differential properties of block ciphers." 7 | )] 8 | pub enum CryptagraphOptions { 9 | #[structopt(name = "search")] 10 | Search { 11 | #[structopt(short = "c", long = "cipher")] 12 | /** 13 | Name of the cipher to analyse. Current available ciphers are: 14 | aes, boron, des, epcbc48, epcbc96, fly, gift64, gift128, halka, iceberg, khazad, klein, led, mantis, mcrypton, mibs, midori, present, pride, prince, puffin, qarma, rectangle, skinny64, skinny128, twine 15 | */ 16 | cipher: String, 17 | 18 | #[structopt(short = "t", long = "type")] 19 | /** 20 | The type of property to analyse. Currently supported are: 21 | linear, differential 22 | */ 23 | property_type: PropertyType, 24 | 25 | #[structopt(short = "r", long = "rounds")] 26 | /** 27 | The number of rounds the analyse. 28 | */ 29 | rounds: usize, 30 | 31 | #[structopt(short = "p", long = "patterns")] 32 | /** 33 | The number of S-box patterns to generate. The number of patterns determine how many different properties over a single round are analysed. 34 | */ 35 | num_patterns: usize, 36 | 37 | #[structopt(short = "a", long = "anchors")] 38 | /** 39 | If provided, this parameter parameter overrides the default number of anchors. The number of anchors is 2^(). 40 | */ 41 | anchors: Option, 42 | 43 | #[structopt(short = "i", long = "mask_in")] 44 | /** 45 | Path to a file which restrict the input and output values of the property. Each line of the file must be of the form ','. 46 | */ 47 | file_mask_in: Option, 48 | 49 | #[structopt(short = "o", long = "mask_out")] 50 | /** 51 | Prefix of a path to a set of two files in which to dump the discovered properties as well as the set of their inputs and outputs. The two files generated are .app and .set. 52 | */ 53 | file_mask_out: Option, 54 | 55 | #[structopt(short = "n", long = "num_keep")] 56 | /** 57 | The number of properties to display as output. If specified together with , the 58 | results are also written to the file .app. 59 | */ 60 | num_keep: Option, 61 | 62 | #[structopt(short = "g", long = "file_graph")] 63 | /** 64 | Prefix of a path to dump the graph data to. The file generate is .graph. 65 | */ 66 | file_graph: Option, 67 | }, 68 | 69 | #[structopt(name = "dist")] 70 | Dist { 71 | #[structopt(short = "c", long = "cipher")] 72 | /** 73 | Name of the cipher to analyse. Current available ciphers are: 74 | aes, epcbc48, epcbc96, fly, gift64, gift128, khazad, klein, led, mantis, mibs, midori, present, pride, prince, puffin, qarma, rectangle, skinny64, skinny128, twine 75 | */ 76 | cipher: String, 77 | 78 | #[structopt(short = "i", long = "mask_in")] 79 | /** 80 | Path to a file which restrict the input and output values of the property. Each line of the file must be of the form ','. 81 | */ 82 | file_mask_in: String, 83 | 84 | #[structopt(short = "r", long = "rounds")] 85 | /** 86 | Number of rounds to generate correlations for. 87 | */ 88 | rounds: usize, 89 | 90 | #[structopt(short = "k", long = "keys")] 91 | /** 92 | Number of keys to generation correlations for. 93 | */ 94 | keys: usize, 95 | 96 | #[structopt(short = "m", long = "masks")] 97 | /** 98 | Path to a file containing intermediate masksk. 99 | */ 100 | masks: String, 101 | 102 | #[structopt(short = "o", long = "output")] 103 | /** 104 | Name of output file. File name is .corrs 105 | */ 106 | output: String, 107 | }, 108 | } 109 | -------------------------------------------------------------------------------- /src/src/sbox.rs: -------------------------------------------------------------------------------- 1 | //! Type representing an S-box. 2 | 3 | use crate::utility::parity_masks; 4 | use std::convert::TryInto; 5 | 6 | /// A structure that represents an S-box. 7 | #[derive(Clone, Debug)] 8 | pub struct Sbox { 9 | in_size: usize, 10 | out_size: usize, 11 | table: Vec, 12 | lat: Vec>, 13 | ddt: Vec>, 14 | } 15 | 16 | impl Sbox { 17 | /// Creates a new S-box from its table description. `size` is the bit size of the S-box. 18 | /// 19 | /// # Panics 20 | /// The function panics if the length of `table` is not equal to 2<\sup>`size`<\sup>. 21 | pub fn new(in_size: usize, out_size: usize, table: Vec) -> Sbox { 22 | assert_eq!(1 << in_size, table.len()); 23 | 24 | let lat = Sbox::generate_lat(&table[..], in_size, out_size); 25 | let ddt = Sbox::generate_ddt(&table[..], in_size, out_size); 26 | 27 | Sbox { 28 | in_size, 29 | out_size, 30 | table, 31 | lat, 32 | ddt, 33 | } 34 | } 35 | 36 | /// Generates the LAT associated with the S-box. 37 | fn generate_lat(table: &[u8], in_size: usize, out_size: usize) -> Vec> { 38 | let rows = 1 << in_size; 39 | let cols = 1 << out_size; 40 | let mut lat = vec![vec![0; cols]; rows]; 41 | 42 | for (plaintext, &ciphertext) in table.iter().enumerate() { 43 | for alpha in 0..rows { 44 | for beta in 0..cols { 45 | let parity = parity_masks( 46 | plaintext as u128, 47 | u128::from(ciphertext), 48 | alpha as u128, 49 | beta as u128, 50 | ); 51 | 52 | lat[alpha as usize][beta as usize] += (1 - parity) as usize; 53 | } 54 | } 55 | } 56 | 57 | lat 58 | } 59 | 60 | /// Generates the DDT associated with the S-box. 61 | fn generate_ddt(table: &[u8], in_size: usize, out_size: usize) -> Vec> { 62 | let rows = 1 << in_size; 63 | let cols = 1 << out_size; 64 | let mut ddt = vec![vec![0; cols]; rows]; 65 | 66 | for plaintext_0 in 0..rows { 67 | let ciphertext_0 = table[plaintext_0]; 68 | 69 | for (in_diff, ddt_row) in ddt.iter_mut().enumerate() { 70 | let plaintext_1 = plaintext_0 ^ in_diff; 71 | let ciphertext_1 = table[plaintext_1]; 72 | 73 | ddt_row[(ciphertext_0 ^ ciphertext_1) as usize] += 1; 74 | } 75 | } 76 | 77 | ddt 78 | } 79 | 80 | /// Applies the S-box to the input. 81 | pub fn apply>(&self, x: T) -> u8 { 82 | let x = match x.try_into() { 83 | Ok(x) => x, 84 | Err(_) => panic!("Conversion error"), 85 | }; 86 | assert!(x < (1 << self.in_size)); 87 | self.table[x] 88 | } 89 | 90 | /// Returns the value of a balanced linear approximation of the S-box. 91 | pub fn linear_balance(&self) -> i16 { 92 | (1 << (self.in_size - 1)) as i16 93 | } 94 | 95 | /// Returns the probability of an impossible differential of the S-box. 96 | pub fn differential_zero(&self) -> i16 { 97 | 0 98 | } 99 | 100 | /// Returns the probability of the trivial differential of the S-box. 101 | pub fn differential_trivial(&self) -> i16 { 102 | (1 << self.in_size) as i16 103 | } 104 | 105 | /// Returns a bitmask that corresponds to the S-box input size. 106 | pub fn mask_in(&self) -> u128 { 107 | (1 << self.in_size) - 1 108 | } 109 | 110 | /// Returns a bitmask that corresponds to the S-box output size. 111 | pub fn mask_out(&self) -> u128 { 112 | (1 << self.out_size) - 1 113 | } 114 | 115 | /// Returns the input size of the S-box in bits. 116 | pub fn size_in(&self) -> usize { 117 | self.in_size 118 | } 119 | 120 | /// Returns the output size of the S-box in bits. 121 | pub fn size_out(&self) -> usize { 122 | self.out_size 123 | } 124 | 125 | /// Returns a reference to the LAT of the S-box. 126 | pub fn lat(&self) -> &Vec> { 127 | &self.lat 128 | } 129 | 130 | /// Returns a reference to the DDT of the S-box. 131 | pub fn ddt(&self) -> &Vec> { 132 | &self.ddt 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/src/dist/distributions.rs: -------------------------------------------------------------------------------- 1 | //! Main functions for generating correlations distributions. 2 | 3 | use fnv::FnvHashMap; 4 | use std::fs::{File, OpenOptions}; 5 | use std::io::{BufRead, BufReader, Write}; 6 | use std::time::Instant; 7 | 8 | use crate::cipher::*; 9 | use crate::dist::correlations::get_correlations; 10 | 11 | /// Reads a file of allowed input and output values and stores them in a hash set. The values in 12 | /// the files are assumed to be in hexadecimals, without the '0x' prefix, and input/output masks 13 | /// should be separated by a comma. 14 | fn read_allowed(file_mask_in: &str) -> Vec<(u128, u128)> { 15 | let file = File::open(file_mask_in).expect("Could not open file."); 16 | let mut allowed = Vec::new(); 17 | 18 | for line in BufReader::new(file).lines() { 19 | let s = line.expect("Error reading file"); 20 | let split: Vec<_> = s.split(',').collect(); 21 | let alpha = u128::from_str_radix(split.get(0).expect("Could not read input data"), 16) 22 | .expect("Could not parse integer. Is it in hexadecimals?"); 23 | let beta = u128::from_str_radix(split.get(1).expect("Could not read input data"), 16) 24 | .expect("Could not parse integer. Is it in hexadecimals?"); 25 | allowed.push((alpha, beta)); 26 | } 27 | 28 | allowed 29 | } 30 | 31 | /// Loads a set of intermediate masks from file. The values in the files are assumed to be in 32 | /// hexadecimals, without the '0x' prefix. 33 | fn load_masks(path: &str) -> Option> { 34 | let file = File::open(path).unwrap(); 35 | let reader = BufReader::new(&file); 36 | let mut masks = vec![]; 37 | for line in reader.lines() { 38 | let line = line.unwrap(); 39 | let mask = match u128::from_str_radix(&line, 16) { 40 | Ok(m) => m, 41 | Err(_) => return None, 42 | }; 43 | masks.push(mask); 44 | } 45 | Some(masks) 46 | } 47 | 48 | /// Saves a set of correlations in a file. The file format is csv, and the headers have the form 49 | /// `input_output`. 50 | fn dump_correlations(correlations: &FnvHashMap<(u128, u128), Vec>, path: &str) { 51 | let mut file = OpenOptions::new() 52 | .write(true) 53 | .truncate(true) 54 | .create(true) 55 | .open(path) 56 | .expect("Could not open file."); 57 | 58 | let mut values = Vec::new(); 59 | 60 | let mut line = String::new(); 61 | for ((alpha, beta), corrs) in correlations.iter() { 62 | line.push_str(&format!("{:032x}_{:032x},", alpha, beta)); 63 | values.push(corrs); 64 | } 65 | line.pop(); 66 | writeln!(file, "{}", line).expect("Could not write to file."); 67 | 68 | for j in 0..values.first().expect("Empty data set.").len() { 69 | let mut line = String::new(); 70 | 71 | for v in &values { 72 | line.push_str(&format!("{},", v[j])); 73 | } 74 | line.pop(); 75 | writeln!(file, "{}", line).expect("Could not write to file."); 76 | } 77 | } 78 | 79 | /// Generates correlation distributions for a given cipher. The correlations are saved in a csv file 80 | /// with the suffix '.corrs'. The headers have the form `input_output`. 81 | /// 82 | /// # Parameters 83 | /// * `cipher`: The cipher to calculate correlations for. 84 | /// * `file_mask_in`: Path to a file containing allowed input-output masks. 85 | /// * `rounds`: Number of rounds to calculate correlations for. 86 | /// * `keys`: Number of master keys to generation correlations for. 87 | /// * `masks`: Path to a file containing a set of intermediate masks used when generating trails. 88 | /// * `output`: Prefix of the output file. 89 | pub fn get_distributions( 90 | cipher: &dyn Cipher, 91 | file_mask_in: &str, 92 | rounds: usize, 93 | keys: usize, 94 | masks: &str, 95 | output: &str, 96 | ) { 97 | let start = Instant::now(); 98 | 99 | // read mask files 100 | let masks = match load_masks(&masks) { 101 | Some(m) => m, 102 | None => panic!("failed to load mask set"), 103 | }; 104 | 105 | let allowed = read_allowed(file_mask_in); 106 | 107 | println!("Cipher: {}", cipher.name()); 108 | println!("Properties masks: {}", allowed.len()); 109 | println!("Intermediate masks: {}", masks.len()); 110 | 111 | let mut correlations = get_correlations(cipher, &allowed, rounds, keys, &masks); 112 | 113 | // Remove approximations with zero correlation 114 | correlations.retain(|_, v| v.iter().fold(false, |acc, &x| acc | (x != 0.0))); 115 | 116 | let path = format!("{}.corrs", output); 117 | dump_correlations(&correlations, &path); 118 | 119 | println!("Generation finished. [{:?} s]", start.elapsed().as_secs()); 120 | } 121 | -------------------------------------------------------------------------------- /src/src/cipher/mod.rs: -------------------------------------------------------------------------------- 1 | //! A trait for representing ciphers as well as several cipher implementations. 2 | 3 | use crate::property::PropertyType; 4 | use crate::sbox::Sbox; 5 | 6 | /// Different type of ciphers. 7 | #[derive(PartialEq, Eq)] 8 | pub enum CipherStructure { 9 | /// A regular SPN cipher. 10 | Spn, 11 | /// A Feistel cipher. 12 | Feistel, 13 | /// A cipher with a reflective structure similar to PRINCE. 14 | Prince, 15 | } 16 | 17 | /// A trait defining a cipher. 18 | pub trait Cipher: Sync { 19 | /// Returns the type of the cipher. 20 | fn structure(&self) -> CipherStructure; 21 | 22 | /// Returns the block size of the cipher in bits. 23 | fn size(&self) -> usize; 24 | 25 | /// Returns key size in bits. 26 | fn key_size(&self) -> usize; 27 | 28 | /// Returns the number of S-boxes in the non-linear layer. 29 | fn num_sboxes(&self) -> usize; 30 | 31 | /// Returns the i'th S-box of the cipher. 32 | fn sbox(&self, i: usize) -> &Sbox; 33 | 34 | /// Returns the position of the LSB of the input to the i'th S-box of the cipher. 35 | fn sbox_pos_in(&self, i: usize) -> usize; 36 | 37 | /// Returns the position of the LSB of the output to the i'th S-box of the cipher. 38 | fn sbox_pos_out(&self, i: usize) -> usize; 39 | 40 | /// Applies the linear layer of the cipher to the input. 41 | fn linear_layer(&self, input: u128) -> u128; 42 | 43 | /// Applies the inverse linear layer of the cipher to the input. 44 | fn linear_layer_inv(&self, input: u128) -> u128; 45 | 46 | /// Applies the reflection layer for Prince like ciphers. 47 | /// For all other cipher types, this can remain unimplemented. 48 | #[allow(unused_variables)] 49 | fn reflection_layer(&self, _input: u128) -> u128 { 50 | panic!("Not implemented for this type of cipher") 51 | } 52 | 53 | /// Computes a vector of round key from a cipher key. Note that the length of the output 54 | /// is not necessarily equal to `rounds`. See the `whitening` function. 55 | fn key_schedule(&self, rounds: usize, key: &[u8]) -> Vec; 56 | 57 | /// Performs encryption with the cipher (for testing) 58 | fn encrypt(&self, input: u128, _round_keys: &[u128]) -> u128 { 59 | input 60 | } 61 | 62 | /// Performs decryption with the cipher (for testing). 63 | fn decrypt(&self, input: u128, _round_keys: &[u128]) -> u128 { 64 | input 65 | } 66 | 67 | /// Returns the name of the cipher. 68 | fn name(&self) -> String; 69 | 70 | /// Transforms the input and output mask of the S-box layer to an input and output mask 71 | /// of a round. Note that this transformation can depend on the property type. 72 | #[allow(unused_variables)] 73 | fn sbox_mask_transform( 74 | &self, 75 | input: u128, 76 | output: u128, 77 | property_type: PropertyType, 78 | ) -> (u128, u128); 79 | 80 | /// Specifies if the cipher uses a pre-whitening key. In this case, the key-schedule returns 81 | /// rounds+1 round keys. 82 | fn whitening(&self) -> bool; 83 | } 84 | 85 | #[macro_use] 86 | mod tests; 87 | 88 | pub mod aes; 89 | pub mod boron; 90 | pub mod des; 91 | pub mod epcbc48; 92 | pub mod epcbc96; 93 | pub mod fly; 94 | pub mod gift128; 95 | pub mod gift64; 96 | pub mod halka; 97 | pub mod iceberg; 98 | pub mod khazad; 99 | pub mod klein; 100 | pub mod led; 101 | pub mod mantis; 102 | pub mod mcrypton; 103 | pub mod mibs; 104 | pub mod midori; 105 | pub mod present; 106 | pub mod pride; 107 | pub mod prince; 108 | pub mod puffin; 109 | pub mod qarma; 110 | pub mod rectangle; 111 | pub mod skinny128; 112 | pub mod skinny64; 113 | pub mod tc05; 114 | pub mod twine; 115 | 116 | /// Converts the name of a cipher to an instance of that cipher. 117 | pub fn name_to_cipher(name: &str) -> Option> { 118 | match name { 119 | "aes" => Some(Box::new(aes::Aes::new())), 120 | "boron" => Some(Box::new(boron::Boron::new())), 121 | "des" => Some(Box::new(des::Des::new())), 122 | "epcbc48" => Some(Box::new(epcbc48::Epcbc48::new())), 123 | "epcbc96" => Some(Box::new(epcbc96::Epcbc96::new())), 124 | "fly" => Some(Box::new(fly::Fly::new())), 125 | "gift64" => Some(Box::new(gift64::Gift64::new())), 126 | "gift128" => Some(Box::new(gift128::Gift128::new())), 127 | "halka" => Some(Box::new(halka::Halka::new())), 128 | "iceberg" => Some(Box::new(iceberg::Iceberg::new())), 129 | "khazad" => Some(Box::new(khazad::Khazad::new())), 130 | "klein" => Some(Box::new(klein::Klein::new())), 131 | "led" => Some(Box::new(led::Led::new())), 132 | "mantis" => Some(Box::new(mantis::Mantis::new())), 133 | "mcrypton" => Some(Box::new(mcrypton::Mcrypton::new())), 134 | "mibs" => Some(Box::new(mibs::Mibs::new())), 135 | "midori" => Some(Box::new(midori::Midori::new())), 136 | "present" => Some(Box::new(present::Present::new())), 137 | "pride" => Some(Box::new(pride::Pride::new())), 138 | "prince" => Some(Box::new(prince::Prince::new())), 139 | "puffin" => Some(Box::new(puffin::Puffin::new())), 140 | "qarma" => Some(Box::new(qarma::Qarma::new())), 141 | "rectangle" => Some(Box::new(rectangle::Rectangle::new())), 142 | "skinny64" => Some(Box::new(skinny64::Skinny64::new())), 143 | "skinny128" => Some(Box::new(skinny128::Skinny128::new())), 144 | "twine" => Some(Box::new(twine::Twine::new())), 145 | "tc05" => Some(Box::new(tc05::TC05::new())), 146 | _ => None, 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/src/cipher/qarma.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of QARMA. 2 | 3 | use crate::cipher::{Cipher, CipherStructure}; 4 | use crate::property::PropertyType; 5 | use crate::sbox::Sbox; 6 | 7 | /***************************************************************** 8 | QARMA 9 | ******************************************************************/ 10 | 11 | // A structure representing the QARMA cipher. 12 | #[derive(Clone)] 13 | pub struct Qarma { 14 | size: usize, 15 | key_size: usize, 16 | sbox: Sbox, 17 | constants: [u128; 8], 18 | permute_cell_table: [usize; 16], 19 | ipermute_cell_table: [usize; 16], 20 | } 21 | 22 | impl Qarma { 23 | /// Create a new instance of the cipher. 24 | pub fn new() -> Qarma { 25 | let table = vec![0, 14, 2, 10, 9, 15, 8, 11, 6, 4, 3, 7, 13, 12, 1, 5]; 26 | let constants = [ 27 | 0x0000000000000000, 28 | 0x13198A2E03707344, 29 | 0xA4093822299F31D0, 30 | 0x082EFA98EC4E6C89, 31 | 0x452821E638D01377, 32 | 0xBE5466CF34E90C6C, 33 | 0x3F84D5B5B5470917, 34 | 0x9216D5D98979FB1B, 35 | ]; 36 | let permute_cell_table = [0, 5, 15, 10, 13, 8, 2, 7, 11, 14, 4, 1, 6, 3, 9, 12]; 37 | let ipermute_cell_table = [0, 11, 6, 13, 10, 1, 12, 7, 5, 14, 3, 8, 15, 4, 9, 2]; 38 | 39 | Qarma { 40 | size: 64, 41 | key_size: 128, 42 | sbox: Sbox::new(4, 4, table), 43 | constants, 44 | permute_cell_table, 45 | ipermute_cell_table, 46 | } 47 | } 48 | } 49 | 50 | impl Qarma { 51 | fn mix_columns(&self, x: u128) -> u128 { 52 | let mut output = 0; 53 | output ^= ((((x << 1) & 0xeeee0000) | ((x >> 3) & 0x11110000)) >> 16) 54 | ^ ((((x << 2) & 0xcccc00000000) | ((x >> 2) & 0x333300000000)) >> 32) 55 | ^ ((((x << 1) & 0xeeee000000000000) | ((x >> 3) & 0x1111000000000000)) >> 48); 56 | 57 | output ^= ((((x << 1) & 0xeeee) | ((x >> 3) & 0x1111)) << 16) 58 | ^ ((((x << 1) & 0xeeee00000000) | ((x >> 3) & 0x111100000000)) >> 16) 59 | ^ ((((x << 2) & 0xcccc000000000000) | ((x >> 2) & 0x3333000000000000)) >> 32); 60 | 61 | output ^= ((((x << 2) & 0xcccc) | ((x >> 2) & 0x3333)) << 32) 62 | ^ ((((x << 1) & 0xeeee0000) | ((x >> 3) & 0x11110000)) << 16) 63 | ^ ((((x << 1) & 0xeeee000000000000) | ((x >> 3) & 0x1111000000000000)) >> 16); 64 | 65 | output ^= ((((x << 1) & 0xeeee) | ((x >> 3) & 0x1111)) << 48) 66 | ^ ((((x << 2) & 0xcccc0000) | ((x >> 2) & 0x33330000)) << 32) 67 | ^ ((((x << 1) & 0xeeee00000000) | ((x >> 3) & 0x111100000000)) << 16); 68 | 69 | output 70 | } 71 | } 72 | 73 | impl Cipher for Qarma { 74 | fn structure(&self) -> CipherStructure { 75 | CipherStructure::Prince 76 | } 77 | 78 | fn size(&self) -> usize { 79 | self.size 80 | } 81 | 82 | fn key_size(&self) -> usize { 83 | self.key_size 84 | } 85 | 86 | fn num_sboxes(&self) -> usize { 87 | self.size / self.sbox.size_in() 88 | } 89 | 90 | fn sbox(&self, _i: usize) -> &Sbox { 91 | &self.sbox 92 | } 93 | 94 | fn sbox_pos_in(&self, i: usize) -> usize { 95 | i * self.sbox(i).size_in() 96 | } 97 | 98 | fn sbox_pos_out(&self, i: usize) -> usize { 99 | i * self.sbox(i).size_out() 100 | } 101 | 102 | fn linear_layer(&self, input: u128) -> u128 { 103 | let mut output = 0; 104 | 105 | // Apply PermuteCells 106 | for i in 0..16 { 107 | output ^= ((input >> (i * 4)) & 0xf) << (self.permute_cell_table[i] * 4); 108 | } 109 | 110 | // Apply MixColumns 111 | output = self.mix_columns(output); 112 | 113 | output 114 | } 115 | 116 | fn linear_layer_inv(&self, input: u128) -> u128 { 117 | // Apply MixColumns 118 | let output = self.mix_columns(input); 119 | 120 | // Apply inverse PermuteCells 121 | let mut tmp = 0; 122 | for i in 0..16 { 123 | tmp ^= ((output >> (i * 4)) & 0xf) << (self.ipermute_cell_table[i] * 4); 124 | } 125 | 126 | tmp 127 | } 128 | 129 | fn reflection_layer(&self, input: u128) -> u128 { 130 | // Note that this reflection layer is not as defined in 131 | // the specification. It is specified such that if the S-box 132 | // application before and after reflection is replaced by a full 133 | // round, this reflection layer ensures equivalent functionality. 134 | let mut output = self.mix_columns(input); 135 | output = self.mix_columns(output); 136 | output = self.mix_columns(output); 137 | 138 | output 139 | } 140 | 141 | #[allow(unused_variables)] 142 | fn key_schedule(&self, rounds: usize, key: &[u8]) -> Vec { 143 | panic!("Not implemented") 144 | } 145 | 146 | #[allow(unused_variables)] 147 | fn encrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 148 | panic!("Not implemented") 149 | } 150 | 151 | #[allow(unused_variables)] 152 | fn decrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 153 | panic!("Not implemented") 154 | } 155 | 156 | fn name(&self) -> String { 157 | String::from("QARMA") 158 | } 159 | 160 | fn sbox_mask_transform( 161 | &self, 162 | input: u128, 163 | output: u128, 164 | _property_type: PropertyType, 165 | ) -> (u128, u128) { 166 | (input, self.linear_layer(output)) 167 | } 168 | 169 | #[inline(always)] 170 | fn whitening(&self) -> bool { 171 | true 172 | } 173 | } 174 | 175 | impl Default for Qarma { 176 | fn default() -> Self { 177 | Qarma::new() 178 | } 179 | } 180 | 181 | #[cfg(test)] 182 | mod tests { 183 | use crate::cipher; 184 | 185 | #[test] 186 | fn linear() { 187 | let cipher = cipher::name_to_cipher("qarma").unwrap(); 188 | let x = 0x0123456789abcedf; 189 | assert_eq!(x, cipher.linear_layer(cipher.linear_layer_inv(x))); 190 | } 191 | 192 | #[test] 193 | fn reflection() { 194 | let cipher = cipher::name_to_cipher("qarma").unwrap(); 195 | let x = 0x0123456789abcedf; 196 | 197 | assert_eq!(x, cipher.reflection_layer(cipher.reflection_layer(x))); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/src/cipher/mcrypton.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of mCrpyton. 2 | 3 | use crate::cipher::{Cipher, CipherStructure}; 4 | use crate::property::PropertyType; 5 | use crate::sbox::Sbox; 6 | 7 | /***************************************************************** 8 | mCrypton 9 | ******************************************************************/ 10 | 11 | /// A structure representing the mCrypton cipher. 12 | #[derive(Clone)] 13 | pub struct Mcrypton { 14 | size: usize, 15 | key_size: usize, 16 | sbox0: Sbox, 17 | sbox1: Sbox, 18 | sbox2: Sbox, 19 | sbox3: Sbox, 20 | constants: [u128; 13], 21 | } 22 | 23 | impl Mcrypton { 24 | /// Create a new instance of the cipher. 25 | pub fn new() -> Mcrypton { 26 | let table0 = vec![4, 15, 3, 8, 13, 10, 12, 0, 11, 5, 7, 14, 2, 6, 1, 9]; 27 | let table1 = vec![1, 12, 7, 10, 6, 13, 5, 3, 15, 11, 2, 0, 8, 4, 9, 14]; 28 | let table2 = vec![7, 14, 12, 2, 0, 9, 13, 10, 3, 15, 5, 8, 6, 4, 11, 1]; 29 | let table3 = vec![11, 0, 10, 7, 13, 6, 4, 2, 12, 14, 3, 9, 1, 5, 15, 8]; 30 | 31 | let constants = [ 32 | 0x1111, 0x2222, 0x4444, 0x8888, 0x3333, 0x6666, 0xcccc, 0xbbbb, 0x5555, 0xaaaa, 0x7777, 33 | 0xeeee, 0xffff, 34 | ]; 35 | Mcrypton { 36 | size: 64, 37 | key_size: 64, 38 | sbox0: Sbox::new(4, 4, table0), 39 | sbox1: Sbox::new(4, 4, table1), 40 | sbox2: Sbox::new(4, 4, table2), 41 | sbox3: Sbox::new(4, 4, table3), 42 | constants, 43 | } 44 | } 45 | } 46 | 47 | impl Cipher for Mcrypton { 48 | fn structure(&self) -> CipherStructure { 49 | CipherStructure::Spn 50 | } 51 | 52 | fn size(&self) -> usize { 53 | self.size 54 | } 55 | 56 | fn key_size(&self) -> usize { 57 | self.key_size 58 | } 59 | 60 | fn num_sboxes(&self) -> usize { 61 | self.size / self.sbox0.size_in() 62 | } 63 | 64 | fn sbox(&self, i: usize) -> &Sbox { 65 | let j = ((i / 4) + (i % 4)) % 4; 66 | 67 | match j { 68 | 0 => &self.sbox0, 69 | 1 => &self.sbox1, 70 | 2 => &self.sbox2, 71 | 3 => &self.sbox3, 72 | _ => unreachable!(), 73 | } 74 | } 75 | 76 | fn sbox_pos_in(&self, i: usize) -> usize { 77 | i * self.sbox(i).size_in() 78 | } 79 | 80 | fn sbox_pos_out(&self, i: usize) -> usize { 81 | i * self.sbox(i).size_out() 82 | } 83 | 84 | fn linear_layer(&self, input: u128) -> u128 { 85 | let mut output = 0; 86 | 87 | // Apply pi 88 | let masks = [0b1110, 0b1101, 0b1011, 0b0111]; 89 | 90 | for c in 0..4 { 91 | for r in 0..4 { 92 | let mut m = masks[(c + r) % 4] 93 | ^ (masks[(c + r + 1) % 4] << 16) 94 | ^ (masks[(c + r + 2) % 4] << 32) 95 | ^ (masks[(c + r + 3) % 4] << 48); 96 | m <<= 4 * c; 97 | 98 | let x = (input & m) >> (4 * c); 99 | let y = (x & 0xf) ^ ((x >> 16) & 0xf) ^ ((x >> 32) & 0xf) ^ ((x >> 48) & 0xf); 100 | 101 | output ^= y << (4 * c + 16 * r); 102 | } 103 | } 104 | 105 | // Apply tau 106 | let tmp = output; 107 | output = 0; 108 | 109 | for c in 0..4 { 110 | for r in 0..4 { 111 | output ^= ((tmp >> (4 * c + 16 * r)) & 0xf) << (4 * r + 16 * c); 112 | } 113 | } 114 | 115 | output 116 | } 117 | 118 | fn linear_layer_inv(&self, input: u128) -> u128 { 119 | let mut output = 0; 120 | 121 | // Apply tau 122 | let tmp = input; 123 | 124 | for c in 0..4 { 125 | for r in 0..4 { 126 | output ^= ((tmp >> (4 * c + 16 * r)) & 0xf) << (4 * r + 16 * c); 127 | } 128 | } 129 | 130 | // Apply pi 131 | let tmp = output; 132 | output = 0; 133 | let masks = [0b1110, 0b1101, 0b1011, 0b0111]; 134 | 135 | for c in 0..4 { 136 | for r in 0..4 { 137 | let mut m = masks[(c + r) % 4] 138 | ^ (masks[(c + r + 1) % 4] << 16) 139 | ^ (masks[(c + r + 2) % 4] << 32) 140 | ^ (masks[(c + r + 3) % 4] << 48); 141 | m <<= 4 * c; 142 | 143 | let x = (tmp & m) >> (4 * c); 144 | let y = (x & 0xf) ^ ((x >> 16) & 0xf) ^ ((x >> 32) & 0xf) ^ ((x >> 48) & 0xf); 145 | 146 | output ^= y << (4 * c + 16 * r); 147 | } 148 | } 149 | 150 | output 151 | } 152 | 153 | fn reflection_layer(&self, _input: u128) -> u128 { 154 | panic!("Not implemented for this type of cipher") 155 | } 156 | 157 | fn key_schedule(&self, _rounds: usize, key: &[u8]) -> Vec { 158 | if key.len() * 8 != self.key_size { 159 | panic!("invalid key-length"); 160 | } 161 | 162 | panic!("Not implemented!") 163 | } 164 | 165 | fn encrypt(&self, _input: u128, _round_keys: &[u128]) -> u128 { 166 | panic!("Not implemented!") 167 | } 168 | 169 | fn decrypt(&self, _input: u128, _round_keys: &[u128]) -> u128 { 170 | panic!("Not implemented!") 171 | } 172 | 173 | fn name(&self) -> String { 174 | String::from("mCrypton") 175 | } 176 | 177 | fn sbox_mask_transform( 178 | &self, 179 | input: u128, 180 | output: u128, 181 | _property_type: PropertyType, 182 | ) -> (u128, u128) { 183 | (input, self.linear_layer(output)) 184 | } 185 | 186 | #[inline(always)] 187 | fn whitening(&self) -> bool { 188 | true 189 | } 190 | } 191 | 192 | impl Default for Mcrypton { 193 | fn default() -> Self { 194 | Mcrypton::new() 195 | } 196 | } 197 | 198 | #[cfg(test)] 199 | mod tests { 200 | use crate::cipher; 201 | 202 | #[test] 203 | fn linear_test() { 204 | let cipher = cipher::name_to_cipher("mcrypton").unwrap(); 205 | let x = 0x0123456789abcdef; 206 | 207 | assert_eq!(x, cipher.linear_layer_inv(cipher.linear_layer(x))); 208 | } 209 | 210 | /*#[test] 211 | fn encryption_decryption_test() { 212 | let cipher = cipher::name_to_cipher("mcrypton").unwrap(); 213 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 214 | let round_keys = cipher.key_schedule(12, &key); 215 | let plaintext = 0x0123456789abcdef; 216 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 217 | 218 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 219 | 220 | let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 221 | let round_keys = cipher.key_schedule(12, &key); 222 | let plaintext = 0x0123456789abcdef; 223 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 224 | 225 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 226 | }*/ 227 | } 228 | -------------------------------------------------------------------------------- /src/src/search/search_properties.rs: -------------------------------------------------------------------------------- 1 | //! Main functions for searching for properties of a cipher. 2 | 3 | use fnv::FnvHashSet; 4 | use std::fs::{File, OpenOptions}; 5 | use std::io::{BufRead, BufReader, Write}; 6 | use std::time::Instant; 7 | 8 | use crate::cipher::Cipher; 9 | use crate::property::{Property, PropertyType}; 10 | use crate::search::find_properties::parallel_find_properties; 11 | use crate::search::graph::MultistageGraph; 12 | use crate::search::graph_generate::generate_graph; 13 | 14 | /// Dumps a graph to file for plotting with python graph-tool. 15 | fn dump_to_graph_tool(graph: &MultistageGraph, path: &str) { 16 | let mut path = path.to_string(); 17 | path.push_str(".graph"); 18 | 19 | // Contents of previous files are overwritten 20 | let mut file = OpenOptions::new() 21 | .write(true) 22 | .truncate(true) 23 | .create(true) 24 | .open(path) 25 | .expect("Could not open file."); 26 | 27 | let stages = graph.stages(); 28 | 29 | for (tail, heads) in graph.forward_edges() { 30 | for (head, (edges, _)) in heads { 31 | for i in 0..stages { 32 | if (edges >> i) & 0x1 == 1 { 33 | writeln!(file, "{},{},{},{}", i, tail, i + 1, head) 34 | .expect("Could not write to file."); 35 | } 36 | } 37 | } 38 | } 39 | } 40 | 41 | /// Dumps all vertices of a graph to the file .set. 42 | fn dump_masks(graph: &MultistageGraph, file_mask_out: &str) { 43 | let mut file_set_path = file_mask_out.to_string(); 44 | file_set_path.push_str(".set"); 45 | 46 | // Collect edges and vertices 47 | let mut mask_set = FnvHashSet::::default(); 48 | mask_set.extend(graph.forward_edges().keys()); 49 | mask_set.extend(graph.backward_edges().keys()); 50 | 51 | // Contents of previous files are overwritten 52 | let mut file = OpenOptions::new() 53 | .write(true) 54 | .truncate(true) 55 | .create(true) 56 | .open(file_set_path) 57 | .expect("Could not open file."); 58 | 59 | for mask in &mask_set { 60 | writeln!(file, "{:032x}", mask).expect("Could not write to file."); 61 | } 62 | } 63 | 64 | /// Dumps a vector of properties to .app. 65 | fn dump_results(properties: &[Property], file_mask_out: &str) { 66 | let mut file_set_path = file_mask_out.to_string(); 67 | file_set_path.push_str(".app"); 68 | 69 | // Contents of previous files are overwritten 70 | let mut file = OpenOptions::new() 71 | .write(true) 72 | .truncate(true) 73 | .create(true) 74 | .open(file_set_path) 75 | .expect("Could not open file."); 76 | 77 | for property in properties { 78 | writeln!( 79 | file, 80 | "{:?},{},{}", 81 | property, 82 | property.trails, 83 | property.value.log2() 84 | ) 85 | .expect("Could not write to file."); 86 | } 87 | } 88 | 89 | /// Reads a file of allowed input and output values and stores them in a hash set. 90 | /// The values in the files are assumed to be in hexadecimals, without the '0x' prefix, and 91 | /// input/output masks should be separated by a comma. 92 | fn read_allowed(file_mask_in: &str) -> FnvHashSet<(u128, u128)> { 93 | let file = File::open(file_mask_in).expect("Could not open file."); 94 | let mut allowed = FnvHashSet::default(); 95 | 96 | for line in BufReader::new(file).lines() { 97 | let s = line.expect("Error reading file"); 98 | let split: Vec<_> = s.split(',').collect(); 99 | let alpha = u128::from_str_radix(split.get(0).expect("Could not read input data"), 16) 100 | .expect("Could not parse integer. Is it in hexadecimals?"); 101 | let beta = u128::from_str_radix(split.get(1).expect("Could not read input data"), 16) 102 | .expect("Could not parse integer. Is it in hexadecimals?"); 103 | allowed.insert((alpha, beta)); 104 | } 105 | 106 | allowed 107 | } 108 | 109 | /// Searches for properties over a given number of rounds for a given cipher. 110 | /// 111 | /// # Parameters 112 | /// * `cipher`: The cipher to investigate. 113 | /// * `property_type`: The type of property to search for. 114 | /// * `rounds`: The number of rounds to consider. 115 | /// * `patterns`: The number of S-box patterns to generate. Relates to the number of properties generate per round. 116 | /// * `file_mask_in`: Prefix of two files which restict the input/output values of the properties. 117 | /// * `file_mask_out`: Prefix of two files to which results are dumped. 118 | /// * `file_graph`: Prefix of a file to which raw graph data is dumped. 119 | #[cfg_attr(clippy, allow(too_many_arguments))] 120 | pub fn search_properties( 121 | cipher: &dyn Cipher, 122 | property_type: PropertyType, 123 | rounds: usize, 124 | patterns: usize, 125 | anchors: Option, 126 | file_mask_in: Option, 127 | file_mask_out: Option, 128 | num_keep: Option, 129 | file_graph: Option, 130 | ) { 131 | println!("\tCipher: {}.", cipher.name()); 132 | match property_type { 133 | PropertyType::Linear => println!("\tProperty: Linear"), 134 | PropertyType::Differential => println!("\tProperty: Differential"), 135 | } 136 | println!("\tRounds: {}.", rounds); 137 | println!("\tS-box patterns: {}", patterns); 138 | match anchors { 139 | Some(a) => println!("\tMaximum anchors: 2^{}", a), 140 | None => println!("\tMaximum anchors: 2^17"), 141 | } 142 | println!(); 143 | 144 | let start = Instant::now(); 145 | // Restrict the number of results printed 146 | let keep = match num_keep { 147 | Some(x) => x, 148 | None => 20, 149 | }; 150 | 151 | let allowed = match file_mask_in { 152 | Some(path) => read_allowed(&path), 153 | None => FnvHashSet::default(), 154 | }; 155 | 156 | println!("\n--------------------------------------- GENERATING GRAPH ---------------------------------------\n"); 157 | 158 | let graph = generate_graph(cipher, property_type, rounds, patterns, anchors, &allowed); 159 | 160 | if let Some(path) = file_graph { 161 | dump_to_graph_tool(&graph, &path); 162 | } 163 | 164 | if let Some(path) = &file_mask_out { 165 | dump_masks(&graph, path); 166 | } 167 | 168 | println!("\n------------------------------------- FINDING PROPERTIES ---------------------------------------\n"); 169 | 170 | let (result, min_value, paths) = 171 | parallel_find_properties(cipher, &graph, property_type, &allowed, keep); 172 | 173 | println!("\n------------------------------------------ RESULTS ---------------------------------------------\n"); 174 | 175 | println!("Search finished. [{:?} s]", start.elapsed().as_secs()); 176 | 177 | if !result.is_empty() { 178 | println!("Smallest value: {}", min_value.log2()); 179 | println!("Largest value: {}\n", result[0].value.log2()); 180 | println!("Total number of trails: {}", paths); 181 | } 182 | 183 | for &property in &result { 184 | if property.input == 0 && property.output == 0 { 185 | continue; 186 | } 187 | 188 | print!("Approximation: {:?} ", property); 189 | println!("[{}, {}]", property.trails, property.value.log2()); 190 | } 191 | 192 | if num_keep.is_some() && file_mask_out.is_some() { 193 | dump_results(&result, &file_mask_out.unwrap()); 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /src/src/cipher/epcbc96.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of EPCBC-96. 2 | 3 | use crate::cipher::{Cipher, CipherStructure}; 4 | use crate::property::PropertyType; 5 | use crate::sbox::Sbox; 6 | 7 | /***************************************************************** 8 | EPCBC96 9 | ******************************************************************/ 10 | 11 | /// A structure representing the EPCBC96 cipher. 12 | #[derive(Clone)] 13 | pub struct Epcbc96 { 14 | size: usize, 15 | key_size: usize, 16 | sbox: Sbox, 17 | isbox: Sbox, 18 | } 19 | 20 | impl Epcbc96 { 21 | const SBOX: [u8; 16] = [ 22 | 0xc, 0x5, 0x6, 0xb, 0x9, 0x0, 0xa, 0xd, 0x3, 0xe, 0xf, 0x8, 0x4, 0x7, 0x1, 0x2, 23 | ]; 24 | const ISBOX: [u8; 16] = [ 25 | 0x5, 0xe, 0xf, 0x8, 0xc, 0x1, 0x2, 0xd, 0xb, 0x4, 0x6, 0x3, 0x0, 0x7, 0x9, 0xa, 26 | ]; 27 | 28 | /// Create a new instance of the cipher. 29 | pub fn new() -> Epcbc96 { 30 | let table: Vec<_> = From::from(&Epcbc96::SBOX[0..]); 31 | let itable: Vec<_> = From::from(&Epcbc96::ISBOX[0..]); 32 | Epcbc96 { 33 | size: 96, 34 | key_size: 96, 35 | sbox: Sbox::new(4, 4, table), 36 | isbox: Sbox::new(4, 4, itable), 37 | } 38 | } 39 | } 40 | 41 | impl Cipher for Epcbc96 { 42 | fn structure(&self) -> CipherStructure { 43 | CipherStructure::Spn 44 | } 45 | 46 | fn size(&self) -> usize { 47 | self.size 48 | } 49 | 50 | fn key_size(&self) -> usize { 51 | self.key_size 52 | } 53 | 54 | fn num_sboxes(&self) -> usize { 55 | self.size / self.sbox.size_in() 56 | } 57 | 58 | fn sbox(&self, _i: usize) -> &Sbox { 59 | &self.sbox 60 | } 61 | 62 | fn sbox_pos_in(&self, i: usize) -> usize { 63 | i * self.sbox(i).size_in() 64 | } 65 | 66 | fn sbox_pos_out(&self, i: usize) -> usize { 67 | i * self.sbox(i).size_out() 68 | } 69 | 70 | fn linear_layer(&self, input: u128) -> u128 { 71 | let mut output = 0; 72 | 73 | for i in 0..self.size - 1 { 74 | output ^= ((input >> i) & 0x1) << ((i * self.size / 4) % (self.size - 1)); 75 | } 76 | output ^= ((input >> (self.size - 1)) & 0x1) << (self.size - 1); 77 | 78 | output 79 | } 80 | 81 | fn linear_layer_inv(&self, input: u128) -> u128 { 82 | let mut output = 0; 83 | 84 | for i in 0..self.size - 1 { 85 | output ^= ((input >> ((i * self.size / 4) % (self.size - 1))) & 0x1) << i; 86 | } 87 | output ^= ((input >> (self.size - 1)) & 0x1) << (self.size - 1); 88 | 89 | output 90 | } 91 | 92 | fn reflection_layer(&self, _input: u128) -> u128 { 93 | panic!("Not implemented for this type of cipher") 94 | } 95 | 96 | fn key_schedule(&self, rounds: usize, key: &[u8]) -> Vec { 97 | if key.len() * 8 != self.key_size { 98 | panic!("invalid key-length"); 99 | } 100 | 101 | let mut keys = vec![]; 102 | let mut k = 0; 103 | 104 | // load key into 80-bit state (s0 || s1) 105 | for &x in key.iter().take(12) { 106 | k <<= 8; 107 | k |= u128::from(x); 108 | } 109 | 110 | keys.push(k); 111 | 112 | for i in 0..rounds { 113 | // Apply S-box 114 | let mut tmp = 0; 115 | 116 | for j in 0..24 { 117 | tmp ^= u128::from(self.sbox.apply((k >> (4 * j)) & 0xf)) << (4 * j); 118 | } 119 | 120 | // Apply linear layer 121 | k = self.linear_layer(tmp); 122 | 123 | // Apply round constant 124 | k ^= i as u128; 125 | 126 | keys.push(k); 127 | } 128 | 129 | keys 130 | } 131 | 132 | fn encrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 133 | let mut output = input; 134 | 135 | output ^= round_keys[0]; 136 | 137 | for round_key in round_keys.iter().take(33).skip(1) { 138 | // Apply S-box 139 | let mut tmp = 0; 140 | 141 | for j in 0..24 { 142 | tmp ^= u128::from(self.sbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 143 | } 144 | 145 | // Apply linear layer 146 | output = self.linear_layer(tmp); 147 | 148 | // Add round key 149 | output ^= round_key 150 | } 151 | 152 | output 153 | } 154 | 155 | fn decrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 156 | let mut output = input; 157 | 158 | output ^= round_keys[32]; 159 | 160 | for i in 1..33 { 161 | // Apply linear layer 162 | output = self.linear_layer_inv(output); 163 | 164 | // Apply S-box 165 | let mut tmp = 0; 166 | 167 | for j in 0..24 { 168 | tmp ^= u128::from(self.isbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 169 | } 170 | 171 | // Add round key 172 | output = tmp ^ round_keys[32 - i] 173 | } 174 | 175 | output 176 | } 177 | 178 | fn name(&self) -> String { 179 | String::from("EPCBC96") 180 | } 181 | 182 | fn sbox_mask_transform( 183 | &self, 184 | input: u128, 185 | output: u128, 186 | _property_type: PropertyType, 187 | ) -> (u128, u128) { 188 | (input, self.linear_layer(output)) 189 | } 190 | 191 | #[inline(always)] 192 | fn whitening(&self) -> bool { 193 | true 194 | } 195 | } 196 | 197 | impl Default for Epcbc96 { 198 | fn default() -> Self { 199 | Epcbc96::new() 200 | } 201 | } 202 | 203 | #[cfg(test)] 204 | mod tests { 205 | use crate::cipher; 206 | 207 | #[test] 208 | fn linear() { 209 | let cipher = cipher::name_to_cipher("epcbc96").unwrap(); 210 | let x = 0x0123456789ab; 211 | 212 | assert_eq!(x, cipher.linear_layer_inv(cipher.linear_layer(x))); 213 | } 214 | 215 | #[test] 216 | fn encryption_test() { 217 | let cipher = cipher::name_to_cipher("epcbc96").unwrap(); 218 | let key = [ 219 | 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 220 | ]; 221 | let round_keys = cipher.key_schedule(32, &key); 222 | let plaintext = 0x0123456789ABCDEF01234567; 223 | let ciphertext = 0x408C65649781E6A5C9757244; 224 | 225 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 226 | } 227 | 228 | #[test] 229 | fn decryption_test() { 230 | let cipher = cipher::name_to_cipher("epcbc96").unwrap(); 231 | let key = [ 232 | 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 233 | ]; 234 | let round_keys = cipher.key_schedule(32, &key); 235 | let plaintext = 0x0123456789ABCDEF01234567; 236 | let ciphertext = 0x408C65649781E6A5C9757244; 237 | 238 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 239 | } 240 | 241 | #[test] 242 | fn encryption_decryption_test() { 243 | let cipher = cipher::name_to_cipher("epcbc96").unwrap(); 244 | let key = [ 245 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 246 | ]; 247 | let round_keys = cipher.key_schedule(32, &key); 248 | let plaintext = 0x000000000000; 249 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 250 | 251 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 252 | 253 | let key = [ 254 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 255 | ]; 256 | let round_keys = cipher.key_schedule(32, &key); 257 | let plaintext = 0xff; 258 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 259 | 260 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /src/src/cipher/epcbc48.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of EPCBC-48. 2 | 3 | use crate::cipher::{Cipher, CipherStructure}; 4 | use crate::property::PropertyType; 5 | use crate::sbox::Sbox; 6 | use std::mem; 7 | 8 | /***************************************************************** 9 | EPCBC48 10 | ******************************************************************/ 11 | 12 | //// A structure representing the EPCBC48 cipher. 13 | #[derive(Clone)] 14 | pub struct Epcbc48 { 15 | size: usize, 16 | key_size: usize, 17 | sbox: Sbox, 18 | isbox: Sbox, 19 | } 20 | 21 | impl Epcbc48 { 22 | const SBOX: [u8; 16] = [ 23 | 0xc, 0x5, 0x6, 0xb, 0x9, 0x0, 0xa, 0xd, 0x3, 0xe, 0xf, 0x8, 0x4, 0x7, 0x1, 0x2, 24 | ]; 25 | const ISBOX: [u8; 16] = [ 26 | 0x5, 0xe, 0xf, 0x8, 0xc, 0x1, 0x2, 0xd, 0xb, 0x4, 0x6, 0x3, 0x0, 0x7, 0x9, 0xa, 27 | ]; 28 | 29 | /// Create a new instance of the cipher. 30 | pub fn new() -> Epcbc48 { 31 | let table: Vec<_> = From::from(&Epcbc48::SBOX[0..]); 32 | let itable: Vec<_> = From::from(&Epcbc48::ISBOX[0..]); 33 | Epcbc48 { 34 | size: 48, 35 | key_size: 96, 36 | sbox: Sbox::new(4, 4, table), 37 | isbox: Sbox::new(4, 4, itable), 38 | } 39 | } 40 | } 41 | 42 | impl Cipher for Epcbc48 { 43 | fn structure(&self) -> CipherStructure { 44 | CipherStructure::Spn 45 | } 46 | 47 | fn size(&self) -> usize { 48 | self.size 49 | } 50 | 51 | fn key_size(&self) -> usize { 52 | self.key_size 53 | } 54 | 55 | fn num_sboxes(&self) -> usize { 56 | self.size / self.sbox.size_in() 57 | } 58 | 59 | fn sbox(&self, _i: usize) -> &Sbox { 60 | &self.sbox 61 | } 62 | 63 | fn sbox_pos_in(&self, i: usize) -> usize { 64 | i * self.sbox(i).size_in() 65 | } 66 | 67 | fn sbox_pos_out(&self, i: usize) -> usize { 68 | i * self.sbox(i).size_out() 69 | } 70 | 71 | fn linear_layer(&self, input: u128) -> u128 { 72 | let mut output = 0; 73 | 74 | for i in 0..self.size - 1 { 75 | output ^= ((input >> i) & 0x1) << ((i * self.size / 4) % (self.size - 1)); 76 | } 77 | output ^= ((input >> (self.size - 1)) & 0x1) << (self.size - 1); 78 | 79 | output 80 | } 81 | 82 | fn linear_layer_inv(&self, input: u128) -> u128 { 83 | let mut output = 0; 84 | 85 | for i in 0..self.size - 1 { 86 | output ^= ((input >> ((i * self.size / 4) % (self.size - 1))) & 0x1) << i; 87 | } 88 | output ^= ((input >> (self.size - 1)) & 0x1) << (self.size - 1); 89 | 90 | output 91 | } 92 | 93 | fn reflection_layer(&self, _input: u128) -> u128 { 94 | panic!("Not implemented for this type of cipher") 95 | } 96 | 97 | fn key_schedule(&self, rounds: usize, key: &[u8]) -> Vec { 98 | if key.len() * 8 != self.key_size { 99 | panic!("invalid key-length"); 100 | } 101 | 102 | let mut keys = vec![]; 103 | let mut l = 0; 104 | let mut r = 0; 105 | 106 | // load key into 80-bit state (s0 || s1) 107 | for i in 0..6 { 108 | l <<= 8; 109 | l |= u128::from(key[i]); 110 | 111 | r <<= 8; 112 | r |= u128::from(key[i + 6]); 113 | } 114 | 115 | keys.push(l); 116 | l ^= r; 117 | 118 | for i in 0..rounds { 119 | // Apply S-box 120 | let mut tmp = 0; 121 | 122 | for j in 0..12 { 123 | tmp ^= u128::from(self.sbox.apply((r >> (4 * j)) & 0xf)) << (4 * j); 124 | } 125 | 126 | // Apply linear layer 127 | r = self.linear_layer(tmp); 128 | 129 | // Apply round constant 130 | r ^= i as u128; 131 | 132 | keys.push(r); 133 | 134 | if (i + 1) % 4 == 0 { 135 | mem::swap(&mut l, &mut r); 136 | l ^= r; 137 | } 138 | } 139 | 140 | keys 141 | } 142 | 143 | fn encrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 144 | let mut output = input; 145 | 146 | output ^= round_keys[0]; 147 | 148 | for round_key in round_keys.iter().take(33).skip(1) { 149 | // Apply S-box 150 | let mut tmp = 0; 151 | 152 | for j in 0..12 { 153 | tmp ^= u128::from(self.sbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 154 | } 155 | 156 | // Apply linear layer 157 | output = self.linear_layer(tmp); 158 | 159 | // Add round key 160 | output ^= round_key 161 | } 162 | 163 | output 164 | } 165 | 166 | fn decrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 167 | let mut output = input; 168 | 169 | output ^= round_keys[32]; 170 | 171 | for i in 1..33 { 172 | // Apply linear layer 173 | output = self.linear_layer_inv(output); 174 | 175 | // Apply S-box 176 | let mut tmp = 0; 177 | 178 | for j in 0..12 { 179 | tmp ^= u128::from(self.isbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 180 | } 181 | 182 | // Add round key 183 | output = tmp ^ round_keys[32 - i] 184 | } 185 | 186 | output 187 | } 188 | 189 | fn name(&self) -> String { 190 | String::from("EPCBC48") 191 | } 192 | 193 | fn sbox_mask_transform( 194 | &self, 195 | input: u128, 196 | output: u128, 197 | _property_type: PropertyType, 198 | ) -> (u128, u128) { 199 | (input, self.linear_layer(output)) 200 | } 201 | 202 | #[inline(always)] 203 | fn whitening(&self) -> bool { 204 | true 205 | } 206 | } 207 | 208 | impl Default for Epcbc48 { 209 | fn default() -> Self { 210 | Epcbc48::new() 211 | } 212 | } 213 | 214 | #[cfg(test)] 215 | mod tests { 216 | use crate::cipher; 217 | 218 | #[test] 219 | fn linear() { 220 | let cipher = cipher::name_to_cipher("epcbc48").unwrap(); 221 | let x = 0x0123456789ab; 222 | 223 | assert_eq!(x, cipher.linear_layer_inv(cipher.linear_layer(x))); 224 | } 225 | 226 | #[test] 227 | fn encryption_test() { 228 | let cipher = cipher::name_to_cipher("epcbc48").unwrap(); 229 | let key = [ 230 | 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 231 | ]; 232 | let round_keys = cipher.key_schedule(32, &key); 233 | let plaintext = 0x0123456789AB; 234 | let ciphertext = 0x0B46B67143DC; 235 | 236 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 237 | } 238 | 239 | #[test] 240 | fn decryption_test() { 241 | let cipher = cipher::name_to_cipher("epcbc48").unwrap(); 242 | let key = [ 243 | 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 244 | ]; 245 | let round_keys = cipher.key_schedule(32, &key); 246 | let plaintext = 0x0123456789AB; 247 | let ciphertext = 0x0B46B67143DC; 248 | 249 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 250 | } 251 | 252 | #[test] 253 | fn encryption_decryption_test() { 254 | let cipher = cipher::name_to_cipher("epcbc48").unwrap(); 255 | let key = [ 256 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 257 | ]; 258 | let round_keys = cipher.key_schedule(32, &key); 259 | let plaintext = 0x000000000000; 260 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 261 | 262 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 263 | 264 | let key = [ 265 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 266 | ]; 267 | let round_keys = cipher.key_schedule(32, &key); 268 | let plaintext = 0xff; 269 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 270 | 271 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /src/src/search/find_properties.rs: -------------------------------------------------------------------------------- 1 | //! Functions for searching for properties once a graph has been generated. 2 | 3 | use crossbeam_utils; 4 | use fnv::FnvHashSet; 5 | use indexmap::IndexMap; 6 | use num_cpus; 7 | use std::f64; 8 | use std::sync::mpsc; 9 | use std::time::Instant; 10 | 11 | use crate::cipher::{Cipher, CipherStructure}; 12 | use crate::property::{Property, PropertyType}; 13 | use crate::search::graph::MultistageGraph; 14 | use crate::utility::ProgressBar; 15 | 16 | // The number of threads used for parallel calls is fixed 17 | lazy_static! { 18 | static ref THREADS: usize = num_cpus::get(); 19 | } 20 | 21 | /// Find all properties for a given graph starting with a specific input value. 22 | fn find_properties( 23 | cipher: &dyn Cipher, 24 | graph: &MultistageGraph, 25 | property_type: PropertyType, 26 | input: u128, 27 | ) -> IndexMap { 28 | let start_property = Property::new(input, input, 1.0, 1); 29 | 30 | // The edge map maps output values to properties over a number of rounds 31 | // It first contains an "empty" property 32 | let mut edge_map = IndexMap::new(); 33 | edge_map.insert(input, start_property); 34 | 35 | // Extend the edge map the desired number of rounds 36 | for r in 0..graph.stages() { 37 | let mut new_edge_map = IndexMap::new(); 38 | 39 | // Go through all edges (i.e. properties (input, output)) in the current map 40 | for (output, &property) in &edge_map { 41 | // Look up output in the single round map in order to extend one round 42 | if let Some(inputs) = graph.forward_edges().get(output) { 43 | for (&new_output, &(stages, length)) in inputs.iter() { 44 | if ((stages >> r) & 0x1) != 1 { 45 | continue; 46 | } 47 | 48 | // Either add the new path to the current property or create a new one 49 | let new_value = match property_type { 50 | PropertyType::Linear => length, 51 | PropertyType::Differential => length, 52 | }; 53 | 54 | let entry = new_edge_map 55 | .entry(new_output as u128) 56 | .or_insert(Property::new(property.input, new_output as u128, 0.0, 0)); 57 | 58 | (*entry).trails += property.trails; 59 | (*entry).value += property.value * new_value; 60 | } 61 | } 62 | } 63 | 64 | edge_map = new_edge_map; 65 | } 66 | 67 | // In case of Prince type cipher, go back through the graph as well 68 | if cipher.structure() == CipherStructure::Prince { 69 | // First apply reflection layer 70 | edge_map = edge_map 71 | .iter() 72 | .map(|(&k, &v)| (cipher.reflection_layer(k), v)) 73 | .collect(); 74 | 75 | // Extend the edge map the desired number of rounds backwards 76 | for r in 0..graph.stages() { 77 | let mut new_edge_map = IndexMap::new(); 78 | 79 | // Go through all backward edges (i.e. properties (input, output)) in the current map 80 | for (output, &property) in &edge_map { 81 | // Look up output in the single round map in order to extend one round 82 | if let Some(inputs) = graph.backward_edges().get(output) { 83 | for (&new_output, &(stages, length)) in inputs.iter() { 84 | if ((stages >> (graph.stages() - 1 - r)) & 0x1) != 1 { 85 | continue; 86 | } 87 | 88 | // Either add the new path to the current property or create a new one 89 | let new_value = match property_type { 90 | PropertyType::Linear => length, 91 | PropertyType::Differential => length, 92 | }; 93 | 94 | let entry = new_edge_map 95 | .entry(new_output as u128) 96 | .or_insert(Property::new(property.input, new_output as u128, 0.0, 0)); 97 | 98 | (*entry).trails += property.trails; 99 | (*entry).value += property.value * new_value; 100 | } 101 | } 102 | } 103 | 104 | edge_map = new_edge_map; 105 | } 106 | } 107 | 108 | edge_map 109 | } 110 | 111 | /// Find all properties for a given graph in a parallelised way. 112 | /// 113 | /// # Parameters 114 | /// * `cipher`: The cipher we are analysing. 115 | /// * `graph`: A graph generated with `generate_graph`. 116 | /// * `property_type': The type of property the graph represents. 117 | /// * `allowed`: A set of allowed input-output pairs. Properties not matching these are filtered. 118 | /// * `num_keep`: Only the best `num_keep` properties are returned. 119 | pub fn parallel_find_properties( 120 | cipher: &dyn Cipher, 121 | graph: &MultistageGraph, 122 | property_type: PropertyType, 123 | allowed: &FnvHashSet<(u128, u128)>, 124 | num_keep: usize, 125 | ) -> (Vec, f64, u128) { 126 | println!( 127 | "Finding properties ({} input values, {} edges):", 128 | graph.num_vertices(0), 129 | graph.num_edges() 130 | ); 131 | 132 | let start = Instant::now(); 133 | let (result_tx, result_rx) = mpsc::channel(); 134 | 135 | // Start scoped worker threads 136 | crossbeam_utils::thread::scope(|scope| { 137 | for t in 0..*THREADS { 138 | let result_tx = result_tx.clone(); 139 | 140 | scope.spawn(move |_| { 141 | let mut progress_bar = 142 | ProgressBar::new((0..graph.num_vertices(0)).skip(t).step_by(*THREADS).len()); 143 | let mut result = vec![]; 144 | let mut min_value = 1.0_f64; 145 | let mut num_found = 0; 146 | let mut paths = 0; 147 | 148 | // Split input values between threads and call find_properties 149 | for &input in graph 150 | .get_vertices_outgoing(0) 151 | .iter() 152 | .skip(t) 153 | .step_by(*THREADS) 154 | { 155 | let properties = find_properties(cipher, &graph, property_type, input as u128); 156 | num_found += properties.len(); 157 | 158 | for property in properties.values() { 159 | if allowed.is_empty() 160 | || allowed.contains(&(property.input, property.output)) 161 | { 162 | paths += property.trails; 163 | result.push(*property); 164 | } 165 | } 166 | 167 | // Only keep best properties 168 | result.sort_by(|a, b| b.value.partial_cmp(&a.value).unwrap()); 169 | 170 | if let Some(property) = result.last() { 171 | min_value = min_value.min(property.value); 172 | } 173 | 174 | result.truncate(num_keep); 175 | 176 | if t == 0 { 177 | progress_bar.increment(); 178 | } 179 | } 180 | 181 | result_tx 182 | .send((result, min_value, num_found, paths)) 183 | .expect("Thread could not send result"); 184 | }); 185 | } 186 | }) 187 | .expect("Threads failed to join."); 188 | 189 | // Collect results from all threads 190 | let mut paths = 0; 191 | let mut num_found = 0; 192 | let mut min_value = 1.0_f64; 193 | let mut result = vec![]; 194 | 195 | for _ in 0..*THREADS { 196 | let mut thread_result = result_rx.recv().expect("Main could not receive result"); 197 | 198 | result.append(&mut thread_result.0); 199 | min_value = min_value.min(thread_result.1); 200 | num_found += thread_result.2; 201 | paths += thread_result.3; 202 | } 203 | 204 | result.sort_by(|a, b| b.value.partial_cmp(&a.value).unwrap()); 205 | result.truncate(num_keep); 206 | 207 | println!( 208 | "\nFound {} properties. [{:?} s]", 209 | num_found, 210 | start.elapsed().as_secs() 211 | ); 212 | 213 | (result, min_value, paths) 214 | } 215 | -------------------------------------------------------------------------------- /src/src/cipher/gift64.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of GIFT-64. 2 | 3 | use crate::cipher::{Cipher, CipherStructure}; 4 | use crate::property::PropertyType; 5 | use crate::sbox::Sbox; 6 | 7 | /***************************************************************** 8 | GIFT64 9 | ******************************************************************/ 10 | 11 | /// A structure representing the GIFT64 cipher. 12 | #[derive(Clone)] 13 | pub struct Gift64 { 14 | size: usize, 15 | key_size: usize, 16 | sbox: Sbox, 17 | isbox: Sbox, 18 | constants: [u128; 48], 19 | } 20 | 21 | impl Gift64 { 22 | const PERMUTATION: [[u128; 0x100]; 8] = include!("data/gift.perm"); 23 | const PERMUTATION_INV: [[u128; 0x100]; 8] = include!("data/gift.perm.inv"); 24 | 25 | /// Create a new instance of the cipher. 26 | pub fn new() -> Gift64 { 27 | let table = vec![ 28 | 0x1, 0xa, 0x4, 0xc, 0x6, 0xf, 0x3, 0x9, 0x2, 0xd, 0xb, 0x7, 0x5, 0x0, 0x8, 0xe, 29 | ]; 30 | let itable = vec![ 31 | 0xd, 0x0, 0x8, 0x6, 0x2, 0xc, 0x4, 0xb, 0xe, 0x7, 0x1, 0xa, 0x3, 0x9, 0xf, 0x5, 32 | ]; 33 | let constants = [ 34 | 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3e, 0x3d, 0x3b, 0x37, 0x2f, 0x1e, 0x3c, 0x39, 0x33, 35 | 0x27, 0x0e, 0x1d, 0x3a, 0x35, 0x2b, 0x16, 0x2c, 0x18, 0x30, 0x21, 0x02, 0x05, 0x0b, 36 | 0x17, 0x2e, 0x1c, 0x38, 0x31, 0x23, 0x06, 0x0d, 0x1b, 0x36, 0x2d, 0x1a, 0x34, 0x29, 37 | 0x12, 0x24, 0x08, 0x11, 0x22, 0x04, 38 | ]; 39 | 40 | Gift64 { 41 | size: 64, 42 | key_size: 128, 43 | sbox: Sbox::new(4, 4, table), 44 | isbox: Sbox::new(4, 4, itable), 45 | constants, 46 | } 47 | } 48 | } 49 | 50 | impl Cipher for Gift64 { 51 | fn structure(&self) -> CipherStructure { 52 | CipherStructure::Spn 53 | } 54 | 55 | fn size(&self) -> usize { 56 | self.size 57 | } 58 | 59 | fn key_size(&self) -> usize { 60 | self.key_size 61 | } 62 | 63 | fn num_sboxes(&self) -> usize { 64 | self.size / self.sbox.size_in() 65 | } 66 | 67 | fn sbox(&self, _i: usize) -> &Sbox { 68 | &self.sbox 69 | } 70 | 71 | fn sbox_pos_in(&self, i: usize) -> usize { 72 | i * self.sbox(i).size_in() 73 | } 74 | 75 | fn sbox_pos_out(&self, i: usize) -> usize { 76 | i * self.sbox(i).size_out() 77 | } 78 | 79 | fn linear_layer(&self, input: u128) -> u128 { 80 | let mut output = 0; 81 | output ^= Gift64::PERMUTATION[0][((input) & 0xff) as usize]; 82 | output ^= Gift64::PERMUTATION[1][((input >> 8) & 0xff) as usize]; 83 | output ^= Gift64::PERMUTATION[2][((input >> 16) & 0xff) as usize]; 84 | output ^= Gift64::PERMUTATION[3][((input >> 24) & 0xff) as usize]; 85 | output ^= Gift64::PERMUTATION[4][((input >> 32) & 0xff) as usize]; 86 | output ^= Gift64::PERMUTATION[5][((input >> 40) & 0xff) as usize]; 87 | output ^= Gift64::PERMUTATION[6][((input >> 48) & 0xff) as usize]; 88 | output ^= Gift64::PERMUTATION[7][((input >> 56) & 0xff) as usize]; 89 | 90 | output 91 | } 92 | 93 | fn linear_layer_inv(&self, input: u128) -> u128 { 94 | let mut output = 0; 95 | output ^= Gift64::PERMUTATION_INV[0][((input) & 0xff) as usize]; 96 | output ^= Gift64::PERMUTATION_INV[1][((input >> 8) & 0xff) as usize]; 97 | output ^= Gift64::PERMUTATION_INV[2][((input >> 16) & 0xff) as usize]; 98 | output ^= Gift64::PERMUTATION_INV[3][((input >> 24) & 0xff) as usize]; 99 | output ^= Gift64::PERMUTATION_INV[4][((input >> 32) & 0xff) as usize]; 100 | output ^= Gift64::PERMUTATION_INV[5][((input >> 40) & 0xff) as usize]; 101 | output ^= Gift64::PERMUTATION_INV[6][((input >> 48) & 0xff) as usize]; 102 | output ^= Gift64::PERMUTATION_INV[7][((input >> 56) & 0xff) as usize]; 103 | 104 | output 105 | } 106 | 107 | fn reflection_layer(&self, _input: u128) -> u128 { 108 | panic!("Not implemented for this type of cipher") 109 | } 110 | 111 | fn key_schedule(&self, rounds: usize, key: &[u8]) -> Vec { 112 | if key.len() * 8 != self.key_size { 113 | panic!("invalid key-length"); 114 | } 115 | 116 | let mut keys = vec![]; 117 | let mut k1 = 0; 118 | let mut k0 = 0; 119 | 120 | // Load key into 128-bit state (k1 || k0) 121 | for i in 0..8 { 122 | k1 <<= 8; 123 | k0 <<= 8; 124 | k1 |= u128::from(key[i]); 125 | k0 |= u128::from(key[i + 8]); 126 | } 127 | 128 | for r in 0..rounds { 129 | let mut round_key = 0; 130 | 131 | for i in 0..16 { 132 | round_key ^= ((k0 >> i) & 0x1) << (4 * i); 133 | round_key ^= ((k0 >> (i + 16)) & 0x1) << (4 * i + 1); 134 | } 135 | 136 | round_key ^= 1 << 63; 137 | round_key ^= (self.constants[r] & 0x1) << 3; 138 | round_key ^= ((self.constants[r] >> 1) & 0x1) << 7; 139 | round_key ^= ((self.constants[r] >> 2) & 0x1) << 11; 140 | round_key ^= ((self.constants[r] >> 3) & 0x1) << 15; 141 | round_key ^= ((self.constants[r] >> 4) & 0x1) << 19; 142 | round_key ^= ((self.constants[r] >> 5) & 0x1) << 23; 143 | 144 | keys.push(round_key); 145 | 146 | let t0 = k0; 147 | let t1 = k1; 148 | 149 | k0 = (t0 >> 32) & 0xffffffffffffffff; 150 | k0 ^= (t1 << 32) & 0xffffffffffffffff; 151 | k1 = (t1 >> 32) & 0xffffffffffffffff; 152 | k1 ^= ((((t0 & 0xffff) >> 12) ^ ((t0 & 0xffff) << 4)) & 0xffff) << 32; 153 | k1 ^= ((((t0 & 0xffff0000) >> 2) ^ ((t0 & 0xffff0000) << 14)) & 0xffff0000) << 32; 154 | } 155 | 156 | keys 157 | } 158 | 159 | fn encrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 160 | let mut output = input; 161 | 162 | for round_key in round_keys.iter().take(28) { 163 | // Apply S-box 164 | let mut tmp = 0; 165 | 166 | for j in 0..16 { 167 | tmp ^= u128::from(self.sbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 168 | } 169 | 170 | // Apply linear layer 171 | output = self.linear_layer(tmp); 172 | 173 | // Add round key 174 | output ^= round_key; 175 | } 176 | 177 | output 178 | } 179 | 180 | fn decrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 181 | let mut output = input; 182 | 183 | for i in 0..28 { 184 | // Add round key 185 | output ^= round_keys[27 - i]; 186 | 187 | // Apply linear layer 188 | output = self.linear_layer_inv(output); 189 | 190 | // Apply S-box 191 | let mut tmp = 0; 192 | 193 | for j in 0..16 { 194 | tmp ^= u128::from(self.isbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 195 | } 196 | 197 | output = tmp; 198 | } 199 | 200 | output 201 | } 202 | 203 | fn name(&self) -> String { 204 | String::from("GIFT64") 205 | } 206 | 207 | fn sbox_mask_transform( 208 | &self, 209 | input: u128, 210 | output: u128, 211 | _property_type: PropertyType, 212 | ) -> (u128, u128) { 213 | (input, self.linear_layer(output)) 214 | } 215 | 216 | #[inline(always)] 217 | fn whitening(&self) -> bool { 218 | false 219 | } 220 | } 221 | 222 | impl Default for Gift64 { 223 | fn default() -> Self { 224 | Gift64::new() 225 | } 226 | } 227 | 228 | #[cfg(test)] 229 | mod tests { 230 | use crate::cipher; 231 | 232 | #[test] 233 | fn encryption_decryption_test() { 234 | let cipher = cipher::name_to_cipher("gift64").unwrap(); 235 | let key = [ 236 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 237 | 0x00, 0x00, 238 | ]; 239 | let round_keys = cipher.key_schedule(28, &key); 240 | let plaintext = 0x0123456789abcdef; 241 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 242 | 243 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 244 | 245 | let key = [ 246 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 247 | 0xff, 0xff, 248 | ]; 249 | let round_keys = cipher.key_schedule(28, &key); 250 | let plaintext = 0x0123456789abcdef; 251 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 252 | 253 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /src/src/cipher/gift128.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of GIFT-128. 2 | 3 | use crate::cipher::{Cipher, CipherStructure}; 4 | use crate::property::PropertyType; 5 | use crate::sbox::Sbox; 6 | 7 | /***************************************************************** 8 | GIFT128 9 | ******************************************************************/ 10 | 11 | /// A structure representing the GIFT128 cipher. 12 | #[derive(Clone)] 13 | pub struct Gift128 { 14 | size: usize, 15 | key_size: usize, 16 | sbox: Sbox, 17 | isbox: Sbox, 18 | constants: [u128; 48], 19 | perm: [u128; 128], 20 | iperm: [u128; 128], 21 | } 22 | 23 | impl Gift128 { 24 | /// Create a new instance of the cipher. 25 | pub fn new() -> Gift128 { 26 | let table = vec![ 27 | 0x1, 0xa, 0x4, 0xc, 0x6, 0xf, 0x3, 0x9, 0x2, 0xd, 0xb, 0x7, 0x5, 0x0, 0x8, 0xe, 28 | ]; 29 | let itable = vec![ 30 | 0xd, 0x0, 0x8, 0x6, 0x2, 0xc, 0x4, 0xb, 0xe, 0x7, 0x1, 0xa, 0x3, 0x9, 0xf, 0x5, 31 | ]; 32 | let constants = [ 33 | 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3e, 0x3d, 0x3b, 0x37, 0x2f, 0x1e, 0x3c, 0x39, 0x33, 34 | 0x27, 0x0e, 0x1d, 0x3a, 0x35, 0x2b, 0x16, 0x2c, 0x18, 0x30, 0x21, 0x02, 0x05, 0x0b, 35 | 0x17, 0x2e, 0x1c, 0x38, 0x31, 0x23, 0x06, 0x0d, 0x1b, 0x36, 0x2d, 0x1a, 0x34, 0x29, 36 | 0x12, 0x24, 0x08, 0x11, 0x22, 0x04, 37 | ]; 38 | let perm = [ 39 | 0, 33, 66, 99, 96, 1, 34, 67, 64, 97, 2, 35, 32, 65, 98, 3, 4, 37, 70, 103, 100, 5, 38, 40 | 71, 68, 101, 6, 39, 36, 69, 102, 7, 8, 41, 74, 107, 104, 9, 42, 75, 72, 105, 10, 43, 41 | 40, 73, 106, 11, 12, 45, 78, 111, 108, 13, 46, 79, 76, 109, 14, 47, 44, 77, 110, 15, 42 | 16, 49, 82, 115, 112, 17, 50, 83, 80, 113, 18, 51, 48, 81, 114, 19, 20, 53, 86, 119, 43 | 116, 21, 54, 87, 84, 117, 22, 55, 52, 85, 118, 23, 24, 57, 90, 123, 120, 25, 58, 91, 44 | 88, 121, 26, 59, 56, 89, 122, 27, 28, 61, 94, 127, 124, 29, 62, 95, 92, 125, 30, 63, 45 | 60, 93, 126, 31, 46 | ]; 47 | let iperm = [ 48 | 0, 5, 10, 15, 16, 21, 26, 31, 32, 37, 42, 47, 48, 53, 58, 63, 64, 69, 74, 79, 80, 85, 49 | 90, 95, 96, 101, 106, 111, 112, 117, 122, 127, 12, 1, 6, 11, 28, 17, 22, 27, 44, 33, 50 | 38, 43, 60, 49, 54, 59, 76, 65, 70, 75, 92, 81, 86, 91, 108, 97, 102, 107, 124, 113, 51 | 118, 123, 8, 13, 2, 7, 24, 29, 18, 23, 40, 45, 34, 39, 56, 61, 50, 55, 72, 77, 66, 71, 52 | 88, 93, 82, 87, 104, 109, 98, 103, 120, 125, 114, 119, 4, 9, 14, 3, 20, 25, 30, 19, 36, 53 | 41, 46, 35, 52, 57, 62, 51, 68, 73, 78, 67, 84, 89, 94, 83, 100, 105, 110, 99, 116, 54 | 121, 126, 115, 55 | ]; 56 | 57 | Gift128 { 58 | size: 128, 59 | key_size: 128, 60 | sbox: Sbox::new(4, 4, table), 61 | isbox: Sbox::new(4, 4, itable), 62 | constants, 63 | perm, 64 | iperm, 65 | } 66 | } 67 | } 68 | 69 | impl Cipher for Gift128 { 70 | fn structure(&self) -> CipherStructure { 71 | CipherStructure::Spn 72 | } 73 | 74 | fn size(&self) -> usize { 75 | self.size 76 | } 77 | 78 | fn key_size(&self) -> usize { 79 | self.key_size 80 | } 81 | 82 | fn num_sboxes(&self) -> usize { 83 | self.size / self.sbox.size_in() 84 | } 85 | 86 | fn sbox(&self, _i: usize) -> &Sbox { 87 | &self.sbox 88 | } 89 | 90 | fn sbox_pos_in(&self, i: usize) -> usize { 91 | i * self.sbox(i).size_in() 92 | } 93 | 94 | fn sbox_pos_out(&self, i: usize) -> usize { 95 | i * self.sbox(i).size_out() 96 | } 97 | 98 | fn linear_layer(&self, input: u128) -> u128 { 99 | let mut output = 0; 100 | 101 | for i in 0..128 { 102 | output ^= ((input >> i) & 0x1) << self.perm[i]; 103 | } 104 | 105 | output 106 | } 107 | 108 | fn linear_layer_inv(&self, input: u128) -> u128 { 109 | let mut output = 0; 110 | 111 | for i in 0..128 { 112 | output ^= ((input >> i) & 0x1) << self.iperm[i]; 113 | } 114 | 115 | output 116 | } 117 | 118 | fn reflection_layer(&self, _input: u128) -> u128 { 119 | panic!("Not implemented for this type of cipher") 120 | } 121 | 122 | fn key_schedule(&self, rounds: usize, key: &[u8]) -> Vec { 123 | if key.len() * 8 != self.key_size { 124 | panic!("invalid key-length"); 125 | } 126 | 127 | let mut keys = vec![]; 128 | let mut k1 = 0; 129 | let mut k0 = 0; 130 | 131 | // Load key into 128-bit state (k1 || k0) 132 | for i in 0..8 { 133 | k1 <<= 8; 134 | k0 <<= 8; 135 | k1 |= u128::from(key[i]); 136 | k0 |= u128::from(key[i + 8]); 137 | } 138 | 139 | for r in 0..rounds { 140 | let mut round_key = 0; 141 | 142 | for i in 0..32 { 143 | round_key ^= ((k0 >> i) & 0x1) << (4 * i + 1); 144 | round_key ^= ((k0 >> (i + 32)) & 0x1) << (4 * i + 2); 145 | } 146 | 147 | round_key ^= 1 << 127; 148 | round_key ^= (self.constants[r] & 0x1) << 3; 149 | round_key ^= ((self.constants[r] >> 1) & 0x1) << 7; 150 | round_key ^= ((self.constants[r] >> 2) & 0x1) << 11; 151 | round_key ^= ((self.constants[r] >> 3) & 0x1) << 15; 152 | round_key ^= ((self.constants[r] >> 4) & 0x1) << 19; 153 | round_key ^= ((self.constants[r] >> 5) & 0x1) << 23; 154 | 155 | keys.push(round_key); 156 | 157 | let t0 = k0; 158 | let t1 = k1; 159 | 160 | k0 = t0 >> 32; 161 | k0 ^= t1 << 32; 162 | k1 = t1 >> 32; 163 | k1 ^= ((((t0 & 0xffff) >> 12) ^ ((t0 & 0xffff) << 4)) & 0xffff) << 32; 164 | k1 ^= ((((t0 & 0xffff0000) >> 2) ^ ((t0 & 0xffff0000) << 14)) & 0xffff0000) << 32; 165 | } 166 | 167 | keys 168 | } 169 | 170 | fn encrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 171 | let mut output = input; 172 | 173 | for round_key in round_keys.iter().take(40) { 174 | // Apply S-box 175 | let mut tmp = 0; 176 | 177 | for j in 0..32 { 178 | tmp ^= u128::from(self.sbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 179 | } 180 | 181 | // Apply linear layer 182 | output = self.linear_layer(tmp); 183 | 184 | // Add round key 185 | output ^= round_key; 186 | } 187 | 188 | output 189 | } 190 | 191 | fn decrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 192 | let mut output = input; 193 | 194 | for i in 0..40 { 195 | // Add round key 196 | output ^= round_keys[39 - i]; 197 | 198 | // Apply linear layer 199 | output = self.linear_layer_inv(output); 200 | 201 | // Apply S-box 202 | let mut tmp = 0; 203 | 204 | for j in 0..32 { 205 | tmp ^= u128::from(self.isbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 206 | } 207 | 208 | output = tmp; 209 | } 210 | 211 | output 212 | } 213 | 214 | fn name(&self) -> String { 215 | String::from("GIFT128") 216 | } 217 | 218 | fn sbox_mask_transform( 219 | &self, 220 | input: u128, 221 | output: u128, 222 | _property_type: PropertyType, 223 | ) -> (u128, u128) { 224 | (input, self.linear_layer(output)) 225 | } 226 | 227 | #[inline(always)] 228 | fn whitening(&self) -> bool { 229 | false 230 | } 231 | } 232 | 233 | impl Default for Gift128 { 234 | fn default() -> Self { 235 | Gift128::new() 236 | } 237 | } 238 | 239 | #[cfg(test)] 240 | mod tests { 241 | use crate::cipher; 242 | 243 | #[test] 244 | fn encryption_decryption_test() { 245 | let cipher = cipher::name_to_cipher("gift128").unwrap(); 246 | let key = [ 247 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 248 | 0x00, 0x00, 249 | ]; 250 | let round_keys = cipher.key_schedule(40, &key); 251 | let plaintext = 0x00112233445566778899aabbccddeeff; 252 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 253 | 254 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 255 | 256 | let key = [ 257 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 258 | 0xff, 0xff, 259 | ]; 260 | let round_keys = cipher.key_schedule(40, &key); 261 | let plaintext = 0x00112233445566778899aabbccddeeff; 262 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 263 | 264 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /src/src/cipher/des.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of DES. 2 | 3 | use crate::cipher::{Cipher, CipherStructure}; 4 | use crate::property::PropertyType; 5 | use crate::sbox::Sbox; 6 | 7 | /***************************************************************** 8 | DES 9 | ******************************************************************/ 10 | 11 | /// A structure representing the DES cipher. 12 | #[derive(Clone)] 13 | pub struct Des { 14 | size: usize, 15 | key_size: usize, 16 | sbox0: Sbox, 17 | sbox1: Sbox, 18 | sbox2: Sbox, 19 | sbox3: Sbox, 20 | sbox4: Sbox, 21 | sbox5: Sbox, 22 | sbox6: Sbox, 23 | sbox7: Sbox, 24 | permute: [usize; 32], 25 | expand: [usize; 48], 26 | } 27 | 28 | impl Des { 29 | /// Create a new instance of the cipher. 30 | pub fn new() -> Des { 31 | let table0 = vec![ 32 | 0xd, 0x1, 0x2, 0xf, 0x8, 0xd, 0x4, 0x8, 0x6, 0xa, 0xf, 0x3, 0xb, 0x7, 0x1, 0x4, 0xa, 33 | 0xc, 0x9, 0x5, 0x3, 0x6, 0xe, 0xb, 0x5, 0x0, 0x0, 0xe, 0xc, 0x9, 0x7, 0x2, 0x7, 0x2, 34 | 0xb, 0x1, 0x4, 0xe, 0x1, 0x7, 0x9, 0x4, 0xc, 0xa, 0xe, 0x8, 0x2, 0xd, 0x0, 0xf, 0x6, 35 | 0xc, 0xa, 0x9, 0xd, 0x0, 0xf, 0x3, 0x3, 0x5, 0x5, 0x6, 0x8, 0xb, 36 | ]; 37 | let table1 = vec![ 38 | 0x4, 0xd, 0xb, 0x0, 0x2, 0xb, 0xe, 0x7, 0xf, 0x4, 0x0, 0x9, 0x8, 0x1, 0xd, 0xa, 0x3, 39 | 0xe, 0xc, 0x3, 0x9, 0x5, 0x7, 0xc, 0x5, 0x2, 0xa, 0xf, 0x6, 0x8, 0x1, 0x6, 0x1, 0x6, 40 | 0x4, 0xb, 0xb, 0xd, 0xd, 0x8, 0xc, 0x1, 0x3, 0x4, 0x7, 0xa, 0xe, 0x7, 0xa, 0x9, 0xf, 41 | 0x5, 0x6, 0x0, 0x8, 0xf, 0x0, 0xe, 0x5, 0x2, 0x9, 0x3, 0x2, 0xc, 42 | ]; 43 | let table2 = vec![ 44 | 0xc, 0xa, 0x1, 0xf, 0xa, 0x4, 0xf, 0x2, 0x9, 0x7, 0x2, 0xc, 0x6, 0x9, 0x8, 0x5, 0x0, 45 | 0x6, 0xd, 0x1, 0x3, 0xd, 0x4, 0xe, 0xe, 0x0, 0x7, 0xb, 0x5, 0x3, 0xb, 0x8, 0x9, 0x4, 46 | 0xe, 0x3, 0xf, 0x2, 0x5, 0xc, 0x2, 0x9, 0x8, 0x5, 0xc, 0xf, 0x3, 0xa, 0x7, 0xb, 0x0, 47 | 0xe, 0x4, 0x1, 0xa, 0x7, 0x1, 0x6, 0xd, 0x0, 0xb, 0x8, 0x6, 0xd, 48 | ]; 49 | let table3 = vec![ 50 | 0x2, 0xe, 0xc, 0xb, 0x4, 0x2, 0x1, 0xc, 0x7, 0x4, 0xa, 0x7, 0xb, 0xd, 0x6, 0x1, 0x8, 51 | 0x5, 0x5, 0x0, 0x3, 0xf, 0xf, 0xa, 0xd, 0x3, 0x0, 0x9, 0xe, 0x8, 0x9, 0x6, 0x4, 0xb, 52 | 0x2, 0x8, 0x1, 0xc, 0xb, 0x7, 0xa, 0x1, 0xd, 0xe, 0x7, 0x2, 0x8, 0xd, 0xf, 0x6, 0x9, 53 | 0xf, 0xc, 0x0, 0x5, 0x9, 0x6, 0xa, 0x3, 0x4, 0x0, 0x5, 0xe, 0x3, 54 | ]; 55 | let table4 = vec![ 56 | 0x7, 0xd, 0xd, 0x8, 0xe, 0xb, 0x3, 0x5, 0x0, 0x6, 0x6, 0xf, 0x9, 0x0, 0xa, 0x3, 0x1, 57 | 0x4, 0x2, 0x7, 0x8, 0x2, 0x5, 0xc, 0xb, 0x1, 0xc, 0xa, 0x4, 0xe, 0xf, 0x9, 0xa, 0x3, 58 | 0x6, 0xf, 0x9, 0x0, 0x0, 0x6, 0xc, 0xa, 0xb, 0x1, 0x7, 0xd, 0xd, 0x8, 0xf, 0x9, 0x1, 59 | 0x4, 0x3, 0x5, 0xe, 0xb, 0x5, 0xc, 0x2, 0x7, 0x8, 0x2, 0x4, 0xe, 60 | ]; 61 | let table5 = vec![ 62 | 0xa, 0xd, 0x0, 0x7, 0x9, 0x0, 0xe, 0x9, 0x6, 0x3, 0x3, 0x4, 0xf, 0x6, 0x5, 0xa, 0x1, 63 | 0x2, 0xd, 0x8, 0xc, 0x5, 0x7, 0xe, 0xb, 0xc, 0x4, 0xb, 0x2, 0xf, 0x8, 0x1, 0xd, 0x1, 64 | 0x6, 0xa, 0x4, 0xd, 0x9, 0x0, 0x8, 0x6, 0xf, 0x9, 0x3, 0x8, 0x0, 0x7, 0xb, 0x4, 0x1, 65 | 0xf, 0x2, 0xe, 0xc, 0x3, 0x5, 0xb, 0xa, 0x5, 0xe, 0x2, 0x7, 0xc, 66 | ]; 67 | let table6 = vec![ 68 | 0xf, 0x3, 0x1, 0xd, 0x8, 0x4, 0xe, 0x7, 0x6, 0xf, 0xb, 0x2, 0x3, 0x8, 0x4, 0xe, 0x9, 69 | 0xc, 0x7, 0x0, 0x2, 0x1, 0xd, 0xa, 0xc, 0x6, 0x0, 0x9, 0x5, 0xb, 0xa, 0x5, 0x0, 0xd, 70 | 0xe, 0x8, 0x7, 0xa, 0xb, 0x1, 0xa, 0x3, 0x4, 0xf, 0xd, 0x4, 0x1, 0x2, 0x5, 0xb, 0x8, 71 | 0x6, 0xc, 0x7, 0x6, 0xc, 0x9, 0x0, 0x3, 0x5, 0x2, 0xe, 0xf, 0x9, 72 | ]; 73 | let table7 = vec![ 74 | 0xe, 0x0, 0x4, 0xf, 0xd, 0x7, 0x1, 0x4, 0x2, 0xe, 0xf, 0x2, 0xb, 0xd, 0x8, 0x1, 0x3, 75 | 0xa, 0xa, 0x6, 0x6, 0xc, 0xc, 0xb, 0x5, 0x9, 0x9, 0x5, 0x0, 0x3, 0x7, 0x8, 0x4, 0xf, 76 | 0x1, 0xc, 0xe, 0x8, 0x8, 0x2, 0xd, 0x4, 0x6, 0x9, 0x2, 0x1, 0xb, 0x7, 0xf, 0x5, 0xc, 77 | 0xb, 0x9, 0x3, 0x7, 0xe, 0x3, 0xa, 0xa, 0x0, 0x5, 0x6, 0x0, 0xd, 78 | ]; 79 | 80 | let permute = [ 81 | 7, 28, 21, 10, 26, 2, 19, 13, 23, 29, 5, 0, 18, 8, 24, 30, 22, 1, 14, 27, 6, 9, 17, 31, 82 | 15, 4, 20, 3, 11, 12, 25, 16, 83 | ]; 84 | let expand = [ 85 | 31, 0, 1, 2, 3, 4, 3, 4, 5, 6, 7, 8, 7, 8, 9, 10, 11, 12, 11, 12, 13, 14, 15, 16, 15, 86 | 16, 17, 18, 19, 20, 19, 20, 21, 22, 23, 24, 23, 24, 25, 26, 27, 28, 27, 28, 29, 30, 31, 87 | 0, 88 | ]; 89 | 90 | Des { 91 | size: 64, 92 | key_size: 56, 93 | sbox0: Sbox::new(6, 4, table0), 94 | sbox1: Sbox::new(6, 4, table1), 95 | sbox2: Sbox::new(6, 4, table2), 96 | sbox3: Sbox::new(6, 4, table3), 97 | sbox4: Sbox::new(6, 4, table4), 98 | sbox5: Sbox::new(6, 4, table5), 99 | sbox6: Sbox::new(6, 4, table6), 100 | sbox7: Sbox::new(6, 4, table7), 101 | permute, 102 | expand, 103 | } 104 | } 105 | 106 | /// A "linear" version of the inverse expansion. Used for sbox_mask_transform 107 | fn inv_expand(&self, input: u128) -> u128 { 108 | let mut output = 0; 109 | 110 | for (i, j) in self.expand.iter().enumerate() { 111 | output ^= ((input >> i) & 0x1) << j; 112 | } 113 | 114 | output 115 | } 116 | } 117 | 118 | impl Cipher for Des { 119 | fn structure(&self) -> CipherStructure { 120 | CipherStructure::Feistel 121 | } 122 | 123 | fn size(&self) -> usize { 124 | self.size 125 | } 126 | 127 | fn key_size(&self) -> usize { 128 | self.key_size 129 | } 130 | 131 | fn num_sboxes(&self) -> usize { 132 | 16 133 | } 134 | 135 | fn sbox(&self, i: usize) -> &Sbox { 136 | match i { 137 | 0 => &self.sbox0, 138 | 1 => &self.sbox1, 139 | 2 => &self.sbox2, 140 | 3 => &self.sbox3, 141 | 4 => &self.sbox4, 142 | 5 => &self.sbox5, 143 | 6 => &self.sbox6, 144 | 7 => &self.sbox7, 145 | 8 => &self.sbox0, 146 | 9 => &self.sbox1, 147 | 10 => &self.sbox2, 148 | 11 => &self.sbox3, 149 | 12 => &self.sbox4, 150 | 13 => &self.sbox5, 151 | 14 => &self.sbox6, 152 | 15 => &self.sbox7, 153 | _ => panic!("S-box index out of bounds"), 154 | } 155 | } 156 | 157 | fn sbox_pos_in(&self, i: usize) -> usize { 158 | i * self.sbox(i).size_in() 159 | } 160 | 161 | fn sbox_pos_out(&self, i: usize) -> usize { 162 | i * self.sbox(i).size_out() 163 | } 164 | 165 | fn linear_layer(&self, input: u128) -> u128 { 166 | let mut output = 0; 167 | 168 | for (i, j) in self.permute.iter().enumerate() { 169 | output ^= ((input >> j) & 0x1) << i; 170 | } 171 | 172 | output 173 | } 174 | 175 | fn linear_layer_inv(&self, input: u128) -> u128 { 176 | let mut output = 0; 177 | 178 | for (i, j) in self.permute.iter().enumerate() { 179 | output ^= ((input >> i) & 0x1) << j; 180 | } 181 | 182 | output 183 | } 184 | 185 | fn reflection_layer(&self, _input: u128) -> u128 { 186 | panic!("Not implemented for this type of cipher") 187 | } 188 | 189 | fn key_schedule(&self, _rounds: usize, key: &[u8]) -> Vec { 190 | if key.len() * 8 != self.key_size { 191 | panic!("invalid key-length"); 192 | } 193 | 194 | panic!("Not implemented") 195 | } 196 | 197 | fn encrypt(&self, _input: u128, _round_keys: &[u128]) -> u128 { 198 | panic!("Not implemented") 199 | } 200 | 201 | fn decrypt(&self, _input: u128, _round_keys: &[u128]) -> u128 { 202 | panic!("Not implemented") 203 | } 204 | 205 | fn name(&self) -> String { 206 | String::from("DES") 207 | } 208 | 209 | fn sbox_mask_transform( 210 | &self, 211 | input: u128, 212 | output: u128, 213 | property_type: PropertyType, 214 | ) -> (u128, u128) { 215 | match property_type { 216 | PropertyType::Linear => { 217 | let input = 218 | self.inv_expand(input & 0xffffffffffff) ^ (self.inv_expand(input >> 48) << 32); 219 | let output = self.linear_layer(output & 0xffffffff) 220 | ^ ((self.linear_layer(output >> 32)) << 32); 221 | 222 | let mut alpha = ((output & 0xffffffff) << 32) ^ (output >> 32); 223 | alpha ^= input & 0xffffffff; 224 | 225 | let mut beta = ((output & 0xffffffff) << 32) ^ (output >> 32); 226 | beta ^= input & 0xffffffff00000000; 227 | 228 | (alpha, beta) 229 | } 230 | PropertyType::Differential => { 231 | panic!("Differentials are not implemented for DES"); 232 | } 233 | } 234 | } 235 | 236 | #[inline(always)] 237 | fn whitening(&self) -> bool { 238 | false 239 | } 240 | } 241 | 242 | impl Default for Des { 243 | fn default() -> Self { 244 | Des::new() 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /src/src/cipher/boron.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of BORON with an 80-bit key. 2 | 3 | use crate::cipher::{Cipher, CipherStructure}; 4 | use crate::property::PropertyType; 5 | use crate::sbox::Sbox; 6 | 7 | /***************************************************************** 8 | BORON 9 | ******************************************************************/ 10 | 11 | /// A structure representing the BORON cipher. 12 | #[derive(Clone)] 13 | pub struct Boron { 14 | size: usize, 15 | key_size: usize, 16 | sbox: Sbox, 17 | isbox: Sbox, 18 | } 19 | 20 | impl Boron { 21 | /// Create a new instance of the cipher. 22 | pub fn new() -> Boron { 23 | let table = vec![ 24 | 0xe, 0x4, 0xb, 0x1, 0x7, 0x9, 0xc, 0xa, 0xd, 0x2, 0x0, 0xf, 0x8, 0x5, 0x3, 0x6, 25 | ]; 26 | let itable = vec![ 27 | 0xa, 0x3, 0x9, 0xe, 0x1, 0xd, 0xf, 0x4, 0xc, 0x5, 0x7, 0x2, 0x6, 0x8, 0x0, 0xb, 28 | ]; 29 | 30 | Boron { 31 | size: 64, 32 | key_size: 80, 33 | sbox: Sbox::new(4, 4, table), 34 | isbox: Sbox::new(4, 4, itable), 35 | } 36 | } 37 | } 38 | 39 | impl Cipher for Boron { 40 | fn structure(&self) -> CipherStructure { 41 | CipherStructure::Spn 42 | } 43 | 44 | fn size(&self) -> usize { 45 | self.size 46 | } 47 | 48 | fn key_size(&self) -> usize { 49 | self.key_size 50 | } 51 | 52 | fn num_sboxes(&self) -> usize { 53 | self.size / self.sbox.size_in() 54 | } 55 | 56 | fn sbox(&self, _i: usize) -> &Sbox { 57 | &self.sbox 58 | } 59 | 60 | fn sbox_pos_in(&self, i: usize) -> usize { 61 | i * self.sbox(i).size_in() 62 | } 63 | 64 | fn sbox_pos_out(&self, i: usize) -> usize { 65 | i * self.sbox(i).size_out() 66 | } 67 | 68 | fn linear_layer(&self, input: u128) -> u128 { 69 | let mut output = 0; 70 | 71 | // Block shuffle 72 | output ^= (input & 0xff00ff00ff00ff00) >> 8; 73 | output ^= (input & 0x00ff00ff00ff00ff) << 8; 74 | 75 | // Permutation 76 | let tmp = output; 77 | output = 0; 78 | 79 | output ^= ((tmp << 1) & 0xfffe) ^ ((tmp >> 15) & 0x0001); 80 | output ^= ((tmp << 4) & 0xfff00000) ^ ((tmp >> 12) & 0x000f0000); 81 | output ^= ((tmp << 7) & 0xff8000000000) ^ ((tmp >> 9) & 0x007f00000000); 82 | output ^= ((tmp << 9) & 0xfe00000000000000) ^ ((tmp >> 7) & 0x01ff000000000000); 83 | 84 | // XOR 85 | output ^= (output & 0xffff) << 32; 86 | output ^= (output & 0xffff000000000000) >> 32; 87 | output ^= (output & 0xffff0000) >> 16; 88 | output ^= (output & 0xffff00000000) << 16; 89 | 90 | output 91 | } 92 | 93 | fn linear_layer_inv(&self, input: u128) -> u128 { 94 | let mut output = input; 95 | 96 | // XOR 97 | output ^= (output & 0xffff00000000) << 16; 98 | output ^= (output & 0xffff0000) >> 16; 99 | output ^= (output & 0xffff000000000000) >> 32; 100 | output ^= (output & 0xffff) << 32; 101 | 102 | // Permutation 103 | let tmp = output; 104 | output = 0; 105 | 106 | output ^= ((tmp & 0x0001) << 15) ^ ((tmp & 0xfffe) >> 1); 107 | output ^= ((tmp & 0x000f0000) << 12) ^ ((tmp & 0xfff00000) >> 4); 108 | output ^= ((tmp & 0x007f00000000) << 9) ^ ((tmp & 0xff8000000000) >> 7); 109 | output ^= ((tmp & 0x01ff000000000000) << 7) ^ ((tmp & 0xfe00000000000000) >> 9); 110 | 111 | // Block shuffle 112 | let tmp = output; 113 | output = 0; 114 | 115 | output ^= (tmp & 0xff00ff00ff00ff00) >> 8; 116 | output ^= (tmp & 0x00ff00ff00ff00ff) << 8; 117 | 118 | output 119 | } 120 | 121 | fn reflection_layer(&self, _input: u128) -> u128 { 122 | panic!("Not implemented for this type of cipher") 123 | } 124 | 125 | fn key_schedule(&self, rounds: usize, key: &[u8]) -> Vec { 126 | if key.len() * 8 != self.key_size { 127 | panic!("invalid key-length"); 128 | } 129 | 130 | let mut keys = vec![]; 131 | let mut s: u128 = 0; 132 | 133 | // load key into 80-bit state 134 | for &k in key.iter().take(10) { 135 | s <<= 8; 136 | s |= u128::from(k); 137 | } 138 | 139 | for r in 0..=rounds { 140 | keys.push(s & 0xffffffffffffffff); 141 | 142 | s = ((s << 13) & 0xffffffffffffffffffff) ^ ((s >> 67) & 0xffffffffffffffffffff); 143 | 144 | let tmp = s & 0xf; 145 | s &= 0xfffffffffffffffffff0; 146 | s ^= u128::from(self.sbox.apply(tmp)); 147 | 148 | let rnd = (r & 0b11111) as u128; 149 | s ^= rnd << 59; 150 | } 151 | 152 | keys 153 | } 154 | 155 | fn encrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 156 | let mut output = input; 157 | 158 | output ^= round_keys[0]; 159 | 160 | for round_key in round_keys.iter().take(26).skip(1) { 161 | // Apply S-box 162 | let mut tmp = 0; 163 | 164 | for j in 0..16 { 165 | tmp ^= u128::from(self.sbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 166 | } 167 | 168 | // Apply linear layer 169 | output = self.linear_layer(tmp); 170 | 171 | // Add round key 172 | output ^= round_key 173 | } 174 | 175 | output 176 | } 177 | 178 | fn decrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 179 | let mut output = input; 180 | 181 | output ^= round_keys[25]; 182 | 183 | for i in 1..26 { 184 | // Apply linear layer 185 | output = self.linear_layer_inv(output); 186 | 187 | // Apply S-box 188 | let mut tmp = 0; 189 | 190 | for j in 0..16 { 191 | tmp ^= u128::from(self.isbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 192 | } 193 | 194 | // Add round key 195 | output = tmp ^ round_keys[25 - i] 196 | } 197 | 198 | output 199 | } 200 | 201 | fn name(&self) -> String { 202 | String::from("BORON") 203 | } 204 | 205 | fn sbox_mask_transform( 206 | &self, 207 | input: u128, 208 | output: u128, 209 | _property_type: PropertyType, 210 | ) -> (u128, u128) { 211 | (input, self.linear_layer(output)) 212 | } 213 | 214 | #[inline(always)] 215 | fn whitening(&self) -> bool { 216 | true 217 | } 218 | } 219 | 220 | impl Default for Boron { 221 | fn default() -> Self { 222 | Boron::new() 223 | } 224 | } 225 | 226 | #[cfg(test)] 227 | mod tests { 228 | use crate::cipher; 229 | 230 | #[test] 231 | fn linear_test() { 232 | let cipher = cipher::name_to_cipher("boron").unwrap(); 233 | let x = 0x0123456789abcdef; 234 | 235 | assert_eq!(x, cipher.linear_layer_inv(cipher.linear_layer(x))); 236 | } 237 | 238 | #[test] 239 | fn encryption_test() { 240 | let cipher = cipher::name_to_cipher("boron").unwrap(); 241 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 242 | let round_keys = cipher.key_schedule(25, &key); 243 | let plaintext = 0x0000000000000000; 244 | let ciphertext = 0x3cf72a8b7518e6f7; 245 | 246 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 247 | 248 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 249 | let round_keys = cipher.key_schedule(25, &key); 250 | let plaintext = 0x0123456789abcdef; 251 | let ciphertext = 0x5a664928b961c619; 252 | 253 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 254 | } 255 | 256 | #[test] 257 | fn decryption_test() { 258 | let cipher = cipher::name_to_cipher("boron").unwrap(); 259 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 260 | let round_keys = cipher.key_schedule(25, &key); 261 | let plaintext = 0x0000000000000000; 262 | let ciphertext = 0x3cf72a8b7518e6f7; 263 | 264 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 265 | 266 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 267 | let round_keys = cipher.key_schedule(25, &key); 268 | let plaintext = 0x0123456789abcdef; 269 | let ciphertext = 0x5a664928b961c619; 270 | 271 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 272 | } 273 | 274 | #[test] 275 | fn encryption_decryption_test() { 276 | let cipher = cipher::name_to_cipher("boron").unwrap(); 277 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 278 | let round_keys = cipher.key_schedule(25, &key); 279 | let plaintext = 0x0123456789abcdef; 280 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 281 | 282 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 283 | 284 | let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 285 | let round_keys = cipher.key_schedule(25, &key); 286 | let plaintext = 0x0123456789abcdef; 287 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 288 | 289 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /src/src/cipher/iceberg.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of ICEBERG. 2 | 3 | use crate::cipher::{Cipher, CipherStructure}; 4 | use crate::property::PropertyType; 5 | use crate::sbox::Sbox; 6 | 7 | /***************************************************************** 8 | ICEBERG 9 | ******************************************************************/ 10 | 11 | /// A structure representing the ICEBERG cipher. 12 | #[derive(Clone)] 13 | pub struct Iceberg { 14 | size: usize, 15 | key_size: usize, 16 | sbox_8: Sbox, 17 | sbox_4: Sbox, 18 | table_64: [usize; 64], 19 | table_d: [u128; 16], 20 | table_4: [u128; 16], 21 | table_128: [usize; 128], 22 | } 23 | 24 | impl Iceberg { 25 | /// Create a new instance of the cipher. 26 | pub fn new() -> Iceberg { 27 | let sbox_8 = vec![ 28 | 0x24, 0xc1, 0x38, 0x30, 0xe7, 0x57, 0xdf, 0x20, 0x3e, 0x99, 0x1a, 0x34, 0xca, 0xd6, 29 | 0x52, 0xfd, 0x40, 0x6c, 0xd3, 0x3d, 0x4a, 0x59, 0xf8, 0x77, 0xfb, 0x61, 0x0a, 0x56, 30 | 0xb9, 0xd2, 0xfc, 0xf1, 0x07, 0xf5, 0x93, 0xcd, 0x00, 0xb6, 0x62, 0xa7, 0x63, 0xfe, 31 | 0x44, 0xbd, 0x5f, 0x92, 0x6b, 0x68, 0x03, 0x4e, 0xa2, 0x97, 0x0b, 0x60, 0x83, 0xa3, 32 | 0x02, 0xe5, 0x45, 0x67, 0xf4, 0x13, 0x08, 0x8b, 0x10, 0xce, 0xbe, 0xb4, 0x2a, 0x3a, 33 | 0x96, 0x84, 0xc8, 0x9f, 0x14, 0xc0, 0xc4, 0x6f, 0x31, 0xd9, 0xab, 0xae, 0x0e, 0x64, 34 | 0x7c, 0xda, 0x1b, 0x05, 0xa8, 0x15, 0xa5, 0x90, 0x94, 0x85, 0x71, 0x2c, 0x35, 0x19, 35 | 0x26, 0x28, 0x53, 0xe2, 0x7f, 0x3b, 0x2f, 0xa9, 0xcc, 0x2e, 0x11, 0x76, 0xed, 0x4d, 36 | 0x87, 0x5e, 0xc2, 0xc7, 0x80, 0xb0, 0x6d, 0x17, 0xb2, 0xff, 0xe4, 0xb7, 0x54, 0x9d, 37 | 0xb8, 0x66, 0x74, 0x9c, 0xdb, 0x36, 0x47, 0x5d, 0xde, 0x70, 0xd5, 0x91, 0xaa, 0x3f, 38 | 0xc9, 0xd8, 0xf3, 0xf2, 0x5b, 0x89, 0x2d, 0x22, 0x5c, 0xe1, 0x46, 0x33, 0xe6, 0x09, 39 | 0xbc, 0xe8, 0x81, 0x7d, 0xe9, 0x49, 0xe0, 0xb1, 0x32, 0x37, 0xea, 0x5a, 0xf6, 0x27, 40 | 0x58, 0x69, 0x8a, 0x50, 0xba, 0xdd, 0x51, 0xf9, 0x75, 0xa1, 0x78, 0xd0, 0x43, 0xf7, 41 | 0x25, 0x7b, 0x7e, 0x1c, 0xac, 0xd4, 0x9a, 0x2b, 0x42, 0xe3, 0x4b, 0x01, 0x72, 0xd7, 42 | 0x4c, 0xfa, 0xeb, 0x73, 0x48, 0x8c, 0x0c, 0xf0, 0x6a, 0x23, 0x41, 0xec, 0xb3, 0xef, 43 | 0x1d, 0x12, 0xbb, 0x88, 0x0d, 0xc3, 0x8d, 0x4f, 0x55, 0x82, 0xee, 0xad, 0x86, 0x06, 44 | 0xa0, 0x95, 0x65, 0xbf, 0x7a, 0x39, 0x98, 0x04, 0x9b, 0x9e, 0xa4, 0xc6, 0xcf, 0x6e, 45 | 0xdc, 0xd1, 0xcb, 0x1f, 0x8f, 0x8e, 0x3c, 0x21, 0xa6, 0xb5, 0x16, 0xaf, 0xc5, 0x18, 46 | 0x1e, 0x0f, 0x29, 0x79, 47 | ]; 48 | 49 | let sbox_4 = vec![ 50 | 0xd, 0x7, 0x3, 0x2, 0x9, 0xa, 0xc, 0x1, 0xf, 0x4, 0x5, 0xe, 0x6, 0x0, 0xb, 0x8, 51 | ]; 52 | let table_64 = [ 53 | 0, 12, 23, 25, 38, 42, 53, 59, 22, 9, 26, 32, 1, 47, 51, 61, 24, 37, 18, 41, 55, 58, 8, 54 | 2, 16, 3, 10, 27, 33, 46, 48, 62, 11, 28, 60, 49, 36, 17, 4, 43, 50, 19, 5, 39, 56, 45, 55 | 29, 13, 30, 35, 40, 14, 57, 6, 54, 20, 44, 52, 21, 7, 34, 15, 31, 63, 56 | ]; 57 | let table_d = [ 58 | 0x0, 0xe, 0xd, 0x3, 0xb, 0x5, 0x6, 0x8, 0x7, 0x9, 0xa, 0x4, 0xc, 0x2, 0x1, 0xf, 59 | ]; 60 | let table_4 = [ 61 | 0b0000, 0b0010, 0b0001, 0b0011, 0b1000, 0b1010, 0b1001, 0b1011, 0b0100, 0b0110, 0b0101, 62 | 0b0111, 0b1100, 0b1110, 0b1101, 0b1111, 63 | ]; 64 | let table_128 = [ 65 | 76, 110, 83, 127, 67, 114, 92, 97, 98, 65, 121, 106, 78, 112, 91, 82, 71, 101, 89, 126, 66 | 72, 107, 81, 118, 90, 124, 73, 88, 64, 104, 100, 85, 109, 87, 75, 113, 120, 66, 103, 67 | 115, 122, 108, 95, 69, 74, 116, 80, 102, 84, 96, 125, 68, 93, 105, 119, 79, 123, 86, 68 | 70, 117, 111, 77, 99, 94, 28, 9, 37, 4, 51, 43, 58, 16, 20, 26, 44, 34, 0, 61, 12, 55, 69 | 46, 22, 15, 2, 48, 31, 57, 33, 27, 18, 24, 14, 6, 52, 63, 42, 49, 7, 8, 62, 30, 17, 47, 70 | 38, 29, 53, 11, 21, 41, 32, 1, 60, 13, 35, 5, 39, 45, 59, 23, 54, 36, 10, 40, 56, 25, 71 | 50, 19, 3, 72 | ]; 73 | 74 | Iceberg { 75 | size: 64, 76 | key_size: 128, 77 | sbox_8: Sbox::new(8, 8, sbox_8), 78 | sbox_4: Sbox::new(4, 4, sbox_4), 79 | table_64, 80 | table_d, 81 | table_4, 82 | table_128, 83 | } 84 | } 85 | } 86 | 87 | impl Cipher for Iceberg { 88 | fn structure(&self) -> CipherStructure { 89 | CipherStructure::Spn 90 | } 91 | 92 | fn size(&self) -> usize { 93 | self.size 94 | } 95 | 96 | fn key_size(&self) -> usize { 97 | self.key_size 98 | } 99 | 100 | fn num_sboxes(&self) -> usize { 101 | self.size / self.sbox_8.size_in() 102 | } 103 | 104 | fn sbox(&self, _i: usize) -> &Sbox { 105 | &self.sbox_8 106 | } 107 | 108 | fn sbox_pos_in(&self, i: usize) -> usize { 109 | i * self.sbox(i).size_in() 110 | } 111 | 112 | fn sbox_pos_out(&self, i: usize) -> usize { 113 | i * self.sbox(i).size_out() 114 | } 115 | 116 | fn linear_layer(&self, input: u128) -> u128 { 117 | let mut output = 0; 118 | 119 | // Apply 64-bit permutation 120 | for i in 0..64 { 121 | output ^= ((input >> self.table_64[i]) & 0x1) << i; 122 | } 123 | 124 | // Apply matrix multiplication 125 | let tmp = output; 126 | output = 0; 127 | 128 | for i in 0..16 { 129 | output ^= self.table_d[((tmp >> (4 * i)) & 0xf) as usize] << (4 * i); 130 | } 131 | 132 | // Apply 4-bit permutation 133 | let tmp = output; 134 | output = 0; 135 | 136 | for i in 0..16 { 137 | output ^= self.table_4[((tmp >> (4 * i)) & 0xf) as usize] << (4 * i); 138 | } 139 | 140 | // Apply 64-bit permutation again 141 | let tmp = output; 142 | output = 0; 143 | 144 | for i in 0..64 { 145 | output ^= ((tmp >> self.table_64[i]) & 0x1) << i; 146 | } 147 | 148 | output 149 | } 150 | 151 | fn linear_layer_inv(&self, input: u128) -> u128 { 152 | let mut output = 0; 153 | 154 | // Apply 64-bit permutation 155 | for i in 0..64 { 156 | output ^= ((input >> self.table_64[i]) & 0x1) << i; 157 | } 158 | 159 | // Apply 4-bit permutation 160 | let tmp = output; 161 | output = 0; 162 | 163 | for i in 0..16 { 164 | output ^= self.table_4[((tmp >> (4 * i)) & 0xf) as usize] << (4 * i); 165 | } 166 | 167 | // Apply matrix multiplication 168 | let tmp = output; 169 | output = 0; 170 | 171 | for i in 0..16 { 172 | output ^= self.table_d[((tmp >> (4 * i)) & 0xf) as usize] << (4 * i); 173 | } 174 | 175 | // Apply 64-bit permutation again 176 | let tmp = output; 177 | output = 0; 178 | 179 | for i in 0..64 { 180 | output ^= ((tmp >> self.table_64[i]) & 0x1) << i; 181 | } 182 | 183 | output 184 | } 185 | 186 | fn reflection_layer(&self, _input: u128) -> u128 { 187 | panic!("Not implemented for this type of cipher") 188 | } 189 | 190 | fn key_schedule(&self, _rounds: usize, key: &[u8]) -> Vec { 191 | if key.len() * 8 != self.key_size { 192 | panic!("invalid key-length"); 193 | } 194 | 195 | panic!("Not implemented!") 196 | } 197 | 198 | fn encrypt(&self, _input: u128, _round_keys: &[u128]) -> u128 { 199 | panic!("Not implemented!") 200 | } 201 | 202 | fn decrypt(&self, _input: u128, _round_keys: &[u128]) -> u128 { 203 | panic!("Not implemented!") 204 | } 205 | 206 | fn name(&self) -> String { 207 | String::from("ICEBERG") 208 | } 209 | 210 | fn sbox_mask_transform( 211 | &self, 212 | input: u128, 213 | output: u128, 214 | _property_type: PropertyType, 215 | ) -> (u128, u128) { 216 | (input, self.linear_layer(output)) 217 | } 218 | 219 | #[inline(always)] 220 | fn whitening(&self) -> bool { 221 | true 222 | } 223 | } 224 | 225 | impl Default for Iceberg { 226 | fn default() -> Self { 227 | Iceberg::new() 228 | } 229 | } 230 | 231 | #[cfg(test)] 232 | mod tests { 233 | use crate::cipher; 234 | 235 | #[test] 236 | fn linear_test() { 237 | let cipher = cipher::name_to_cipher("iceberg").unwrap(); 238 | let x = 0x0123456789abcdef; 239 | 240 | assert_eq!(x, cipher.linear_layer_inv(cipher.linear_layer(x))); 241 | } 242 | 243 | /*#[test] 244 | fn encryption_decryption_test() { 245 | let cipher = cipher::name_to_cipher("mcrypton").unwrap(); 246 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 247 | let round_keys = cipher.key_schedule(12, &key); 248 | let plaintext = 0x0123456789abcdef; 249 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 250 | 251 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 252 | 253 | let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 254 | let round_keys = cipher.key_schedule(12, &key); 255 | let plaintext = 0x0123456789abcdef; 256 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 257 | 258 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 259 | }*/ 260 | } 261 | -------------------------------------------------------------------------------- /src/src/cipher/skinny64.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of SKINNY-64. 2 | 3 | use crate::cipher::{Cipher, CipherStructure}; 4 | use crate::property::PropertyType; 5 | use crate::sbox::Sbox; 6 | 7 | /***************************************************************** 8 | SKINNY 9 | ******************************************************************/ 10 | 11 | /// A structure representing the SKINNY cipher. 12 | #[derive(Clone)] 13 | pub struct Skinny64 { 14 | size: usize, 15 | key_size: usize, 16 | sbox: Sbox, 17 | isbox: Sbox, 18 | shift_rows_table: [usize; 16], 19 | ishift_rows_table: [usize; 16], 20 | key_permute: [usize; 16], 21 | constants: [u128; 48], 22 | } 23 | 24 | impl Skinny64 { 25 | /// Create a new instance of the cipher. 26 | pub fn new() -> Skinny64 { 27 | let table = vec![ 28 | 0xc, 0x6, 0x9, 0x0, 0x1, 0xa, 0x2, 0xb, 0x3, 0x8, 0x5, 0xd, 0x4, 0xe, 0x7, 0xf, 29 | ]; 30 | let itable = vec![ 31 | 0x3, 0x4, 0x6, 0x8, 0xc, 0xa, 0x1, 0xe, 0x9, 0x2, 0x5, 0x7, 0x0, 0xb, 0xd, 0xf, 32 | ]; 33 | let shift_rows_table = [0, 1, 2, 3, 5, 6, 7, 4, 10, 11, 8, 9, 15, 12, 13, 14]; 34 | let ishift_rows_table = [0, 1, 2, 3, 7, 4, 5, 6, 10, 11, 8, 9, 13, 14, 15, 12]; 35 | let key_permute = [8, 9, 10, 11, 12, 13, 14, 15, 2, 0, 4, 7, 6, 3, 5, 1]; 36 | let constants = [ 37 | 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3e, 0x3d, 0x3b, 0x37, 0x2f, 0x1e, 0x3c, 0x39, 0x33, 38 | 0x27, 0x0e, 0x1d, 0x3a, 0x35, 0x2b, 0x16, 0x2c, 0x18, 0x30, 0x21, 0x02, 0x05, 0x0b, 39 | 0x17, 0x2e, 0x1c, 0x38, 0x31, 0x23, 0x06, 0x0d, 0x1b, 0x36, 0x2d, 0x1a, 0x34, 0x29, 40 | 0x12, 0x24, 0x08, 0x11, 0x22, 0x04, 41 | ]; 42 | Skinny64 { 43 | size: 64, 44 | key_size: 64, 45 | sbox: Sbox::new(4, 4, table), 46 | isbox: Sbox::new(4, 4, itable), 47 | shift_rows_table, 48 | ishift_rows_table, 49 | key_permute, 50 | constants, 51 | } 52 | } 53 | } 54 | 55 | impl Cipher for Skinny64 { 56 | fn structure(&self) -> CipherStructure { 57 | CipherStructure::Spn 58 | } 59 | 60 | fn size(&self) -> usize { 61 | self.size 62 | } 63 | 64 | fn key_size(&self) -> usize { 65 | self.key_size 66 | } 67 | 68 | fn num_sboxes(&self) -> usize { 69 | self.size / self.sbox.size_in() 70 | } 71 | 72 | fn sbox(&self, _i: usize) -> &Sbox { 73 | &self.sbox 74 | } 75 | 76 | fn sbox_pos_in(&self, i: usize) -> usize { 77 | i * self.sbox(i).size_in() 78 | } 79 | 80 | fn sbox_pos_out(&self, i: usize) -> usize { 81 | i * self.sbox(i).size_out() 82 | } 83 | 84 | fn linear_layer(&self, input: u128) -> u128 { 85 | let mut output = 0; 86 | 87 | // Apply ShiftRows 88 | for i in 0..16 { 89 | output ^= ((input as u64 >> (i * 4)) & 0xf) << (self.shift_rows_table[i] * 4); 90 | } 91 | 92 | // Apply MixColumns 93 | output ^= (output & 0xffff00000000) >> 16; 94 | output ^= (output & 0xffff) << 32; 95 | output ^= (output & 0xffff00000000) << 16; 96 | output = (output << 16) ^ (output >> 48); 97 | 98 | u128::from(output) 99 | } 100 | 101 | fn linear_layer_inv(&self, input: u128) -> u128 { 102 | let mut output = input as u64; 103 | 104 | // Apply MixColumns 105 | output = (output >> 16) ^ (output << 48); 106 | output ^= (output & 0xffff00000000) << 16; 107 | output ^= (output & 0xffff) << 32; 108 | output ^= (output & 0xffff00000000) >> 16; 109 | 110 | // Apply ShiftRows 111 | let mut tmp = 0; 112 | 113 | for i in 0..16 { 114 | tmp ^= ((output >> (i * 4)) & 0xf) << (self.ishift_rows_table[i] * 4); 115 | } 116 | 117 | u128::from(tmp) 118 | } 119 | 120 | fn reflection_layer(&self, _input: u128) -> u128 { 121 | panic!("Not implemented for this type of cipher") 122 | } 123 | 124 | fn key_schedule(&self, rounds: usize, key: &[u8]) -> Vec { 125 | if key.len() * 8 != self.key_size { 126 | panic!("invalid key-length"); 127 | } 128 | 129 | let mut keys = vec![]; 130 | let mut k = 0; 131 | 132 | for &x in key.iter().take(8) { 133 | k <<= 8; 134 | k |= u128::from(x); 135 | } 136 | 137 | for _ in 0..rounds { 138 | let round_key = self.linear_layer(k & 0xffffffff); 139 | keys.push(round_key); 140 | 141 | let mut tmp = 0; 142 | 143 | // Apply permutation 144 | for i in 0..16 { 145 | tmp ^= ((k >> (i * 4)) & 0xf) << (self.key_permute[i] * 4); 146 | } 147 | 148 | k = tmp; 149 | } 150 | 151 | keys 152 | } 153 | 154 | fn encrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 155 | let mut output = input; 156 | 157 | for (i, round_key) in round_keys.iter().enumerate().take(32) { 158 | // Apply S-box 159 | let mut tmp = 0; 160 | 161 | for j in 0..16 { 162 | tmp ^= u128::from(self.sbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 163 | } 164 | 165 | // Add constants 166 | output = tmp; 167 | output ^= self.constants[i] & 0xf; 168 | output ^= (self.constants[i] >> 4) << 16; 169 | output ^= 0x2 << 32; 170 | 171 | // Shift + MixColumns 172 | output = self.linear_layer(output); 173 | 174 | // Add round key 175 | output ^= round_key; 176 | } 177 | 178 | output 179 | } 180 | 181 | fn decrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 182 | let mut output = input; 183 | 184 | for i in 0..32 { 185 | // Add round key 186 | output ^= round_keys[31 - i]; 187 | 188 | // Shift + MixColumns 189 | output = self.linear_layer_inv(output); 190 | 191 | // Add constants 192 | output ^= self.constants[31 - i] & 0xf; 193 | output ^= (self.constants[31 - i] >> 4) << 16; 194 | output ^= 0x2 << 32; 195 | 196 | // Apply S-box 197 | let mut tmp = 0; 198 | 199 | for j in 0..16 { 200 | tmp ^= u128::from(self.isbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 201 | } 202 | 203 | output = tmp; 204 | } 205 | 206 | output 207 | } 208 | 209 | fn name(&self) -> String { 210 | String::from("SKINNY64") 211 | } 212 | 213 | fn sbox_mask_transform( 214 | &self, 215 | input: u128, 216 | output: u128, 217 | _property_type: PropertyType, 218 | ) -> (u128, u128) { 219 | (input, self.linear_layer(output)) 220 | } 221 | 222 | #[inline(always)] 223 | fn whitening(&self) -> bool { 224 | false 225 | } 226 | } 227 | 228 | impl Default for Skinny64 { 229 | fn default() -> Self { 230 | Skinny64::new() 231 | } 232 | } 233 | 234 | #[cfg(test)] 235 | mod tests { 236 | use crate::cipher; 237 | 238 | #[test] 239 | fn encryption_test() { 240 | let cipher = cipher::name_to_cipher("skinny64").unwrap(); 241 | let key = [0x83, 0x21, 0x86, 0xcf, 0x62, 0x89, 0x62, 0x5f]; 242 | let round_keys = cipher.key_schedule(32, &key); 243 | let plaintext = 0xd91d427759f43060; 244 | let ciphertext = 0x7ca8b9242bfd93bb; 245 | 246 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 247 | 248 | let key = [0x83, 0x21, 0x86, 0xcf, 0x62, 0x89, 0x62, 0x5f]; 249 | let round_keys = cipher.key_schedule(32, &key); 250 | let plaintext = 0xd91d427759f43060; 251 | let ciphertext = 0x7ca8b9242bfd93bb; 252 | 253 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 254 | } 255 | 256 | #[test] 257 | fn decryption_test() { 258 | let cipher = cipher::name_to_cipher("skinny64").unwrap(); 259 | let key = [0x83, 0x21, 0x86, 0xcf, 0x62, 0x89, 0x62, 0x5f]; 260 | let round_keys = cipher.key_schedule(32, &key); 261 | let plaintext = 0xd91d427759f43060; 262 | let ciphertext = 0x7ca8b9242bfd93bb; 263 | 264 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 265 | 266 | let key = [0x83, 0x21, 0x86, 0xcf, 0x62, 0x89, 0x62, 0x5f]; 267 | let round_keys = cipher.key_schedule(32, &key); 268 | let plaintext = 0xd91d427759f43060; 269 | let ciphertext = 0x7ca8b9242bfd93bb; 270 | 271 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 272 | } 273 | 274 | #[test] 275 | fn encryption_decryption_test() { 276 | let cipher = cipher::name_to_cipher("skinny64").unwrap(); 277 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 278 | let round_keys = cipher.key_schedule(32, &key); 279 | let plaintext = 0x0123456789abcdef; 280 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 281 | 282 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 283 | 284 | let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 285 | let round_keys = cipher.key_schedule(32, &key); 286 | let plaintext = 0x0123456789abcdef; 287 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 288 | 289 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /src/src/cipher/tc05.rs: -------------------------------------------------------------------------------- 1 | use crate::cipher::{Cipher, CipherStructure}; 2 | use crate::property::PropertyType; 3 | use crate::sbox::Sbox; 4 | 5 | const SIGMA: [usize; 64] = [ 6 | 0, 16, 32, 48, 1, 17, 33, 49, 2, 18, 34, 50, 3, 19, 35, 51, 4, 20, 36, 52, 5, 21, 37, 53, 6, 7 | 22, 38, 54, 7, 23, 39, 55, 8, 24, 40, 56, 9, 25, 41, 57, 10, 26, 42, 58, 11, 27, 43, 59, 12, 8 | 28, 44, 60, 13, 29, 45, 61, 14, 30, 46, 62, 15, 31, 47, 63, 9 | ]; 10 | 11 | /// A structure representing the TC05_PRESENT toy cipher 12 | /// https://cryptanex.hideinplainsight.io/media/cipher_file/7/specification_TC05_PRESENT_1.pdf 13 | #[derive(Clone)] 14 | pub struct TC05 { 15 | size: usize, 16 | key_size: usize, 17 | sigma: [usize; 64], 18 | sigma_inv: [usize; 64], 19 | sbox: Sbox, 20 | isbox: Sbox, 21 | } 22 | 23 | impl TC05 { 24 | /// Create a new instance of the cipher. 25 | pub fn new() -> TC05 { 26 | let ins = TC05 { 27 | sbox: Sbox::new( 28 | 8, 29 | 8, 30 | vec![ 31 | 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 32 | 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 33 | 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 34 | 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 35 | 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 36 | 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 37 | 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 38 | 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 39 | 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 40 | 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 41 | 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 42 | 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 43 | 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 44 | 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 45 | 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 46 | 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 47 | 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 48 | 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 49 | 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 50 | 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, 51 | ], 52 | ), 53 | isbox: Sbox::new( 54 | 8, 55 | 8, 56 | vec![ 57 | 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 58 | 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 59 | 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 60 | 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, 0x08, 0x2E, 0xA1, 0x66, 61 | 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, 0x72, 62 | 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 63 | 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 64 | 0x57, 0xA7, 0x8D, 0x9D, 0x84, 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 65 | 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 66 | 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 67 | 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 68 | 0x73, 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 69 | 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 70 | 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 71 | 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, 0x1F, 0xDD, 0xA8, 72 | 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 73 | 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 74 | 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 75 | 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 76 | 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D, 77 | ], 78 | ), 79 | sigma: SIGMA, 80 | sigma_inv: TC05::invert_perm(), 81 | size: 64, 82 | key_size: 64, 83 | }; 84 | 85 | assert_eq!(ins.isbox.apply(ins.sbox.apply(0x77)), 0x77); 86 | assert_eq!(ins.isbox.apply(ins.sbox.apply(0x11)), 0x11); 87 | assert_eq!(ins.isbox.apply(ins.sbox.apply(0x00)), 0x00); 88 | 89 | ins 90 | } 91 | 92 | // helper function 93 | fn invert_perm() -> [usize; 64] { 94 | let mut sigma_inv = [0usize; 64]; 95 | for (from, to) in SIGMA.iter().enumerate() { 96 | sigma_inv[*to] = from; 97 | } 98 | 99 | assert!(sigma_inv[SIGMA[31]] == 31); 100 | assert!(sigma_inv[SIGMA[28]] == 28); 101 | assert!(sigma_inv[SIGMA[0]] == 0); 102 | 103 | sigma_inv 104 | } 105 | } 106 | 107 | impl Cipher for TC05 { 108 | fn structure(&self) -> CipherStructure { 109 | CipherStructure::Spn 110 | } 111 | 112 | fn size(&self) -> usize { 113 | self.size 114 | } 115 | 116 | fn key_size(&self) -> usize { 117 | self.key_size 118 | } 119 | 120 | fn num_sboxes(&self) -> usize { 121 | self.size / self.sbox.size_in() 122 | } 123 | 124 | fn sbox(&self, _i: usize) -> &Sbox { 125 | &self.sbox 126 | } 127 | 128 | fn sbox_pos_in(&self, i: usize) -> usize { 129 | i * self.sbox(i).size_in() 130 | } 131 | 132 | fn sbox_pos_out(&self, i: usize) -> usize { 133 | i * self.sbox(i).size_out() 134 | } 135 | 136 | fn linear_layer(&self, input: u128) -> u128 { 137 | let mut tmp = input; 138 | let mut out: u128 = 0; 139 | for to in self.sigma.iter() { 140 | out |= (tmp & 1) << to; 141 | tmp >>= 1; 142 | } 143 | out 144 | } 145 | 146 | fn linear_layer_inv(&self, input: u128) -> u128 { 147 | let mut tmp = input; 148 | let mut out: u128 = 0; 149 | for to in self.sigma_inv.iter() { 150 | out |= (tmp & 1) << to; 151 | tmp >>= 1; 152 | } 153 | out 154 | } 155 | 156 | fn key_schedule(&self, rounds: usize, key: &[u8]) -> Vec { 157 | assert_eq!(key.len(), 8, "64-bit key expected"); 158 | 159 | let mut st: u64 = 0; 160 | for &k in key.iter().take(8) { 161 | st <<= 8; 162 | st |= u64::from(k); 163 | } 164 | 165 | let mut keys = vec![]; 166 | for _ in 0..rounds { 167 | keys.push(u128::from(st)); 168 | st = st.rotate_right(15) ^ 0x3; 169 | } 170 | 171 | keys 172 | } 173 | 174 | fn encrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 175 | let mut st = input; 176 | 177 | for key in round_keys.iter() { 178 | // apply S-Boxes 179 | let mut tmp: u128 = 0; 180 | for i in 0..self.num_sboxes() { 181 | tmp |= u128::from(self.sbox(i).apply(st & 0xff)) << (i * 8); 182 | st >>= self.sbox(i).size_in(); 183 | } 184 | assert_eq!(st, 0); 185 | st = tmp; 186 | 187 | // apply linear layer 188 | st = self.linear_layer(st); 189 | 190 | // add round key 191 | st ^= key; 192 | } 193 | 194 | st 195 | } 196 | 197 | fn decrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 198 | let mut st = input; 199 | let mut round_keys = round_keys.to_vec(); 200 | round_keys.reverse(); 201 | 202 | for key in round_keys.iter() { 203 | // add round key 204 | st ^= key; 205 | 206 | // apply linear layer 207 | st = self.linear_layer_inv(st); 208 | 209 | // apply S-Boxes 210 | let mut tmp: u128 = 0; 211 | for i in 0..self.num_sboxes() { 212 | tmp |= u128::from(self.isbox.apply(st & 0xff)) << (i * 8); 213 | st >>= self.sbox(i).size_in(); 214 | } 215 | assert!(st == 0); 216 | st = tmp; 217 | } 218 | 219 | st 220 | } 221 | 222 | fn name(&self) -> String { 223 | String::from("TC05_PRESENT") 224 | } 225 | 226 | fn sbox_mask_transform( 227 | &self, 228 | input: u128, 229 | output: u128, 230 | _property_type: PropertyType, 231 | ) -> (u128, u128) { 232 | (input, self.linear_layer(output)) 233 | } 234 | 235 | #[inline(always)] 236 | fn whitening(&self) -> bool { 237 | false 238 | } 239 | } 240 | 241 | impl Default for TC05 { 242 | fn default() -> Self { 243 | TC05::new() 244 | } 245 | } 246 | 247 | cipher_test_suite!(TC05); 248 | -------------------------------------------------------------------------------- /src/src/cipher/present.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of PRESENT with an 80-bit key. 2 | 3 | use crate::cipher::{Cipher, CipherStructure}; 4 | use crate::property::PropertyType; 5 | use crate::sbox::Sbox; 6 | 7 | /***************************************************************** 8 | PRESENT 9 | ******************************************************************/ 10 | 11 | /// A structure representing the PRESENT cipher. 12 | #[derive(Clone)] 13 | pub struct Present { 14 | size: usize, 15 | key_size: usize, 16 | sbox: Sbox, 17 | isbox: Sbox, 18 | } 19 | 20 | impl Present { 21 | const PERMUTATION_INV: [[u128; 0x100]; 8] = include!("data/present.inv.perm"); 22 | const PERMUTATION: [[u128; 0x100]; 8] = include!("data/present.perm"); 23 | const SBOX: [u8; 16] = [ 24 | 0xc, 0x5, 0x6, 0xb, 0x9, 0x0, 0xa, 0xd, 0x3, 0xe, 0xf, 0x8, 0x4, 0x7, 0x1, 0x2, 25 | ]; 26 | const ISBOX: [u8; 16] = [ 27 | 0x5, 0xe, 0xf, 0x8, 0xc, 0x1, 0x2, 0xd, 0xb, 0x4, 0x6, 0x3, 0x0, 0x7, 0x9, 0xa, 28 | ]; 29 | 30 | /// Create a new instance of the cipher. 31 | pub fn new() -> Present { 32 | let table: Vec<_> = From::from(&Present::SBOX[0..]); 33 | let itable: Vec<_> = From::from(&Present::ISBOX[0..]); 34 | Present { 35 | size: 64, 36 | key_size: 80, 37 | sbox: Sbox::new(4, 4, table), 38 | isbox: Sbox::new(4, 4, itable), 39 | } 40 | } 41 | } 42 | 43 | impl Cipher for Present { 44 | fn structure(&self) -> CipherStructure { 45 | CipherStructure::Spn 46 | } 47 | 48 | fn size(&self) -> usize { 49 | self.size 50 | } 51 | 52 | fn key_size(&self) -> usize { 53 | self.key_size 54 | } 55 | 56 | fn num_sboxes(&self) -> usize { 57 | self.size / self.sbox.size_in() 58 | } 59 | 60 | fn sbox(&self, _i: usize) -> &Sbox { 61 | &self.sbox 62 | } 63 | 64 | fn sbox_pos_in(&self, i: usize) -> usize { 65 | i * self.sbox(i).size_in() 66 | } 67 | 68 | fn sbox_pos_out(&self, i: usize) -> usize { 69 | i * self.sbox(i).size_out() 70 | } 71 | 72 | fn linear_layer(&self, input: u128) -> u128 { 73 | let mut output = 0; 74 | output ^= Present::PERMUTATION[0][((input as u64) & 0xff) as usize]; 75 | output ^= Present::PERMUTATION[1][((input as u64 >> 8) & 0xff) as usize]; 76 | output ^= Present::PERMUTATION[2][((input as u64 >> 16) & 0xff) as usize]; 77 | output ^= Present::PERMUTATION[3][((input as u64 >> 24) & 0xff) as usize]; 78 | output ^= Present::PERMUTATION[4][((input as u64 >> 32) & 0xff) as usize]; 79 | output ^= Present::PERMUTATION[5][((input as u64 >> 40) & 0xff) as usize]; 80 | output ^= Present::PERMUTATION[6][((input as u64 >> 48) & 0xff) as usize]; 81 | output ^= Present::PERMUTATION[7][((input as u64 >> 56) & 0xff) as usize]; 82 | 83 | output as u128 84 | } 85 | 86 | fn linear_layer_inv(&self, input: u128) -> u128 { 87 | let mut output = 0; 88 | output ^= Present::PERMUTATION_INV[0][((input as u64) & 0xff) as usize]; 89 | output ^= Present::PERMUTATION_INV[1][((input as u64 >> 8) & 0xff) as usize]; 90 | output ^= Present::PERMUTATION_INV[2][((input as u64 >> 16) & 0xff) as usize]; 91 | output ^= Present::PERMUTATION_INV[3][((input as u64 >> 24) & 0xff) as usize]; 92 | output ^= Present::PERMUTATION_INV[4][((input as u64 >> 32) & 0xff) as usize]; 93 | output ^= Present::PERMUTATION_INV[5][((input as u64 >> 40) & 0xff) as usize]; 94 | output ^= Present::PERMUTATION_INV[6][((input as u64 >> 48) & 0xff) as usize]; 95 | output ^= Present::PERMUTATION_INV[7][((input as u64 >> 56) & 0xff) as usize]; 96 | 97 | output as u128 98 | } 99 | 100 | fn reflection_layer(&self, _input: u128) -> u128 { 101 | panic!("Not implemented for this type of cipher") 102 | } 103 | 104 | fn key_schedule(&self, rounds: usize, key: &[u8]) -> Vec { 105 | if key.len() * 8 != self.key_size { 106 | panic!("invalid key-length"); 107 | } 108 | 109 | let mut keys = vec![]; 110 | let mut s0: u64 = 0; 111 | let mut s1: u64 = 0; 112 | 113 | // load key into 80-bit state (s0 || s1) 114 | for &k in key.iter().take(8) { 115 | s0 <<= 8; 116 | s0 |= u64::from(k); 117 | } 118 | 119 | s1 |= u64::from(key[8]); 120 | s1 <<= 8; 121 | s1 |= u64::from(key[9]); 122 | 123 | for r in 0..=rounds { 124 | // extract round key 125 | keys.push(s0); 126 | 127 | // rotate 61-bits left 128 | assert!(s1 >> 16 == 0); 129 | 130 | { 131 | let mut t0: u64 = 0; 132 | t0 |= s0 << 61; 133 | t0 |= s1 << (64 - (3 + 16)); 134 | t0 |= s0 >> 19; 135 | 136 | s1 = (s0 >> 3) & 0xffff; 137 | s0 = t0; 138 | } 139 | 140 | // apply sbox to 4 MSBs 141 | { 142 | let x = s0 >> 60; 143 | let y = u64::from(Present::SBOX[x as usize]); 144 | s0 &= 0x0fffffffffffffff; 145 | s0 |= y << 60; 146 | } 147 | 148 | // add round constant 149 | let rnd = ((r + 1) & 0b11111) as u64; 150 | s0 ^= rnd >> 1; 151 | s1 ^= (rnd & 1) << 15; 152 | } 153 | 154 | keys.iter().map(|&x| u128::from(x)).collect() 155 | } 156 | 157 | fn encrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 158 | let mut output = input; 159 | 160 | output ^= round_keys[0]; 161 | 162 | for round_key in round_keys.iter().take(32).skip(1) { 163 | // Apply S-box 164 | let mut tmp = 0; 165 | 166 | for j in 0..16 { 167 | tmp ^= u128::from(self.sbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 168 | } 169 | 170 | // Apply linear layer 171 | output = self.linear_layer(tmp); 172 | 173 | // Add round key 174 | output ^= round_key 175 | } 176 | 177 | output 178 | } 179 | 180 | fn decrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 181 | let mut output = input; 182 | 183 | output ^= round_keys[31]; 184 | 185 | for i in 1..32 { 186 | // Apply linear layer 187 | output = self.linear_layer_inv(output); 188 | 189 | // Apply S-box 190 | let mut tmp = 0; 191 | 192 | for j in 0..16 { 193 | tmp ^= u128::from(self.isbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 194 | } 195 | 196 | // Add round key 197 | output = tmp ^ round_keys[31 - i] 198 | } 199 | 200 | output 201 | } 202 | 203 | fn name(&self) -> String { 204 | String::from("PRESENT") 205 | } 206 | 207 | fn sbox_mask_transform( 208 | &self, 209 | input: u128, 210 | output: u128, 211 | _property_type: PropertyType, 212 | ) -> (u128, u128) { 213 | (input, self.linear_layer(output)) 214 | } 215 | 216 | #[inline(always)] 217 | fn whitening(&self) -> bool { 218 | true 219 | } 220 | } 221 | 222 | impl Default for Present { 223 | fn default() -> Self { 224 | Present::new() 225 | } 226 | } 227 | 228 | #[cfg(test)] 229 | mod tests { 230 | use crate::cipher; 231 | 232 | #[test] 233 | fn encryption_test() { 234 | let cipher = cipher::name_to_cipher("present").unwrap(); 235 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 236 | let round_keys = cipher.key_schedule(31, &key); 237 | let plaintext = 0x0000000000000000; 238 | let ciphertext = 0x5579c1387b228445; 239 | 240 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 241 | 242 | let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 243 | let round_keys = cipher.key_schedule(31, &key); 244 | let plaintext = 0xffffffffffffffff; 245 | let ciphertext = 0x3333dcd3213210d2; 246 | 247 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 248 | } 249 | 250 | #[test] 251 | fn decryption_test() { 252 | let cipher = cipher::name_to_cipher("present").unwrap(); 253 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 254 | let round_keys = cipher.key_schedule(31, &key); 255 | let plaintext = 0x0000000000000000; 256 | let ciphertext = 0x5579c1387b228445; 257 | 258 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 259 | 260 | let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 261 | let round_keys = cipher.key_schedule(31, &key); 262 | let plaintext = 0xffffffffffffffff; 263 | let ciphertext = 0x3333dcd3213210d2; 264 | 265 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 266 | } 267 | 268 | #[test] 269 | fn encryption_decryption_test() { 270 | let cipher = cipher::name_to_cipher("present").unwrap(); 271 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 272 | let round_keys = cipher.key_schedule(31, &key); 273 | let plaintext = 0x0123456789abcdef; 274 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 275 | 276 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 277 | 278 | let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 279 | let round_keys = cipher.key_schedule(31, &key); 280 | let plaintext = 0x0123456789abcdef; 281 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 282 | 283 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 284 | } 285 | } 286 | -------------------------------------------------------------------------------- /src/src/search/single_round.rs: -------------------------------------------------------------------------------- 1 | //! Types for representing properties of a single round of a cipher in sorted order. 2 | 3 | use crossbeam_utils; 4 | use num_cpus; 5 | use std::sync::mpsc; 6 | 7 | use crate::cipher::Cipher; 8 | use crate::property::{Property, PropertyFilter, PropertyType, ValueMap}; 9 | use crate::search::graph::MultistageGraph; 10 | use crate::search::patterns::{get_sorted_patterns, SboxPattern}; 11 | use crate::utility::{compress, ProgressBar}; 12 | 13 | // The number of threads used for parallel calls is fixed 14 | lazy_static! { 15 | static ref THREADS: usize = num_cpus::get(); 16 | } 17 | 18 | /***********************************************************************************************/ 19 | 20 | /// A struct that represents a list of single round properties of a cipher, sorted in 21 | /// ascending order of their value. The actual properties are lazily 22 | /// generated using the Iterator trait. 23 | #[derive(Clone)] 24 | pub struct SortedProperties<'a> { 25 | cipher: &'a dyn Cipher, 26 | value_maps: Vec, 27 | sbox_patterns: Vec, 28 | property_type: PropertyType, 29 | property_filter: PropertyFilter, 30 | } 31 | 32 | impl<'a> SortedProperties<'a> { 33 | /// Creates a new `SortedProperties` ready to be used as an iterator. 34 | /// The function basically generates patterns in sorted order 35 | /// using an approach inspired by the paper 36 | /// "Efficient Algorithms for Extracting the K Most Critical Paths in Timing Analysis" 37 | /// by Yen, Du, and Ghanta. 38 | pub fn new( 39 | cipher: &dyn Cipher, 40 | pattern_limit: usize, 41 | property_type: PropertyType, 42 | property_filter: PropertyFilter, 43 | ) -> SortedProperties { 44 | let (sbox_patterns, value_maps) = get_sorted_patterns(cipher, pattern_limit, property_type); 45 | 46 | SortedProperties { 47 | cipher, 48 | value_maps, 49 | sbox_patterns, 50 | property_type, 51 | property_filter, 52 | } 53 | } 54 | 55 | /// Returns the number of properties which can be generated. 56 | pub fn len(&self) -> usize { 57 | let mut len = 0; 58 | 59 | for pattern in &self.sbox_patterns { 60 | let combinations = match self.property_filter { 61 | PropertyFilter::All => pattern.num_prop(&self.value_maps), 62 | PropertyFilter::Input => pattern.num_input(&self.value_maps), 63 | PropertyFilter::Output => pattern.num_output(&self.value_maps), 64 | }; 65 | 66 | len += combinations; 67 | } 68 | 69 | len 70 | } 71 | 72 | /// Check wether the set of properties is empty. 73 | pub fn is_empty(&self) -> bool { 74 | self.len() == 0 75 | } 76 | 77 | /// Returns a reference to the cipher the struct was generated with. 78 | pub fn cipher(&self) -> &'a dyn Cipher { 79 | self.cipher 80 | } 81 | 82 | /// Returns a reference to the S-box patterns generated. 83 | pub fn patterns(&self) -> &Vec { 84 | &self.sbox_patterns 85 | } 86 | 87 | /// Overwrites the S-box patterns with a new set. 88 | pub fn set_patterns(&mut self, patterns: &[SboxPattern]) { 89 | self.sbox_patterns = patterns.to_owned(); 90 | } 91 | 92 | /// Returns the number of patterns. 93 | pub fn len_patterns(&self) -> usize { 94 | self.sbox_patterns.len() 95 | } 96 | 97 | /// Sets the type field to all. 98 | pub fn set_type_all(&mut self) { 99 | self.property_filter = PropertyFilter::All; 100 | } 101 | 102 | /// Sets the type field to input. 103 | pub fn set_type_input(&mut self) { 104 | self.property_filter = PropertyFilter::Input; 105 | } 106 | 107 | /// Sets the type field to output. 108 | pub fn set_type_output(&mut self) { 109 | self.property_filter = PropertyFilter::Output; 110 | } 111 | 112 | /// Removes S-box patterns from a set of properties for which none of the resulting properties 113 | /// are represented by the given graph. Note that the order of properties generated is not 114 | /// preserved. 115 | /// 116 | /// `graph` is a graph compressed with `utility::compress`. 117 | /// The `level` supplied to this function must match that which the graph was created with. 118 | pub fn remove_dead_patterns(&mut self, graph: &MultistageGraph, level: usize) { 119 | let (result_tx, result_rx) = mpsc::channel(); 120 | 121 | // Start scoped worker threads 122 | crossbeam_utils::thread::scope(|scope| { 123 | for t in 0..*THREADS { 124 | let mut thread_properties = self.clone(); 125 | let result_tx = result_tx.clone(); 126 | 127 | scope.spawn(move |_| { 128 | thread_properties.set_type_input(); 129 | 130 | // Split the S-box patterns equally across threads 131 | // Note that this does not equally split the number of properties across threads, 132 | // but hopefully it is close enough 133 | let tmp: Vec<_> = thread_properties 134 | .patterns() 135 | .iter() 136 | .cloned() 137 | .skip(t) 138 | .step_by(*THREADS) 139 | .collect(); 140 | thread_properties.set_patterns(&tmp); 141 | 142 | // Find patterns to keep 143 | let mut good_patterns = vec![false; thread_properties.len_patterns()]; 144 | let mut progress_bar = ProgressBar::new(thread_properties.len()); 145 | 146 | for (property, pattern_idx) in &thread_properties { 147 | // Skip if pattern is already marked good 148 | if good_patterns[pattern_idx] { 149 | if t == 0 { 150 | progress_bar.increment(); 151 | } 152 | continue; 153 | } 154 | 155 | let input = compress(property.input, level); 156 | let good = graph.forward_edges().contains_key(&input) 157 | || graph.backward_edges().contains_key(&input); 158 | good_patterns[pattern_idx] |= good; 159 | 160 | if t == 0 { 161 | progress_bar.increment(); 162 | } 163 | } 164 | 165 | // Keep only good patterns 166 | let mut new_patterns = vec![]; 167 | 168 | for (i, keep) in good_patterns.iter().enumerate() { 169 | if *keep { 170 | new_patterns.push(thread_properties.patterns()[i].clone()); 171 | } 172 | } 173 | 174 | result_tx 175 | .send(new_patterns) 176 | .expect("Thread could not send result"); 177 | }); 178 | } 179 | }) 180 | .expect("Threads failed to join."); 181 | 182 | // Collect patterns from each thread and update properties 183 | let mut new_patterns = Vec::new(); 184 | 185 | for _ in 0..*THREADS { 186 | let mut thread_result = result_rx.recv().expect("Main could not receive result"); 187 | new_patterns.append(&mut thread_result); 188 | } 189 | 190 | self.sbox_patterns = new_patterns; 191 | self.set_type_all(); 192 | } 193 | } 194 | 195 | impl<'a> IntoIterator for &'a SortedProperties<'a> { 196 | type Item = (Property, usize); 197 | type IntoIter = SortedPropertiesIterator<'a>; 198 | 199 | fn into_iter(self) -> Self::IntoIter { 200 | SortedPropertiesIterator { 201 | cipher: self.cipher, 202 | value_maps: self.value_maps.clone(), 203 | sbox_patterns: self.sbox_patterns.clone(), 204 | property_type: self.property_type, 205 | property_filter: self.property_filter, 206 | current_pattern: 0, 207 | } 208 | } 209 | } 210 | 211 | /// An iterator over properties represented by a SortedProperties struct. 212 | #[derive(Clone)] 213 | pub struct SortedPropertiesIterator<'a> { 214 | cipher: &'a dyn Cipher, 215 | pub sbox_patterns: Vec, 216 | value_maps: Vec, 217 | property_type: PropertyType, 218 | property_filter: PropertyFilter, 219 | current_pattern: usize, 220 | } 221 | 222 | impl<'a> Iterator for SortedPropertiesIterator<'a> { 223 | type Item = (Property, usize); 224 | 225 | fn next(&mut self) -> Option { 226 | let max_length = self.sbox_patterns.len(); 227 | 228 | // Stop if we have generated all possible properties 229 | if self.current_pattern >= max_length { 230 | return None; 231 | } 232 | 233 | // Generate next property by calling next on the current pattern. 234 | // Repeat until we get a pattern or run out entirely 235 | let mut property = None; 236 | 237 | while property.is_none() { 238 | let pattern = &mut self.sbox_patterns[self.current_pattern]; 239 | property = match pattern.next(&self.value_maps, self.property_filter) { 240 | Some(x) => Some(x), 241 | None => { 242 | self.current_pattern += 1; 243 | 244 | if self.current_pattern >= max_length { 245 | return None; 246 | } 247 | 248 | None 249 | } 250 | } 251 | } 252 | 253 | let mut property = property.unwrap(); 254 | let (input, output) = 255 | self.cipher 256 | .sbox_mask_transform(property.input, property.output, self.property_type); 257 | property.input = input; 258 | property.output = output; 259 | 260 | Some((property, self.current_pattern)) 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /src/src/cipher/fly.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of FLY. 2 | 3 | use crate::cipher::{Cipher, CipherStructure}; 4 | use crate::property::PropertyType; 5 | use crate::sbox::Sbox; 6 | 7 | /***************************************************************** 8 | Fly 9 | ******************************************************************/ 10 | 11 | /// A structure representing the Fly cipher. 12 | #[derive(Clone)] 13 | pub struct Fly { 14 | size: usize, 15 | key_size: usize, 16 | sbox: Sbox, 17 | } 18 | 19 | impl Fly { 20 | const PERMUTATION: [[u128; 0x100]; 8] = include!("data/fly.perm"); 21 | const PERMUTATION_INV: [[u128; 0x100]; 8] = include!("data/fly.inv.perm"); 22 | const SBOX: [u8; 256] = [ 23 | 0x00, 0x9b, 0xc2, 0x15, 0x5d, 0x84, 0x4c, 0xd1, 0x67, 0x38, 0xef, 0xb0, 0x7e, 0x2b, 0xf6, 24 | 0xa3, 0xb9, 0xaa, 0x36, 0x78, 0x2f, 0x6e, 0xe3, 0xf7, 0x12, 0x5c, 0x9a, 0xd4, 0x89, 0xcd, 25 | 0x01, 0x45, 0x2c, 0x63, 0x44, 0xde, 0x02, 0x96, 0x39, 0x70, 0xba, 0xe4, 0x18, 0x57, 0xa1, 26 | 0xf5, 0x8b, 0xce, 0x51, 0x87, 0xed, 0xff, 0xb5, 0xa8, 0xca, 0x1b, 0xdf, 0x90, 0x6c, 0x32, 27 | 0x46, 0x03, 0x7d, 0x29, 0xd5, 0xf2, 0x20, 0x5b, 0xcc, 0x31, 0x04, 0xbd, 0xa6, 0x41, 0x8e, 28 | 0x79, 0xea, 0x9f, 0x68, 0x1c, 0x48, 0xe6, 0x69, 0x8a, 0x13, 0x77, 0x9e, 0xaf, 0xf3, 0x05, 29 | 0xcb, 0x2d, 0xb4, 0xd0, 0x37, 0x52, 0xc4, 0x3e, 0x93, 0xac, 0x40, 0xe9, 0x22, 0x56, 0x7b, 30 | 0x8d, 0xf1, 0x06, 0x17, 0x62, 0xbf, 0xda, 0x1d, 0x7f, 0x07, 0xb1, 0xdb, 0xfa, 0x65, 0x88, 31 | 0x2e, 0xc9, 0xa5, 0x43, 0x58, 0x3c, 0xe0, 0x94, 0x76, 0x21, 0xab, 0xfd, 0x6a, 0x3f, 0xb7, 32 | 0xe2, 0xdd, 0x4f, 0x53, 0x8c, 0xc0, 0x19, 0x95, 0x08, 0x83, 0xc5, 0x4e, 0x09, 0x14, 0x50, 33 | 0xd8, 0x9c, 0xf4, 0xee, 0x27, 0x61, 0x3b, 0x7a, 0xa2, 0xb6, 0xfe, 0xa9, 0x81, 0xc6, 0xe8, 34 | 0xbc, 0x1f, 0x5a, 0x35, 0x72, 0x99, 0x0a, 0xd3, 0x47, 0x24, 0x6d, 0x0b, 0x4d, 0x75, 0x23, 35 | 0x97, 0xd2, 0x60, 0x34, 0xc8, 0x16, 0xa0, 0xbb, 0xfc, 0xe1, 0x5e, 0x8f, 0xe7, 0x98, 0x1a, 36 | 0x64, 0xae, 0x4b, 0x71, 0x85, 0x0c, 0xb3, 0x3d, 0xcf, 0x55, 0x28, 0xd9, 0xf0, 0xb2, 0xdc, 37 | 0x5f, 0x30, 0xf9, 0x0d, 0x26, 0xc3, 0x91, 0xa7, 0x74, 0x1e, 0x82, 0x66, 0x4a, 0xeb, 0x6f, 38 | 0x10, 0xb8, 0xd7, 0x86, 0x73, 0xfb, 0x0e, 0x59, 0x2a, 0x42, 0xe5, 0x9d, 0xa4, 0x33, 0xc7, 39 | 0x3a, 0x54, 0xec, 0x92, 0xc1, 0x25, 0xad, 0x49, 0x80, 0x6b, 0xd6, 0xf8, 0x0f, 0xbe, 0x7c, 40 | 0x11, 41 | ]; 42 | const CONSTANTS: [u128; 25] = [ 43 | 0x0000000000000000, 44 | 0x8000808000000080, 45 | 0x0080008080000000, 46 | 0x8000008080800080, 47 | 0x0080000080808000, 48 | 0x8000008000808000, 49 | 0x8080808080008000, 50 | 0x8080000080800000, 51 | 0x8080008000808080, 52 | 0x0080800080008080, 53 | 0x0000808000800080, 54 | 0x0000008080008000, 55 | 0x8000808080800000, 56 | 0x8080800080808080, 57 | 0x0080808000808080, 58 | 0x0000808080008080, 59 | 0x0000008080800080, 60 | 0x0000000080808000, 61 | 0x8000808000808000, 62 | 0x8080800080008000, 63 | 0x8080000000800000, 64 | 0x8080008000008080, 65 | 0x0080800080000080, 66 | 0x0000808000800000, 67 | 0x8000800080008080, 68 | ]; 69 | 70 | /// Create a new instance of the cipher. 71 | pub fn new() -> Fly { 72 | let table: Vec<_> = From::from(&Fly::SBOX[0..]); 73 | Fly { 74 | size: 64, 75 | key_size: 128, 76 | sbox: Sbox::new(8, 8, table), 77 | } 78 | } 79 | } 80 | 81 | impl Cipher for Fly { 82 | fn structure(&self) -> CipherStructure { 83 | CipherStructure::Spn 84 | } 85 | 86 | fn size(&self) -> usize { 87 | self.size 88 | } 89 | 90 | fn key_size(&self) -> usize { 91 | self.key_size 92 | } 93 | 94 | fn num_sboxes(&self) -> usize { 95 | self.size / self.sbox.size_in() 96 | } 97 | 98 | fn sbox(&self, _i: usize) -> &Sbox { 99 | &self.sbox 100 | } 101 | 102 | fn sbox_pos_in(&self, i: usize) -> usize { 103 | i * self.sbox(i).size_in() 104 | } 105 | 106 | fn sbox_pos_out(&self, i: usize) -> usize { 107 | i * self.sbox(i).size_out() 108 | } 109 | 110 | fn linear_layer(&self, input: u128) -> u128 { 111 | let mut output = 0; 112 | for i in 0..8 { 113 | output ^= Fly::PERMUTATION[i][((input >> (i * 8)) & 0xff) as usize]; 114 | } 115 | output 116 | } 117 | 118 | fn linear_layer_inv(&self, input: u128) -> u128 { 119 | let mut output = 0; 120 | for i in 0..8 { 121 | output ^= Fly::PERMUTATION_INV[i][((input >> (i * 8)) & 0xff) as usize]; 122 | } 123 | output 124 | } 125 | 126 | fn reflection_layer(&self, _input: u128) -> u128 { 127 | panic!("Not implemented for this type of cipher") 128 | } 129 | 130 | fn key_schedule(&self, rounds: usize, key: &[u8]) -> Vec { 131 | if key.len() * 8 != self.key_size { 132 | panic!("invalid key-length"); 133 | } 134 | 135 | let mut keys = vec![]; 136 | let mut k0: u128 = 0; 137 | let mut k1: u128 = 0; 138 | 139 | for i in 0..8 { 140 | k0 <<= 8; 141 | k0 |= u128::from(key[i]); 142 | k1 <<= 8; 143 | k1 |= u128::from(key[i + 8]); 144 | } 145 | 146 | for r in 0..=rounds { 147 | if r % 2 == 0 { 148 | keys.push(k0) 149 | } else { 150 | keys.push(k0 ^ k1) 151 | } 152 | } 153 | 154 | keys 155 | } 156 | 157 | fn encrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 158 | let mut output = input; 159 | 160 | for (i, &round_key) in round_keys.iter().enumerate().take(20) { 161 | // Add round key 162 | output ^= round_key; 163 | 164 | // Appply constants 165 | output ^= 0x4444444444444444; 166 | output ^= Fly::CONSTANTS[i]; 167 | 168 | // Apply S-box 169 | let mut tmp = 0; 170 | 171 | for j in 0..8 { 172 | tmp ^= u128::from(self.sbox.apply((output >> (8 * j)) & 0xff)) << (8 * j); 173 | } 174 | 175 | // Apply linear layer 176 | output = self.linear_layer(tmp); 177 | } 178 | 179 | output ^= round_keys[20]; 180 | 181 | // Appply constants 182 | output ^= 0x4444444444444444; 183 | output ^= Fly::CONSTANTS[20]; 184 | 185 | output 186 | } 187 | 188 | fn decrypt(&self, _input: u128, _round_keys: &[u128]) -> u128 { 189 | panic!("Not implemented") 190 | } 191 | 192 | fn name(&self) -> String { 193 | String::from("Fly") 194 | } 195 | 196 | fn sbox_mask_transform( 197 | &self, 198 | input: u128, 199 | output: u128, 200 | _property_type: PropertyType, 201 | ) -> (u128, u128) { 202 | (input, self.linear_layer(output)) 203 | } 204 | 205 | #[inline(always)] 206 | fn whitening(&self) -> bool { 207 | true 208 | } 209 | } 210 | 211 | impl Default for Fly { 212 | fn default() -> Self { 213 | Fly::new() 214 | } 215 | } 216 | 217 | /* 218 | #[cfg(test)] 219 | mod tests { 220 | use cipher; 221 | 222 | fn translate(x: u128) -> u128 { 223 | let mut y = 0; 224 | 225 | for i in 0..8 { 226 | let z = (x >> (8*i)) & 0xff; 227 | 228 | for j in 0..8 { 229 | y ^= ((z >> j) & 0x1) << (8*j+i); 230 | } 231 | } 232 | 233 | y 234 | } 235 | 236 | #[test] 237 | fn encryption_test() { 238 | let cipher = cipher::name_to_cipher("fly").unwrap(); 239 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 240 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 241 | let round_keys = cipher.key_schedule(21, &key); 242 | let plaintext = 0x0000000000000000; 243 | // let ciphertext = 0x242730FBD342A940; 244 | let ciphertext = 0x40A942D3FB302724; 245 | let ciphertext = translate(ciphertext); 246 | println!("{:016x}", ciphertext); 247 | 248 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 249 | 250 | // let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 251 | // let round_keys = cipher.key_schedule(32, &key); 252 | // let plaintext = 0xffffffffffffffff; 253 | // let ciphertext = 0x3333dcd3213210d2; 254 | 255 | // assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 256 | } 257 | 258 | #[test] 259 | fn decryption_test() { 260 | let cipher = cipher::name_to_cipher("fly").unwrap(); 261 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 262 | let round_keys = cipher.key_schedule(32, &key); 263 | let plaintext = 0x0000000000000000; 264 | let ciphertext = 0x5579c1387b228445; 265 | 266 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 267 | 268 | let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 269 | let round_keys = cipher.key_schedule(32, &key); 270 | let plaintext = 0xffffffffffffffff; 271 | let ciphertext = 0x3333dcd3213210d2; 272 | 273 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 274 | } 275 | 276 | #[test] 277 | fn encryption_decryption_test() { 278 | let cipher = cipher::name_to_cipher("fly").unwrap(); 279 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 280 | let round_keys = cipher.key_schedule(32, &key); 281 | let plaintext = 0x0123456789abcdef; 282 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 283 | 284 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 285 | 286 | let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 287 | let round_keys = cipher.key_schedule(32, &key); 288 | let plaintext = 0x0123456789abcdef; 289 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 290 | 291 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 292 | } 293 | } 294 | */ 295 | -------------------------------------------------------------------------------- /src/src/cipher/puffin.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of PUFFIN. 2 | 3 | use crate::cipher::{Cipher, CipherStructure}; 4 | use crate::property::PropertyType; 5 | use crate::sbox::Sbox; 6 | 7 | /***************************************************************** 8 | PUFFIN 9 | ******************************************************************/ 10 | 11 | /// A structure representing the PUFFIN cipher. 12 | #[derive(Clone)] 13 | pub struct Puffin { 14 | size: usize, 15 | key_size: usize, 16 | sbox: Sbox, 17 | } 18 | 19 | impl Puffin { 20 | const PERMUTATION: [[u128; 0x100]; 8] = include!("data/puffin.perm"); 21 | const KEY_PERMUTATION: [u128; 128] = [ 22 | 22, 121, 126, 110, 79, 81, 116, 55, 113, 21, 29, 20, 56, 76, 41, 112, 45, 109, 95, 87, 94, 23 | 44, 68, 8, 115, 69, 6, 75, 83, 5, 54, 70, 23, 61, 106, 103, 85, 124, 111, 52, 119, 32, 100, 24 | 17, 15, 34, 128, 91, 58, 99, 120, 67, 31, 98, 53, 71, 92, 25, 38, 93, 65, 2, 37, 28, 24, 25 | 82, 88, 14, 96, 118, 1, 9, 125, 27, 127, 18, 4, 10, 102, 7, 35, 105, 48, 63, 30, 77, 72, 26 | 50, 108, 73, 12, 19, 107, 11, 26, 84, 47, 97, 117, 49, 46, 33, 16, 42, 39, 57, 114, 62, 27 | 123, 101, 80, 13, 51, 122, 64, 89, 43, 60, 40, 3, 86, 90, 59, 74, 78, 104, 36, 66, 28 | ]; 29 | const KEY_SELECTION: [u128; 64] = [ 30 | 3, 123, 15, 58, 89, 36, 98, 52, 57, 63, 100, 70, 46, 71, 94, 51, 83, 14, 4, 22, 32, 114, 31 | 84, 101, 12, 23, 31, 65, 41, 96, 120, 50, 45, 54, 112, 122, 29, 81, 30, 121, 97, 55, 26, 32 | 64, 24, 117, 19, 9, 111, 18, 44, 86, 16, 95, 42, 72, 2, 91, 118, 124, 38, 48, 43, 39, 33 | ]; 34 | 35 | // Create a new instance of the cipher. 36 | pub fn new() -> Puffin { 37 | let table = vec![ 38 | 0xd, 0x7, 0x3, 0x2, 0x9, 0xa, 0xc, 0x1, 0xf, 0x4, 0x5, 0xe, 0x6, 0x0, 0xb, 0x8, 39 | ]; 40 | Puffin { 41 | size: 64, 42 | key_size: 128, 43 | sbox: Sbox::new(4, 4, table), 44 | } 45 | } 46 | } 47 | 48 | impl Cipher for Puffin { 49 | fn structure(&self) -> CipherStructure { 50 | CipherStructure::Spn 51 | } 52 | 53 | fn size(&self) -> usize { 54 | self.size 55 | } 56 | 57 | fn key_size(&self) -> usize { 58 | self.key_size 59 | } 60 | 61 | fn num_sboxes(&self) -> usize { 62 | self.size / self.sbox.size_in() 63 | } 64 | 65 | fn sbox(&self, _i: usize) -> &Sbox { 66 | &self.sbox 67 | } 68 | 69 | fn sbox_pos_in(&self, i: usize) -> usize { 70 | i * self.sbox(i).size_in() 71 | } 72 | 73 | fn sbox_pos_out(&self, i: usize) -> usize { 74 | i * self.sbox(i).size_out() 75 | } 76 | 77 | fn linear_layer(&self, input: u128) -> u128 { 78 | let mut output = 0; 79 | 80 | output ^= Puffin::PERMUTATION[0][((input) & 0xff) as usize]; 81 | output ^= Puffin::PERMUTATION[1][((input >> 8) & 0xff) as usize]; 82 | output ^= Puffin::PERMUTATION[2][((input >> 16) & 0xff) as usize]; 83 | output ^= Puffin::PERMUTATION[3][((input >> 24) & 0xff) as usize]; 84 | output ^= Puffin::PERMUTATION[4][((input >> 32) & 0xff) as usize]; 85 | output ^= Puffin::PERMUTATION[5][((input >> 40) & 0xff) as usize]; 86 | output ^= Puffin::PERMUTATION[6][((input >> 48) & 0xff) as usize]; 87 | output ^= Puffin::PERMUTATION[7][((input >> 56) & 0xff) as usize]; 88 | 89 | output 90 | } 91 | 92 | fn linear_layer_inv(&self, input: u128) -> u128 { 93 | self.linear_layer(input) 94 | } 95 | 96 | fn reflection_layer(&self, _input: u128) -> u128 { 97 | panic!("Not implemented for this type of cipher") 98 | } 99 | 100 | fn key_schedule(&self, rounds: usize, key: &[u8]) -> Vec { 101 | if key.len() * 8 != self.key_size { 102 | panic!("invalid key-length"); 103 | } 104 | 105 | let mut keys = vec![]; 106 | let mut k1 = 0; 107 | let mut k0 = 0; 108 | 109 | // Load key into 128-bit state (k1 || k0) 110 | for i in 0..8 { 111 | k1 <<= 8; 112 | k0 <<= 8; 113 | k1 |= u128::from(key[i + 8]); 114 | k0 |= u128::from(key[i]); 115 | } 116 | 117 | for r in 0..rounds { 118 | let mut t0 = 0; 119 | let mut t1 = 0; 120 | for i in 0..64 { 121 | if Puffin::KEY_PERMUTATION[i] > 64 { 122 | t1 ^= ((k0 >> i) & 0x1) << (Puffin::KEY_PERMUTATION[i] - 1 - 64); 123 | } else { 124 | t0 ^= ((k0 >> i) & 0x1) << (Puffin::KEY_PERMUTATION[i] - 1); 125 | } 126 | 127 | if Puffin::KEY_PERMUTATION[i + 64] > 64 { 128 | t1 ^= ((k1 >> i) & 0x1) << (Puffin::KEY_PERMUTATION[i + 64] - 1 - 64); 129 | } else { 130 | t0 ^= ((k1 >> i) & 0x1) << (Puffin::KEY_PERMUTATION[i + 64] - 1); 131 | } 132 | } 133 | 134 | k0 = t0; 135 | k1 = t1; 136 | 137 | if r != 2 || r != 5 || r != 6 || r != 8 { 138 | k0 ^= 0b10111; 139 | } 140 | 141 | let mut key = 0; 142 | 143 | for i in 0..64 { 144 | if Puffin::KEY_SELECTION[i] > 64 { 145 | key ^= ((k1 >> (Puffin::KEY_SELECTION[i] - 1 - 64)) & 0x1) << i; 146 | } else { 147 | key ^= ((k0 >> (Puffin::KEY_SELECTION[i] - 1)) & 0x1) << i; 148 | } 149 | } 150 | 151 | keys.push(key); 152 | } 153 | 154 | keys 155 | } 156 | 157 | fn encrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 158 | let mut output = input; 159 | 160 | for &round_key in round_keys.iter().take(33) { 161 | // Apply S-box 162 | let mut tmp = 0; 163 | 164 | for j in 0..16 { 165 | tmp ^= u128::from(self.sbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 166 | } 167 | 168 | // Apply linear layer 169 | output = self.linear_layer(tmp); 170 | 171 | // Add round key 172 | output ^= round_key; 173 | } 174 | 175 | output 176 | } 177 | 178 | fn decrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 179 | let mut output = input; 180 | 181 | for i in 0..33 { 182 | // Add round key 183 | output ^= round_keys[32 - i]; 184 | 185 | // Apply linear layer 186 | output = self.linear_layer(output); 187 | 188 | // Apply S-box 189 | let mut tmp = 0; 190 | 191 | for j in 0..16 { 192 | tmp ^= u128::from(self.sbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 193 | } 194 | 195 | output = tmp; 196 | } 197 | 198 | output 199 | } 200 | 201 | fn name(&self) -> String { 202 | String::from("PUFFIN") 203 | } 204 | 205 | fn sbox_mask_transform( 206 | &self, 207 | input: u128, 208 | output: u128, 209 | _property_type: PropertyType, 210 | ) -> (u128, u128) { 211 | (input, self.linear_layer(output)) 212 | } 213 | 214 | #[inline(always)] 215 | fn whitening(&self) -> bool { 216 | false 217 | } 218 | } 219 | 220 | impl Default for Puffin { 221 | fn default() -> Self { 222 | Puffin::new() 223 | } 224 | } 225 | 226 | #[cfg(test)] 227 | mod tests { 228 | use crate::cipher; 229 | 230 | /* No test vectors provided in specification 231 | #[test] 232 | fn encryption_test() { 233 | let cipher = cipher::name_to_cipher("puffin").unwrap(); 234 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 235 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 236 | let round_keys = cipher.key_schedule(32, &key); 237 | let plaintext = 0x0000000000000000; 238 | let ciphertext = 0x5579c1387b228445; 239 | 240 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 241 | 242 | let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 243 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 244 | let round_keys = cipher.key_schedule(32, &key); 245 | let plaintext = 0xffffffffffffffff; 246 | let ciphertext = 0x3333dcd3213210d2; 247 | 248 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 249 | } 250 | 251 | #[test] 252 | fn decryption_test() { 253 | let cipher = cipher::name_to_cipher("puffin").unwrap(); 254 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 255 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 256 | let round_keys = cipher.key_schedule(32, &key); 257 | let plaintext = 0x0000000000000000; 258 | let ciphertext = 0x5579c1387b228445; 259 | 260 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 261 | 262 | let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 263 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 264 | let round_keys = cipher.key_schedule(32, &key); 265 | let plaintext = 0xffffffffffffffff; 266 | let ciphertext = 0x3333dcd3213210d2; 267 | 268 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 269 | }*/ 270 | 271 | #[test] 272 | fn encryption_decryption_test() { 273 | let cipher = cipher::name_to_cipher("puffin").unwrap(); 274 | let key = [ 275 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 276 | 0x00, 0x00, 277 | ]; 278 | let round_keys = cipher.key_schedule(33, &key); 279 | let plaintext = 0x0123456789abcdef; 280 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 281 | 282 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 283 | 284 | let key = [ 285 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 286 | 0xff, 0xff, 287 | ]; 288 | let round_keys = cipher.key_schedule(33, &key); 289 | let plaintext = 0x0123456789abcdef; 290 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 291 | 292 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 293 | } 294 | } 295 | -------------------------------------------------------------------------------- /src/src/cipher/led.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of LED. 2 | 3 | use crate::cipher::{Cipher, CipherStructure}; 4 | use crate::property::PropertyType; 5 | use crate::sbox::Sbox; 6 | 7 | /***************************************************************** 8 | LED 9 | ******************************************************************/ 10 | 11 | /// A structure representing the LED cipher. 12 | #[derive(Clone)] 13 | pub struct Led { 14 | size: usize, 15 | key_size: usize, 16 | sbox: Sbox, 17 | isbox: Sbox, 18 | shift_rows_table: [usize; 16], 19 | ishift_rows_table: [usize; 16], 20 | constants: [u128; 48], 21 | } 22 | 23 | impl Led { 24 | /// Create a new instance of the cipher. 25 | pub fn new() -> Led { 26 | let table = vec![ 27 | 0xc, 0x5, 0x6, 0xb, 0x9, 0x0, 0xa, 0xd, 0x3, 0xe, 0xf, 0x8, 0x4, 0x7, 0x1, 0x2, 28 | ]; 29 | let itable = vec![ 30 | 0x5, 0xe, 0xf, 0x8, 0xc, 0x1, 0x2, 0xd, 0xb, 0x4, 0x6, 0x3, 0x0, 0x7, 0x9, 0xa, 31 | ]; 32 | let shift_rows_table = [0, 1, 2, 3, 7, 4, 5, 6, 10, 11, 8, 9, 13, 14, 15, 12]; 33 | let ishift_rows_table = [0, 1, 2, 3, 5, 6, 7, 4, 10, 11, 8, 9, 15, 12, 13, 14]; 34 | let constants = [ 35 | 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3e, 0x3d, 0x3b, 0x37, 0x2f, 0x1e, 0x3c, 0x39, 0x33, 36 | 0x27, 0x0e, 0x1d, 0x3a, 0x35, 0x2b, 0x16, 0x2c, 0x18, 0x30, 0x21, 0x02, 0x05, 0x0b, 37 | 0x17, 0x2e, 0x1c, 0x38, 0x31, 0x23, 0x06, 0x0d, 0x1b, 0x36, 0x2d, 0x1a, 0x34, 0x29, 38 | 0x12, 0x24, 0x08, 0x11, 0x22, 0x04, 39 | ]; 40 | Led { 41 | size: 64, 42 | key_size: 64, 43 | sbox: Sbox::new(4, 4, table), 44 | isbox: Sbox::new(4, 4, itable), 45 | shift_rows_table, 46 | ishift_rows_table, 47 | constants, 48 | } 49 | } 50 | } 51 | 52 | /** 53 | Performs multiplication by two in the LED field 54 | */ 55 | fn led_times2(x: u128) -> u128 { 56 | ((x & 0x7777) << 1) ^ ((x & 0x8888) >> 3) ^ ((x & 0x8888) >> 2) 57 | } 58 | 59 | impl Cipher for Led { 60 | fn structure(&self) -> CipherStructure { 61 | CipherStructure::Spn 62 | } 63 | 64 | fn size(&self) -> usize { 65 | self.size 66 | } 67 | 68 | fn key_size(&self) -> usize { 69 | self.key_size 70 | } 71 | 72 | fn num_sboxes(&self) -> usize { 73 | self.size / self.sbox.size_in() 74 | } 75 | 76 | fn sbox(&self, _i: usize) -> &Sbox { 77 | &self.sbox 78 | } 79 | 80 | fn sbox_pos_in(&self, i: usize) -> usize { 81 | i * self.sbox(i).size_in() 82 | } 83 | 84 | fn sbox_pos_out(&self, i: usize) -> usize { 85 | i * self.sbox(i).size_out() 86 | } 87 | 88 | fn linear_layer(&self, input: u128) -> u128 { 89 | let mut x = 0; 90 | 91 | // Apply ShiftRows 92 | for i in 0..16 { 93 | x ^= ((input >> (i * 4)) & 0xf) << (self.shift_rows_table[i] * 4); 94 | } 95 | 96 | // Apply MixColumnsSerial 97 | let mut y; 98 | 99 | for _ in 0..4 { 100 | y = x >> 16; 101 | // Times 4 102 | y ^= led_times2(led_times2(x & 0xffff)) << 48; 103 | // Times 1 104 | y ^= (x & 0xffff0000) << 32; 105 | // Times 2 106 | y ^= led_times2((x & 0xffff00000000) >> 32) << 48; 107 | // Times 2 108 | y ^= led_times2((x & 0xffff000000000000) >> 48) << 48; 109 | x = y; 110 | } 111 | 112 | x 113 | } 114 | 115 | fn linear_layer_inv(&self, input: u128) -> u128 { 116 | let mut x = input; 117 | 118 | // Apply inverse MixColumnsSerial 119 | let mut y; 120 | 121 | for _ in 0..4 { 122 | y = x << 16; 123 | // Times 13 124 | y ^= led_times2(led_times2(led_times2(x & 0xffff))); 125 | y ^= led_times2(led_times2(x & 0xffff)); 126 | y ^= x & 0xffff; 127 | // Times 9 128 | y ^= led_times2(led_times2(led_times2((x & 0xffff0000) >> 16))); 129 | y ^= (x & 0xffff0000) >> 16; 130 | // Times 9 131 | y ^= led_times2(led_times2(led_times2((x & 0xffff00000000) >> 32))); 132 | y ^= (x & 0xffff00000000) >> 32; 133 | // Times 13 134 | y ^= led_times2(led_times2(led_times2((x & 0xffff000000000000) >> 48))); 135 | y ^= led_times2(led_times2((x & 0xffff000000000000) >> 48)); 136 | y ^= (x & 0xffff000000000000) >> 48; 137 | x = y; 138 | } 139 | 140 | // Apply inverse ShiftRows 141 | let mut y = 0; 142 | 143 | for i in 0..16 { 144 | y ^= ((x >> (i * 4)) & 0xf) << (self.ishift_rows_table[i] * 4); 145 | } 146 | 147 | y 148 | } 149 | 150 | fn reflection_layer(&self, _input: u128) -> u128 { 151 | panic!("Not implemented for this type of cipher") 152 | } 153 | 154 | fn key_schedule(&self, rounds: usize, key: &[u8]) -> Vec { 155 | if key.len() * 8 != self.key_size { 156 | panic!("invalid key-length"); 157 | } 158 | 159 | let mut k = 0; 160 | 161 | // Load key into 64-bit state 162 | for &x in key.iter().take(8) { 163 | k <<= 8; 164 | k |= u128::from(x); 165 | } 166 | 167 | // All keys are identical 168 | vec![k; rounds + 1] 169 | } 170 | 171 | fn encrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 172 | let mut output = input; 173 | 174 | output ^= round_keys[0]; 175 | 176 | for s in 0..8 { 177 | for i in 0..4 { 178 | // Add constant 179 | let mut constant = 0x0003000200050004; 180 | constant ^= (self.constants[4 * s + i] >> 3) << 4; 181 | constant ^= (self.constants[4 * s + i] & 0b111) << (4 + 16); 182 | constant ^= (self.constants[4 * s + i] >> 3) << (4 + 32); 183 | constant ^= (self.constants[4 * s + i] & 0b111) << (4 + 48); 184 | 185 | output ^= constant; 186 | 187 | // SubCells 188 | let mut tmp = 0; 189 | 190 | for j in 0..16 { 191 | tmp ^= u128::from(self.sbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 192 | } 193 | 194 | // ShiftRows + MixColumns 195 | output = self.linear_layer(tmp); 196 | } 197 | 198 | output ^= round_keys[s + 1]; 199 | } 200 | 201 | output 202 | } 203 | 204 | fn decrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 205 | let mut output = input; 206 | 207 | output ^= round_keys[8]; 208 | 209 | for s in 0..8 { 210 | for i in 0..4 { 211 | // InvShiftRows + InvMixColumns 212 | output = self.linear_layer_inv(output); 213 | 214 | // SubCells 215 | let mut tmp = 0; 216 | 217 | for j in 0..16 { 218 | tmp ^= u128::from(self.isbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 219 | } 220 | 221 | // Add constant 222 | let mut constant = 0x0003000200050004; 223 | constant ^= (self.constants[31 - (4 * s + i)] >> 3) << 4; 224 | constant ^= (self.constants[31 - (4 * s + i)] & 0b111) << (4 + 16); 225 | constant ^= (self.constants[31 - (4 * s + i)] >> 3) << (4 + 32); 226 | constant ^= (self.constants[31 - (4 * s + i)] & 0b111) << (4 + 48); 227 | 228 | output = tmp ^ constant; 229 | } 230 | 231 | output ^= round_keys[7 - s]; 232 | } 233 | 234 | output 235 | } 236 | 237 | fn name(&self) -> String { 238 | String::from("LED") 239 | } 240 | 241 | fn sbox_mask_transform( 242 | &self, 243 | input: u128, 244 | output: u128, 245 | _property_type: PropertyType, 246 | ) -> (u128, u128) { 247 | (input, self.linear_layer(output)) 248 | } 249 | 250 | #[inline(always)] 251 | fn whitening(&self) -> bool { 252 | true 253 | } 254 | } 255 | 256 | impl Default for Led { 257 | fn default() -> Self { 258 | Led::new() 259 | } 260 | } 261 | 262 | #[cfg(test)] 263 | mod tests { 264 | use crate::cipher; 265 | 266 | #[test] 267 | fn encryption_test() { 268 | let cipher = cipher::name_to_cipher("led").unwrap(); 269 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 270 | let round_keys = cipher.key_schedule(8, &key); 271 | let plaintext = 0x0000000000000000; 272 | let ciphertext = 0x897c0a3001042c93; 273 | 274 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 275 | 276 | let key = [0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10]; 277 | let round_keys = cipher.key_schedule(8, &key); 278 | let plaintext = 0xfedcba9876543210; 279 | let ciphertext = 0x85cf3983e155300a; 280 | 281 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 282 | } 283 | 284 | #[test] 285 | fn decryption_test() { 286 | let cipher = cipher::name_to_cipher("led").unwrap(); 287 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 288 | let round_keys = cipher.key_schedule(8, &key); 289 | let plaintext = 0x0000000000000000; 290 | let ciphertext = 0x897c0a3001042c93; 291 | 292 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 293 | 294 | let key = [0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10]; 295 | let round_keys = cipher.key_schedule(8, &key); 296 | let plaintext = 0xfedcba9876543210; 297 | let ciphertext = 0x85cf3983e155300a; 298 | 299 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 300 | } 301 | 302 | #[test] 303 | fn encryption_decryption_test() { 304 | let cipher = cipher::name_to_cipher("led").unwrap(); 305 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 306 | let round_keys = cipher.key_schedule(8, &key); 307 | let plaintext = 0x0123456789abcdef; 308 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 309 | 310 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 311 | 312 | let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 313 | let round_keys = cipher.key_schedule(8, &key); 314 | let plaintext = 0x0123456789abcdef; 315 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 316 | 317 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 318 | } 319 | } 320 | -------------------------------------------------------------------------------- /src/src/cipher/midori.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of Midori. 2 | 3 | use crate::cipher::{Cipher, CipherStructure}; 4 | use crate::property::PropertyType; 5 | use crate::sbox::Sbox; 6 | 7 | /***************************************************************** 8 | Midori 9 | ******************************************************************/ 10 | 11 | /// A structure representing the Midori cipher. 12 | #[derive(Clone)] 13 | pub struct Midori { 14 | size: usize, 15 | key_size: usize, 16 | sbox: Sbox, 17 | shuffle_cell_table: [usize; 16], 18 | ishuffle_cell_table: [usize; 16], 19 | constants: [u128; 15], 20 | } 21 | 22 | impl Midori { 23 | /// Create a new instance of the cipher. 24 | pub fn new() -> Midori { 25 | let table = vec![ 26 | 0xc, 0xa, 0xd, 0x3, 0xe, 0xb, 0xf, 0x7, 0x8, 0x9, 0x1, 0x5, 0x0, 0x2, 0x4, 0x6, 27 | ]; 28 | let shuffle_cell_table = [0, 7, 14, 9, 5, 2, 11, 12, 15, 8, 1, 6, 10, 13, 4, 3]; 29 | let ishuffle_cell_table = [0, 10, 5, 15, 14, 4, 11, 1, 9, 3, 12, 6, 7, 13, 2, 8]; 30 | let constants = [ 31 | 0x0001010110110011, 32 | 0x0111100011000000, 33 | 0x1010010000110101, 34 | 0x0110001000010011, 35 | 0x0001000001001111, 36 | 0x1101000101110000, 37 | 0x0000001001100110, 38 | 0x0000101111001100, 39 | 0x1001010010000001, 40 | 0x0100000010111000, 41 | 0x0111000110010111, 42 | 0x0010001010001110, 43 | 0x0101000100110000, 44 | 0x1111100011001010, 45 | 0x1101111110010000, 46 | ]; 47 | Midori { 48 | size: 64, 49 | key_size: 128, 50 | sbox: Sbox::new(4, 4, table), 51 | shuffle_cell_table, 52 | ishuffle_cell_table, 53 | constants, 54 | } 55 | } 56 | } 57 | 58 | impl Cipher for Midori { 59 | fn structure(&self) -> CipherStructure { 60 | CipherStructure::Spn 61 | } 62 | 63 | fn size(&self) -> usize { 64 | self.size 65 | } 66 | 67 | fn key_size(&self) -> usize { 68 | self.key_size 69 | } 70 | 71 | fn num_sboxes(&self) -> usize { 72 | self.size / self.sbox.size_in() 73 | } 74 | 75 | fn sbox(&self, _i: usize) -> &Sbox { 76 | &self.sbox 77 | } 78 | 79 | fn sbox_pos_in(&self, i: usize) -> usize { 80 | i * self.sbox(i).size_in() 81 | } 82 | 83 | fn sbox_pos_out(&self, i: usize) -> usize { 84 | i * self.sbox(i).size_out() 85 | } 86 | 87 | fn linear_layer(&self, input: u128) -> u128 { 88 | let mut x = 0; 89 | 90 | // Apply ShuffleCell 91 | for i in 0..16 { 92 | x ^= ((input >> ((15 - i) * 4)) & 0xf) << ((15 - self.shuffle_cell_table[i]) * 4); 93 | } 94 | 95 | // Apply MixColumn 96 | let mut output = 0; 97 | output ^= (x & 0x00f000f000f000f0) >> 4 98 | ^ (x & 0x0f000f000f000f00) >> 8 99 | ^ (x & 0xf000f000f000f000) >> 12; 100 | 101 | output ^= (x & 0x000f000f000f000f) << 4 102 | ^ (x & 0x0f000f000f000f00) >> 4 103 | ^ (x & 0xf000f000f000f000) >> 8; 104 | 105 | output ^= (x & 0x000f000f000f000f) << 8 106 | ^ (x & 0x00f000f000f000f0) << 4 107 | ^ (x & 0xf000f000f000f000) >> 4; 108 | 109 | output ^= (x & 0x000f000f000f000f) << 12 110 | ^ (x & 0x00f000f000f000f0) << 8 111 | ^ (x & 0x0f000f000f000f00) << 4; 112 | 113 | output 114 | } 115 | 116 | fn linear_layer_inv(&self, input: u128) -> u128 { 117 | let mut x = input; 118 | 119 | // Apply MixColumn 120 | let mut output = 0; 121 | output ^= (x & 0x00f000f000f000f0) >> 4 122 | ^ (x & 0x0f000f000f000f00) >> 8 123 | ^ (x & 0xf000f000f000f000) >> 12; 124 | 125 | output ^= (x & 0x000f000f000f000f) << 4 126 | ^ (x & 0x0f000f000f000f00) >> 4 127 | ^ (x & 0xf000f000f000f000) >> 8; 128 | 129 | output ^= (x & 0x000f000f000f000f) << 8 130 | ^ (x & 0x00f000f000f000f0) << 4 131 | ^ (x & 0xf000f000f000f000) >> 4; 132 | 133 | output ^= (x & 0x000f000f000f000f) << 12 134 | ^ (x & 0x00f000f000f000f0) << 8 135 | ^ (x & 0x0f000f000f000f00) << 4; 136 | 137 | // Apply ShuffleCell 138 | x = 0; 139 | 140 | for i in 0..16 { 141 | x ^= ((output >> ((15 - i) * 4)) & 0xf) << ((15 - self.ishuffle_cell_table[i]) * 4); 142 | } 143 | 144 | x 145 | } 146 | 147 | fn reflection_layer(&self, _input: u128) -> u128 { 148 | panic!("Not implemented for this type of cipher") 149 | } 150 | 151 | fn key_schedule(&self, rounds: usize, key: &[u8]) -> Vec { 152 | if key.len() * 8 != self.key_size { 153 | panic!("invalid key-length"); 154 | } 155 | 156 | let mut keys = vec![]; 157 | let mut k0 = 0; 158 | let mut k1 = 0; 159 | 160 | for i in 0..8 { 161 | k0 <<= 8; 162 | k0 |= u128::from(key[i]); 163 | k1 <<= 8; 164 | k1 |= u128::from(key[i + 8]); 165 | } 166 | 167 | keys.push(k0 ^ k1); 168 | 169 | for _ in 0..(rounds / 2 - 1) { 170 | keys.push(k0); 171 | keys.push(k1); 172 | } 173 | 174 | keys.push(k0); 175 | keys.push(k0 ^ k1); 176 | 177 | keys 178 | } 179 | 180 | fn encrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 181 | let mut output = input; 182 | output ^= round_keys[0]; 183 | 184 | for i in 0..15 { 185 | // Apply S-box 186 | let mut tmp = 0; 187 | 188 | for j in 0..16 { 189 | tmp ^= u128::from(self.sbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 190 | } 191 | 192 | // ShuffleCell + MixColumns 193 | output = self.linear_layer(tmp); 194 | 195 | // Add key and constant 196 | output ^= round_keys[i + 1]; 197 | output ^= self.constants[i]; 198 | } 199 | 200 | // Apply S-box 201 | let mut tmp = 0; 202 | 203 | for j in 0..16 { 204 | tmp ^= u128::from(self.sbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 205 | } 206 | 207 | tmp ^ round_keys[16] 208 | } 209 | 210 | fn decrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 211 | let mut output = input; 212 | output ^= round_keys[16]; 213 | 214 | // Apply S-box 215 | let mut tmp = 0; 216 | 217 | for j in 0..16 { 218 | tmp ^= u128::from(self.sbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 219 | } 220 | 221 | for i in 0..15 { 222 | // Add key and constant 223 | output = tmp ^ round_keys[16 - (i + 1)]; 224 | output ^= self.constants[14 - i]; 225 | 226 | // ShuffleCell + MixColumns 227 | output = self.linear_layer_inv(output); 228 | 229 | // Apply S-box 230 | tmp = 0; 231 | 232 | for j in 0..16 { 233 | tmp ^= u128::from(self.sbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 234 | } 235 | } 236 | 237 | tmp ^ round_keys[0] 238 | } 239 | 240 | fn name(&self) -> String { 241 | String::from("Midori") 242 | } 243 | 244 | fn sbox_mask_transform( 245 | &self, 246 | input: u128, 247 | output: u128, 248 | _property_type: PropertyType, 249 | ) -> (u128, u128) { 250 | (input, self.linear_layer(output)) 251 | } 252 | 253 | #[inline(always)] 254 | fn whitening(&self) -> bool { 255 | true 256 | } 257 | } 258 | 259 | impl Default for Midori { 260 | fn default() -> Self { 261 | Midori::new() 262 | } 263 | } 264 | 265 | #[cfg(test)] 266 | mod tests { 267 | use crate::cipher; 268 | 269 | #[test] 270 | fn encryption_test() { 271 | let cipher = cipher::name_to_cipher("midori").unwrap(); 272 | let key = [ 273 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 274 | 0x00, 0x00, 275 | ]; 276 | let round_keys = cipher.key_schedule(16, &key); 277 | let plaintext = 0x0000000000000000; 278 | let ciphertext = 0x3c9cceda2bbd449a; 279 | 280 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 281 | 282 | let key = [ 283 | 0x68, 0x7d, 0xed, 0x3b, 0x3c, 0x85, 0xb3, 0xf3, 0x5b, 0x10, 0x09, 0x86, 0x3e, 0x2a, 284 | 0x8c, 0xbf, 285 | ]; 286 | let round_keys = cipher.key_schedule(16, &key); 287 | let plaintext = 0x42c20fd3b586879e; 288 | let ciphertext = 0x66bcdc6270d901cd; 289 | 290 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 291 | } 292 | 293 | #[test] 294 | fn decryption_test() { 295 | let cipher = cipher::name_to_cipher("midori").unwrap(); 296 | let key = [ 297 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 298 | 0x00, 0x00, 299 | ]; 300 | let round_keys = cipher.key_schedule(16, &key); 301 | let plaintext = 0x0000000000000000; 302 | let ciphertext = 0x3c9cceda2bbd449a; 303 | 304 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 305 | 306 | let key = [ 307 | 0x68, 0x7d, 0xed, 0x3b, 0x3c, 0x85, 0xb3, 0xf3, 0x5b, 0x10, 0x09, 0x86, 0x3e, 0x2a, 308 | 0x8c, 0xbf, 309 | ]; 310 | let round_keys = cipher.key_schedule(16, &key); 311 | let plaintext = 0x42c20fd3b586879e; 312 | let ciphertext = 0x66bcdc6270d901cd; 313 | 314 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 315 | } 316 | 317 | #[test] 318 | fn encryption_decryption_test() { 319 | let cipher = cipher::name_to_cipher("midori").unwrap(); 320 | let key = [ 321 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 322 | 0x00, 0x00, 323 | ]; 324 | let round_keys = cipher.key_schedule(16, &key); 325 | let plaintext = 0x0123456789abcdef; 326 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 327 | 328 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 329 | 330 | let key = [ 331 | 0x68, 0x7d, 0xed, 0x3b, 0x3c, 0x85, 0xb3, 0xf3, 0x5b, 0x10, 0x09, 0x86, 0x3e, 0x2a, 332 | 0x8c, 0xbf, 333 | ]; 334 | let round_keys = cipher.key_schedule(16, &key); 335 | let plaintext = 0x0123456789abcdef; 336 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 337 | 338 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 339 | } 340 | } 341 | -------------------------------------------------------------------------------- /src/src/cipher/mibs.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of MIBS. 2 | 3 | use crate::cipher::{Cipher, CipherStructure}; 4 | use crate::property::PropertyType; 5 | use crate::sbox::Sbox; 6 | 7 | /***************************************************************** 8 | MIBS 9 | ******************************************************************/ 10 | 11 | /// A structure representing the MIBS cipher. 12 | #[derive(Clone)] 13 | pub struct Mibs { 14 | size: usize, 15 | key_size: usize, 16 | sbox: Sbox, 17 | isbox: Sbox, 18 | } 19 | 20 | impl Mibs { 21 | const PERMUTATION: [usize; 8] = [3, 4, 1, 2, 5, 7, 0, 6]; 22 | const IPERMUTATION: [usize; 8] = [6, 2, 3, 0, 1, 4, 7, 5]; 23 | 24 | /// Create a new instance of the cipher. 25 | pub fn new() -> Mibs { 26 | let table = vec![4, 15, 3, 8, 13, 10, 12, 0, 11, 5, 7, 14, 2, 6, 1, 9]; 27 | let itable = vec![7, 14, 12, 2, 0, 9, 13, 10, 3, 15, 5, 8, 6, 4, 11, 1]; 28 | Mibs { 29 | size: 64, 30 | key_size: 64, 31 | sbox: Sbox::new(4, 4, table), 32 | isbox: Sbox::new(4, 4, itable), 33 | } 34 | } 35 | } 36 | 37 | impl Cipher for Mibs { 38 | fn structure(&self) -> CipherStructure { 39 | CipherStructure::Feistel 40 | } 41 | 42 | fn size(&self) -> usize { 43 | self.size 44 | } 45 | 46 | fn key_size(&self) -> usize { 47 | self.key_size 48 | } 49 | 50 | fn num_sboxes(&self) -> usize { 51 | self.size / self.sbox.size_in() 52 | } 53 | 54 | fn sbox(&self, _i: usize) -> &Sbox { 55 | &self.sbox 56 | } 57 | 58 | fn sbox_pos_in(&self, i: usize) -> usize { 59 | i * self.sbox(i).size_in() 60 | } 61 | 62 | fn sbox_pos_out(&self, i: usize) -> usize { 63 | i * self.sbox(i).size_out() 64 | } 65 | 66 | fn linear_layer(&self, input: u128) -> u128 { 67 | let mut x = input as u64; 68 | x ^= (x & (0xf << 16)) >> 16; 69 | x ^= (x & (0xf << 20)) >> 16; 70 | x ^= (x & (0xf << 24)) >> 16; 71 | x ^= (x & (0xf << 28)) >> 16; 72 | x ^= (x & (0xf)) << 24; 73 | x ^= (x & (0xf << 4)) << 24; 74 | x ^= (x & (0xf << 8)) << 8; 75 | x ^= (x & (0xf << 12)) << 8; 76 | x ^= (x & (0xf << 16)) >> 4; 77 | x ^= (x & (0xf << 20)) >> 20; 78 | x ^= (x & (0xf << 24)) >> 20; 79 | x ^= (x & (0xf << 28)) >> 20; 80 | x ^= (x & (0xf)) << 16; 81 | x ^= (x & (0xf << 4)) << 16; 82 | x ^= (x & (0xf << 8)) << 16; 83 | x ^= (x & (0xf << 12)) << 16; 84 | 85 | let mut output = 0; 86 | 87 | output ^= ((x) & 0xf) << (Mibs::PERMUTATION[0] * 4); 88 | output ^= ((x >> 4) & 0xf) << (Mibs::PERMUTATION[1] * 4); 89 | output ^= ((x >> 8) & 0xf) << (Mibs::PERMUTATION[2] * 4); 90 | output ^= ((x >> 12) & 0xf) << (Mibs::PERMUTATION[3] * 4); 91 | output ^= ((x >> 16) & 0xf) << (Mibs::PERMUTATION[4] * 4); 92 | output ^= ((x >> 20) & 0xf) << (Mibs::PERMUTATION[5] * 4); 93 | output ^= ((x >> 24) & 0xf) << (Mibs::PERMUTATION[6] * 4); 94 | output ^= ((x >> 28) & 0xf) << (Mibs::PERMUTATION[7] * 4); 95 | 96 | u128::from(output) 97 | } 98 | 99 | fn linear_layer_inv(&self, input: u128) -> u128 { 100 | let mut output = 0; 101 | 102 | output ^= ((input as u64) & 0xf) << (Mibs::IPERMUTATION[0] * 4); 103 | output ^= ((input as u64 >> 4) & 0xf) << (Mibs::IPERMUTATION[1] * 4); 104 | output ^= ((input as u64 >> 8) & 0xf) << (Mibs::IPERMUTATION[2] * 4); 105 | output ^= ((input as u64 >> 12) & 0xf) << (Mibs::IPERMUTATION[3] * 4); 106 | output ^= ((input as u64 >> 16) & 0xf) << (Mibs::IPERMUTATION[4] * 4); 107 | output ^= ((input as u64 >> 20) & 0xf) << (Mibs::IPERMUTATION[5] * 4); 108 | output ^= ((input as u64 >> 24) & 0xf) << (Mibs::IPERMUTATION[6] * 4); 109 | output ^= ((input as u64 >> 28) & 0xf) << (Mibs::IPERMUTATION[7] * 4); 110 | 111 | let mut x = output; 112 | 113 | x ^= (x & (0xf << 12)) << 16; 114 | x ^= (x & (0xf << 8)) << 16; 115 | x ^= (x & (0xf << 4)) << 16; 116 | x ^= (x & (0xf)) << 16; 117 | x ^= (x & (0xf << 28)) >> 20; 118 | x ^= (x & (0xf << 24)) >> 20; 119 | x ^= (x & (0xf << 20)) >> 20; 120 | x ^= (x & (0xf << 16)) >> 4; 121 | x ^= (x & (0xf << 12)) << 8; 122 | x ^= (x & (0xf << 8)) << 8; 123 | x ^= (x & (0xf << 4)) << 24; 124 | x ^= (x & (0xf)) << 24; 125 | x ^= (x & (0xf << 28)) >> 16; 126 | x ^= (x & (0xf << 24)) >> 16; 127 | x ^= (x & (0xf << 20)) >> 16; 128 | x ^= (x & (0xf << 16)) >> 16; 129 | 130 | u128::from(x) 131 | } 132 | 133 | fn reflection_layer(&self, _input: u128) -> u128 { 134 | panic!("Not implemented for this type of cipher") 135 | } 136 | 137 | fn key_schedule(&self, rounds: usize, key: &[u8]) -> Vec { 138 | if key.len() * 8 != self.key_size { 139 | panic!("invalid key-length"); 140 | } 141 | 142 | let mut keys = vec![]; 143 | let mut s = 0; 144 | 145 | // load key into 63-bit state 146 | for &k in key.iter().take(8) { 147 | s <<= 8; 148 | s |= u64::from(k); 149 | } 150 | 151 | for r in 0..rounds { 152 | s = (s >> 15) ^ (s << (64 - 15)); 153 | s = (s & 0x0fffffffffffffff) ^ (u64::from(self.sbox.apply(s >> 60)) << 60); 154 | s ^= ((r + 1) as u64) << 11; 155 | keys.push(s >> 32); 156 | } 157 | 158 | keys.iter().map(|&x| u128::from(x)).collect() 159 | } 160 | 161 | fn encrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 162 | let mut output = input as u64; 163 | 164 | for &round_key in round_keys.iter().take(32) { 165 | let mut left = output >> 32; 166 | let right = output & 0xffffffff; 167 | output = left; 168 | 169 | // Add round key 170 | left ^= round_key as u64; 171 | 172 | // Sbox 173 | let mut tmp = 0; 174 | 175 | for j in 0..8 { 176 | tmp ^= u128::from(self.sbox.apply((left >> (4 * j)) & 0xf)) << (4 * j); 177 | } 178 | 179 | // Linear layer 180 | left = self.linear_layer(tmp) as u64; 181 | 182 | output ^= (right ^ left) << 32; 183 | } 184 | 185 | output = (output >> 32) ^ (output << 32); 186 | u128::from(output) 187 | } 188 | 189 | fn decrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 190 | let mut output = input as u64; 191 | 192 | for i in 0..32 { 193 | let mut left = output >> 32; 194 | let right = output & 0xffffffff; 195 | output = left; 196 | 197 | // Add round key 198 | left ^= round_keys[31 - i] as u64; 199 | 200 | // Sbox 201 | let mut tmp = 0; 202 | 203 | for j in 0..8 { 204 | tmp ^= u128::from(self.sbox.apply((left >> (4 * j)) & 0xf)) << (4 * j); 205 | } 206 | 207 | // Linear layer 208 | left = self.linear_layer(tmp) as u64; 209 | 210 | output ^= (right ^ left) << 32; 211 | } 212 | 213 | u128::from((output >> 32) ^ (output << 32)) 214 | } 215 | 216 | fn name(&self) -> String { 217 | String::from("MIBS") 218 | } 219 | 220 | fn sbox_mask_transform( 221 | &self, 222 | input: u128, 223 | output: u128, 224 | property_type: PropertyType, 225 | ) -> (u128, u128) { 226 | match property_type { 227 | PropertyType::Linear => { 228 | let input = input as u64; 229 | let output = self.linear_layer(output & 0xffffffff) as u64 230 | ^ ((self.linear_layer(output >> 32) as u64) << 32); 231 | let mut alpha = output; 232 | alpha ^= input << 32; 233 | 234 | let mut beta = output; 235 | beta ^= input >> 32; 236 | 237 | (u128::from(alpha), u128::from(beta)) 238 | } 239 | PropertyType::Differential => { 240 | let input = input as u64; 241 | let output = self.linear_layer(output & 0xffffffff) as u64 242 | ^ ((self.linear_layer(output >> 32) as u64) << 32); 243 | let mut delta = (input >> 32) ^ (input << 32); 244 | delta ^= output & 0xffffffff; 245 | 246 | let mut nabla = (input >> 32) ^ (input << 32); 247 | nabla ^= output & 0xffffffff00000000; 248 | 249 | (u128::from(delta), u128::from(nabla)) 250 | } 251 | } 252 | } 253 | 254 | #[inline(always)] 255 | fn whitening(&self) -> bool { 256 | false 257 | } 258 | } 259 | 260 | impl Default for Mibs { 261 | fn default() -> Self { 262 | Mibs::new() 263 | } 264 | } 265 | 266 | #[cfg(test)] 267 | mod tests { 268 | use crate::cipher; 269 | 270 | #[test] 271 | fn encryption_test() { 272 | let cipher = cipher::name_to_cipher("mibs").unwrap(); 273 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 274 | let round_keys = cipher.key_schedule(32, &key); 275 | let plaintext = 0x0000000000000000; 276 | let ciphertext = 0x6d1d3722e19613d2; 277 | 278 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 279 | 280 | let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 281 | let round_keys = cipher.key_schedule(32, &key); 282 | let plaintext = 0xffffffffffffffff; 283 | let ciphertext = 0x595263b93ffe6e18; 284 | 285 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 286 | } 287 | 288 | #[test] 289 | fn decryption_test() { 290 | let cipher = cipher::name_to_cipher("mibs").unwrap(); 291 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 292 | let round_keys = cipher.key_schedule(32, &key); 293 | let plaintext = 0x0000000000000000; 294 | let ciphertext = 0x6d1d3722e19613d2; 295 | 296 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 297 | 298 | let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 299 | let round_keys = cipher.key_schedule(32, &key); 300 | let plaintext = 0xffffffffffffffff; 301 | let ciphertext = 0x595263b93ffe6e18; 302 | 303 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 304 | } 305 | 306 | #[test] 307 | fn encryption_decryption_test() { 308 | let cipher = cipher::name_to_cipher("mibs").unwrap(); 309 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 310 | let round_keys = cipher.key_schedule(32, &key); 311 | let plaintext = 0x0123456789abcdef; 312 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 313 | 314 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 315 | 316 | let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 317 | let round_keys = cipher.key_schedule(32, &key); 318 | let plaintext = 0x0123456789abcdef; 319 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 320 | 321 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 322 | } 323 | } 324 | -------------------------------------------------------------------------------- /src/src/cipher/klein.rs: -------------------------------------------------------------------------------- 1 | //! Implementation of KLEIN. 2 | 3 | use crate::cipher::{Cipher, CipherStructure}; 4 | use crate::property::PropertyType; 5 | use crate::sbox::Sbox; 6 | use std::mem; 7 | 8 | /***************************************************************** 9 | KLEIN 10 | ******************************************************************/ 11 | 12 | /// A structure representing the KLEIN cipher. 13 | #[derive(Clone)] 14 | pub struct Klein { 15 | size: usize, 16 | key_size: usize, 17 | sbox: Sbox, 18 | } 19 | 20 | impl Klein { 21 | /// Create a new instance of the cipher. 22 | pub fn new() -> Klein { 23 | let table = vec![ 24 | 0x7, 0x4, 0xa, 0x9, 0x1, 0xf, 0xb, 0x0, 0xc, 0x3, 0x2, 0x6, 0x8, 0xe, 0xd, 0x5, 25 | ]; 26 | Klein { 27 | size: 64, 28 | key_size: 64, 29 | sbox: Sbox::new(4, 4, table), 30 | } 31 | } 32 | } 33 | 34 | /** 35 | Calculate y*02 in the Rijndael finite field 36 | */ 37 | fn mult_02(y: u8) -> u8 { 38 | let t = y << 1; 39 | let u = 0xff * ((y >> 7) & 0x1); 40 | (u & 0x1b) ^ t 41 | } 42 | 43 | /** 44 | Calculate y*04 in the Rijndael finite field 45 | */ 46 | fn mult_04(y: u8) -> u8 { 47 | mult_02(mult_02(y)) 48 | } 49 | 50 | /** 51 | Calculate y*08 in the Rijndael finite field 52 | */ 53 | fn mult_08(y: u8) -> u8 { 54 | mult_02(mult_04(y)) 55 | } 56 | 57 | impl Cipher for Klein { 58 | fn structure(&self) -> CipherStructure { 59 | CipherStructure::Spn 60 | } 61 | 62 | fn size(&self) -> usize { 63 | self.size 64 | } 65 | 66 | fn key_size(&self) -> usize { 67 | self.key_size 68 | } 69 | 70 | fn num_sboxes(&self) -> usize { 71 | self.size / self.sbox.size_in() 72 | } 73 | 74 | fn sbox(&self, _i: usize) -> &Sbox { 75 | &self.sbox 76 | } 77 | 78 | fn sbox_pos_in(&self, i: usize) -> usize { 79 | i * self.sbox(i).size_in() 80 | } 81 | 82 | fn sbox_pos_out(&self, i: usize) -> usize { 83 | i * self.sbox(i).size_out() 84 | } 85 | 86 | fn linear_layer(&self, input: u128) -> u128 { 87 | let mut output = input as u64; 88 | 89 | // RotateNibbles 90 | output = (output << 16) ^ (output >> 48); 91 | 92 | // MixNibbles 93 | for i in 0..2 { 94 | let mut x = [ 95 | ((output >> (i * 32 + 24)) & 0xff) as u8, 96 | ((output >> (i * 32 + 16)) & 0xff) as u8, 97 | ((output >> (i * 32 + 8)) & 0xff) as u8, 98 | ((output >> (i * 32)) & 0xff) as u8, 99 | ]; 100 | 101 | let t = x[0] ^ x[1] ^ x[2] ^ x[3]; 102 | let u = x[3] ^ x[0]; 103 | 104 | for j in 0..3 { 105 | x[j] = x[j] ^ mult_02(x[j] ^ x[j + 1]) ^ t; 106 | } 107 | x[3] = x[3] ^ mult_02(u) ^ t; 108 | 109 | output &= !(0xffffffff << (i * 32)); 110 | output ^= u64::from(x[0]) << (i * 32 + 24); 111 | output ^= u64::from(x[1]) << (i * 32 + 16); 112 | output ^= u64::from(x[2]) << (i * 32 + 8); 113 | output ^= u64::from(x[3]) << (i * 32); 114 | } 115 | 116 | u128::from(output) 117 | } 118 | 119 | fn linear_layer_inv(&self, input: u128) -> u128 { 120 | let mut output = input as u64; 121 | 122 | // MixNibbles inverse 123 | for i in 0..2 { 124 | let x = [ 125 | ((output >> (i * 32 + 24)) & 0xff) as u8, 126 | ((output >> (i * 32 + 16)) & 0xff) as u8, 127 | ((output >> (i * 32 + 8)) & 0xff) as u8, 128 | ((output >> (i * 32)) & 0xff) as u8, 129 | ]; 130 | 131 | let mut y = [0, 0, 0, 0]; 132 | 133 | y[0] = mult_08(x[0] ^ x[1] ^ x[2] ^ x[3]) 134 | ^ mult_04(x[0] ^ x[2]) 135 | ^ mult_02(x[0] ^ x[1]) 136 | ^ x[1] 137 | ^ x[2] 138 | ^ x[3]; 139 | y[1] = mult_08(x[1] ^ x[2] ^ x[3] ^ x[0]) 140 | ^ mult_04(x[1] ^ x[3]) 141 | ^ mult_02(x[1] ^ x[2]) 142 | ^ x[2] 143 | ^ x[3] 144 | ^ x[0]; 145 | y[2] = mult_08(x[2] ^ x[3] ^ x[0] ^ x[1]) 146 | ^ mult_04(x[2] ^ x[0]) 147 | ^ mult_02(x[2] ^ x[3]) 148 | ^ x[3] 149 | ^ x[0] 150 | ^ x[1]; 151 | y[3] = mult_08(x[3] ^ x[0] ^ x[1] ^ x[2]) 152 | ^ mult_04(x[3] ^ x[1]) 153 | ^ mult_02(x[3] ^ x[0]) 154 | ^ x[0] 155 | ^ x[1] 156 | ^ x[2]; 157 | 158 | output &= !(0xffffffff << (i * 32)); 159 | output ^= u64::from(y[0]) << (i * 32 + 24); 160 | output ^= u64::from(y[1]) << (i * 32 + 16); 161 | output ^= u64::from(y[2]) << (i * 32 + 8); 162 | output ^= u64::from(y[3]) << (i * 32); 163 | } 164 | 165 | // RotateNibbles inverse 166 | output = (output >> 16) ^ (output << 48); 167 | 168 | u128::from(output) 169 | } 170 | 171 | fn reflection_layer(&self, _input: u128) -> u128 { 172 | panic!("Not implemented for this type of cipher") 173 | } 174 | 175 | fn key_schedule(&self, rounds: usize, key: &[u8]) -> Vec { 176 | if key.len() * 8 != self.key_size { 177 | panic!("invalid key-length"); 178 | } 179 | 180 | let mut keys = vec![]; 181 | let mut k0 = 0; 182 | let mut k1 = 0; 183 | 184 | for i in 0..4 { 185 | k1 <<= 8; 186 | k0 <<= 8; 187 | k1 |= u128::from(key[i]); 188 | k0 |= u128::from(key[i + 4]); 189 | } 190 | 191 | for r in 0..=rounds { 192 | keys.push(k0 ^ (k1 << 32)); 193 | 194 | k0 = ((k0 << 8) & 0xffffff00) ^ ((k0 >> 24) & 0x000000ff); 195 | k1 = ((k1 << 8) & 0xffffff00) ^ ((k1 >> 24) & 0x000000ff); 196 | k1 ^= k0; 197 | mem::swap(&mut k0, &mut k1); 198 | 199 | for i in 2..6 { 200 | k0 = (k0 & !(0xf << (4 * i))) 201 | ^ (u128::from(self.sbox.apply((k0 >> (4 * i)) & 0xf)) << (4 * i)); 202 | } 203 | 204 | k1 ^= ((r + 1) as u128) << 8; 205 | } 206 | 207 | keys 208 | } 209 | 210 | fn encrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 211 | let mut output = input; 212 | 213 | for &round_key in round_keys.iter().take(12) { 214 | // Add key 215 | output ^= round_key; 216 | 217 | // SubNibbles 218 | let mut tmp = 0; 219 | 220 | for j in 0..16 { 221 | tmp ^= u128::from(self.sbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 222 | } 223 | 224 | // Linear layer 225 | output = self.linear_layer(tmp); 226 | } 227 | 228 | output ^= round_keys[12]; 229 | output 230 | } 231 | 232 | fn decrypt(&self, input: u128, round_keys: &[u128]) -> u128 { 233 | let mut output = input; 234 | 235 | for i in 0..12 { 236 | // Add key 237 | output ^= round_keys[12 - i]; 238 | 239 | // Linear layer 240 | output = self.linear_layer_inv(output); 241 | 242 | // SubNibbles 243 | let mut tmp = 0; 244 | 245 | for j in 0..16 { 246 | tmp ^= u128::from(self.sbox.apply((output >> (4 * j)) & 0xf)) << (4 * j); 247 | } 248 | 249 | output = tmp; 250 | } 251 | 252 | output ^= round_keys[0]; 253 | output 254 | } 255 | 256 | fn name(&self) -> String { 257 | String::from("KLEIN") 258 | } 259 | 260 | fn sbox_mask_transform( 261 | &self, 262 | input: u128, 263 | output: u128, 264 | _property_type: PropertyType, 265 | ) -> (u128, u128) { 266 | (input, self.linear_layer(output)) 267 | } 268 | 269 | #[inline(always)] 270 | fn whitening(&self) -> bool { 271 | true 272 | } 273 | } 274 | 275 | impl Default for Klein { 276 | fn default() -> Self { 277 | Klein::new() 278 | } 279 | } 280 | 281 | #[cfg(test)] 282 | mod tests { 283 | use crate::cipher; 284 | 285 | #[test] 286 | fn encryption_test() { 287 | let cipher = cipher::name_to_cipher("klein").unwrap(); 288 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 289 | let round_keys = cipher.key_schedule(12, &key); 290 | let plaintext = 0xffffffffffffffff; 291 | let ciphertext = 0xcdc0b51f14722bbe; 292 | 293 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 294 | 295 | let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 296 | let round_keys = cipher.key_schedule(12, &key); 297 | let plaintext = 0x0000000000000000; 298 | let ciphertext = 0x6456764e8602e154; 299 | 300 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 301 | 302 | let key = [0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef]; 303 | let round_keys = cipher.key_schedule(12, &key); 304 | let plaintext = 0xffffffffffffffff; 305 | let ciphertext = 0x592356c4997176c8; 306 | 307 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 308 | 309 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 310 | let round_keys = cipher.key_schedule(12, &key); 311 | let plaintext = 0x1234567890abcdef; 312 | let ciphertext = 0x629f9d6dff95800e; 313 | 314 | assert_eq!(ciphertext, cipher.encrypt(plaintext, &round_keys)); 315 | } 316 | 317 | #[test] 318 | fn decryption_test() { 319 | let cipher = cipher::name_to_cipher("klein").unwrap(); 320 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 321 | let round_keys = cipher.key_schedule(12, &key); 322 | let plaintext = 0xffffffffffffffff; 323 | let ciphertext = 0xcdc0b51f14722bbe; 324 | 325 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 326 | 327 | let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 328 | let round_keys = cipher.key_schedule(12, &key); 329 | let plaintext = 0x0000000000000000; 330 | let ciphertext = 0x6456764e8602e154; 331 | 332 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 333 | 334 | let key = [0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef]; 335 | let round_keys = cipher.key_schedule(12, &key); 336 | let plaintext = 0xffffffffffffffff; 337 | let ciphertext = 0x592356c4997176c8; 338 | 339 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 340 | 341 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 342 | let round_keys = cipher.key_schedule(12, &key); 343 | let plaintext = 0x1234567890abcdef; 344 | let ciphertext = 0x629f9d6dff95800e; 345 | 346 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 347 | } 348 | 349 | #[test] 350 | fn encryption_decryption_test() { 351 | let cipher = cipher::name_to_cipher("klein").unwrap(); 352 | let key = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; 353 | let round_keys = cipher.key_schedule(12, &key); 354 | let plaintext = 0x0123456789abcdef; 355 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 356 | 357 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 358 | 359 | let key = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; 360 | let round_keys = cipher.key_schedule(12, &key); 361 | let plaintext = 0x0123456789abcdef; 362 | let ciphertext = cipher.encrypt(plaintext, &round_keys); 363 | 364 | assert_eq!(plaintext, cipher.decrypt(ciphertext, &round_keys)); 365 | } 366 | } 367 | --------------------------------------------------------------------------------