From eda805d7fe9cf2a21d35d21928707293088e2236 Mon Sep 17 00:00:00 2001 From: Gulshan Singh Date: Mon, 23 Jan 2017 00:24:46 -0800 Subject: [PATCH 01/15] des: add stub struct and impls --- des/Cargo.toml | 16 ++++++++++++++++ des/src/lib.rs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 des/Cargo.toml create mode 100644 des/src/lib.rs diff --git a/des/Cargo.toml b/des/Cargo.toml new file mode 100644 index 00000000..04bffa76 --- /dev/null +++ b/des/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "des" +version = "0.1.0" +authors = ["The Rust-Crypto Project Developers"] +license = "MIT/Apache-2.0" +description = "DES block cipher" +documentation = "https://docs.rs/des" +repository = "https://github.com/RustCrypto/block-ciphers" +keywords = ["crypto", "des", "block-cipher"] + +[dev-dependencies] +crypto-tests = "0.2" + +[dependencies] +generic-array = "0.5" +block-cipher-trait = "0.2" diff --git a/des/src/lib.rs b/des/src/lib.rs new file mode 100644 index 00000000..beeb7f2d --- /dev/null +++ b/des/src/lib.rs @@ -0,0 +1,33 @@ +extern crate block_cipher_trait; +extern crate generic_array; + +use block_cipher_trait::{Block, BlockCipher, BlockCipherFixKey}; +use generic_array::GenericArray; +use generic_array::typenum::U8; + +#[derive(Copy, Clone)] +struct Des { +} + +impl Des { +} + +impl BlockCipher for Des { + type BlockSize = U8; + + fn encrypt_block(&self, input: &Block, output: &mut Block) { + unimplemented!() + } + + fn decrypt_block(&self, input: &Block, output: &mut Block) { + unimplemented!() + } +} + +impl BlockCipherFixKey for Des { + type KeySize = U8; + + fn new(key: &GenericArray) -> Self { + unimplemented!() + } +} From 4d54315b3f422977ba5d0abf7febb3a427c02a40 Mon Sep 17 00:00:00 2001 From: Gulshan Singh Date: Mon, 23 Jan 2017 18:19:50 -0800 Subject: [PATCH 02/15] des: added constants and implemented sbox function --- des/src/consts.rs | 89 +++++++++++++++++++++++++++++++++++++++++++++++ des/src/lib.rs | 22 +++++++++++- 2 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 des/src/consts.rs diff --git a/des/src/consts.rs b/des/src/consts.rs new file mode 100644 index 00000000..21d218a8 --- /dev/null +++ b/des/src/consts.rs @@ -0,0 +1,89 @@ +pub const INITIAL_PBOX: [u8; 64] = [ + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7, + 56, 48, 40, 32, 24, 16, 8, 0, + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, +]; + +// TODO: This is off by one +pub const FINAL_PBOX: [u8; 64] = [ + 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25, +]; + +pub const EXPANSION_BOX: [u8; 48] = [ + 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, 16, 17, 18, 19, 20, 19, 20, + 21, 22, 23, 24, 23, 24, 25, 26, + 27, 28, 27, 28, 29, 30, 31, 0, +]; + +pub const ROUND_PBOX: [u8; 32] = [ + 15, 6, 19, 20, 28, 11, 27, 16, + 0, 14, 22, 25, 4, 17, 30, 9, + 1, 7, 23, 13, 31, 26, 2, 8, + 18, 12, 29, 5, 21, 10, 3, 24, +]; + +pub const SBOXES: [[u8; 64]; 8] = [ + [ + 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1, + 3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8, + 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7, + 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13, + ], + [ + 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14, + 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5, + 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2, + 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9, + ], + [ + 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10, + 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1, + 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7, + 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12, + ], + [ + 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3, + 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9, + 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8, + 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14, + ], + [ + 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1, + 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6, + 4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13, + 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3, + ], + [ + 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5, + 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8, + 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10, + 7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13, + ], + [ + 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10, + 3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6, + 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7, + 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12, + ], + [ + 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4, + 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2, + 7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13, + 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11, + ], +]; diff --git a/des/src/lib.rs b/des/src/lib.rs index beeb7f2d..0ebf377d 100644 --- a/des/src/lib.rs +++ b/des/src/lib.rs @@ -1,22 +1,42 @@ extern crate block_cipher_trait; extern crate generic_array; +mod consts; + use block_cipher_trait::{Block, BlockCipher, BlockCipherFixKey}; use generic_array::GenericArray; use generic_array::typenum::U8; +use consts::SBOXES; + #[derive(Copy, Clone)] struct Des { } impl Des { + fn apply_sboxes( + &self, + input: u64, + ) -> u64 { + let mut output: u64 = 0; + for i in 0..8 { + let sbox = SBOXES[i]; + let val = (input >> (i * 6)) & 0x3F; + output |= (sbox[val as usize] as u64) << (i * 6); + } + + output + } + + fn apply_pbox(&self) { + } } impl BlockCipher for Des { type BlockSize = U8; fn encrypt_block(&self, input: &Block, output: &mut Block) { - unimplemented!() + } fn decrypt_block(&self, input: &Block, output: &mut Block) { From 71b53f11a43aa81b3004884b639e2e8718f60305 Mon Sep 17 00:00:00 2001 From: Gulshan Singh Date: Tue, 24 Jan 2017 15:10:50 -0800 Subject: [PATCH 03/15] des: implemented apply_pboxa --- des/src/lib.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/des/src/lib.rs b/des/src/lib.rs index 0ebf377d..575cd663 100644 --- a/des/src/lib.rs +++ b/des/src/lib.rs @@ -4,8 +4,8 @@ extern crate generic_array; mod consts; use block_cipher_trait::{Block, BlockCipher, BlockCipherFixKey}; -use generic_array::GenericArray; -use generic_array::typenum::U8; +use generic_array::{ArrayLength, GenericArray}; +use generic_array::typenum::{Cmp, Compare, Less, Same, U8, U65}; use consts::SBOXES; @@ -14,10 +14,8 @@ struct Des { } impl Des { - fn apply_sboxes( - &self, - input: u64, - ) -> u64 { + /// Applies all eight sboxes to the input + fn apply_sboxes(&self, input: u64) -> u64 { let mut output: u64 = 0; for i in 0..8 { let sbox = SBOXES[i]; @@ -28,7 +26,17 @@ impl Des { output } - fn apply_pbox(&self) { + /// Applies the given pbox to the input + fn apply_pbox(&self, input: u64, pbox: GenericArray) -> u64 + where N: ArrayLength + Cmp, + Compare: Same, + { + let len = N::to_usize(); + let mut output = 0; + for i in 0..len { + output |= ((1 << pbox[i]) & input) << i; + } + output } } From 7f026208877df84e5988abaa180c79d65806fa52 Mon Sep 17 00:00:00 2001 From: Gulshan Singh Date: Tue, 24 Jan 2017 16:02:13 -0800 Subject: [PATCH 04/15] des: implemented round function and encrypt_block --- des/Cargo.toml | 1 + des/src/lib.rs | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/des/Cargo.toml b/des/Cargo.toml index 04bffa76..6f3606c6 100644 --- a/des/Cargo.toml +++ b/des/Cargo.toml @@ -14,3 +14,4 @@ crypto-tests = "0.2" [dependencies] generic-array = "0.5" block-cipher-trait = "0.2" +byte-tools = "0.1" diff --git a/des/src/lib.rs b/des/src/lib.rs index 575cd663..f880f382 100644 --- a/des/src/lib.rs +++ b/des/src/lib.rs @@ -1,19 +1,31 @@ extern crate block_cipher_trait; +extern crate byte_tools; extern crate generic_array; mod consts; use block_cipher_trait::{Block, BlockCipher, BlockCipherFixKey}; use generic_array::{ArrayLength, GenericArray}; -use generic_array::typenum::{Cmp, Compare, Less, Same, U8, U65}; +use generic_array::typenum::{Cmp, Compare, Less, Same, U8, U64, U65}; -use consts::SBOXES; +use consts::{INITIAL_PBOX, FINAL_PBOX, SBOXES}; #[derive(Copy, Clone)] struct Des { } impl Des { + fn round(&self, input: u64) -> u64 { + let l = input & 0xFFFFFFFF; + let r = input >> 32; + + ((self.f(r as u32) as u64 ^ l) << 32) & r + } + + fn f(&self, input: u32) -> u32 { + 0 + } + /// Applies all eight sboxes to the input fn apply_sboxes(&self, input: u64) -> u64 { let mut output: u64 = 0; @@ -44,7 +56,24 @@ impl BlockCipher for Des { type BlockSize = U8; fn encrypt_block(&self, input: &Block, output: &mut Block) { + let rounds = 16; + // TODO: Better way to initialize this + let mut data = [0]; + byte_tools::read_u64v_be(&mut data, input); + let mut data = data[0]; + data = self.apply_pbox::( + data, + GenericArray::from_slice(&INITIAL_PBOX), + ); + for _ in 0..rounds { + data = self.round(data); + } + data = self.apply_pbox::( + data, + GenericArray::from_slice(&FINAL_PBOX), + ); + byte_tools::write_u64_be(output, data); } fn decrypt_block(&self, input: &Block, output: &mut Block) { From 2e482cd1799abc309a7eaf985e86388ba165ef53 Mon Sep 17 00:00:00 2001 From: Gulshan Singh Date: Tue, 24 Jan 2017 16:15:08 -0800 Subject: [PATCH 05/15] des: implemented feistl function --- des/src/consts.rs | 2 +- des/src/lib.rs | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/des/src/consts.rs b/des/src/consts.rs index 21d218a8..0bd76030 100644 --- a/des/src/consts.rs +++ b/des/src/consts.rs @@ -21,7 +21,7 @@ pub const FINAL_PBOX: [u8; 64] = [ 33, 1, 41, 9, 49, 17, 57, 25, ]; -pub const EXPANSION_BOX: [u8; 48] = [ +pub const EXPANSION_PBOX: [u8; 48] = [ 31, 0, 1, 2, 3, 4, 3, 4, 5, 6, 7, 8, 7, 8, 9, 10, 11, 12, 11, 12, 13, 14, 15, 16, diff --git a/des/src/lib.rs b/des/src/lib.rs index f880f382..458224a6 100644 --- a/des/src/lib.rs +++ b/des/src/lib.rs @@ -6,12 +6,13 @@ mod consts; use block_cipher_trait::{Block, BlockCipher, BlockCipherFixKey}; use generic_array::{ArrayLength, GenericArray}; -use generic_array::typenum::{Cmp, Compare, Less, Same, U8, U64, U65}; +use generic_array::typenum::{Cmp, Compare, Less, Same, U8, U32, U48, U64, U65}; -use consts::{INITIAL_PBOX, FINAL_PBOX, SBOXES}; +use consts::{EXPANSION_PBOX, INITIAL_PBOX, FINAL_PBOX, ROUND_PBOX, SBOXES}; #[derive(Copy, Clone)] struct Des { + key: u64, } impl Des { @@ -23,7 +24,18 @@ impl Des { } fn f(&self, input: u32) -> u32 { - 0 + let mut val = self.apply_pbox::( + input as u64, + GenericArray::from_slice(&EXPANSION_PBOX), + ); + val ^= self.key; + val = self.apply_sboxes(val); + self.apply_pbox::( + val, + GenericArray::from_slice(&ROUND_PBOX), + ); + + val as u32 } /// Applies all eight sboxes to the input From 480205fefa5f928a0f6e715ae17b57b17fd4e310 Mon Sep 17 00:00:00 2001 From: Gulshan Singh Date: Tue, 24 Jan 2017 16:17:30 -0800 Subject: [PATCH 06/15] des: implemented BlockCipherFixKey::new() --- des/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/des/src/lib.rs b/des/src/lib.rs index 458224a6..bf37035b 100644 --- a/des/src/lib.rs +++ b/des/src/lib.rs @@ -97,6 +97,8 @@ impl BlockCipherFixKey for Des { type KeySize = U8; fn new(key: &GenericArray) -> Self { - unimplemented!() + let mut key_val = [0]; + byte_tools::read_u64v_be(&mut key_val, key); + Des { key: key_val[0] } } } From 8fbe1145ff07d38c3a33121f37fcd5f140e0f6ae Mon Sep 17 00:00:00 2001 From: Gulshan Singh Date: Tue, 24 Jan 2017 16:31:01 -0800 Subject: [PATCH 07/15] des: fixed FINAL_PBOX --- des/src/consts.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/des/src/consts.rs b/des/src/consts.rs index 0bd76030..7d4bf204 100644 --- a/des/src/consts.rs +++ b/des/src/consts.rs @@ -9,16 +9,15 @@ pub const INITIAL_PBOX: [u8; 64] = [ 62, 54, 46, 38, 30, 22, 14, 6, ]; -// TODO: This is off by one pub const FINAL_PBOX: [u8; 64] = [ - 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, - 33, 1, 41, 9, 49, 17, 57, 25, + 33, 1, 41, 9, 49, 17, 57, 25, + 32, 0, 40, 8, 48, 16, 56, 24, ]; pub const EXPANSION_PBOX: [u8; 48] = [ @@ -37,6 +36,12 @@ pub const ROUND_PBOX: [u8; 32] = [ 18, 12, 29, 5, 21, 10, 3, 24, ]; +// These boxes are not the same ones that appear in the literature. Normally, +// the first and the last bits of the six input bits are used to choose the row +// and the middle four bits are used to choose the column. These sboxes are +// rearranged so that the bottom four bits choose the column and the top two +// bits choose the row. In other words, we can directly index the sbox array +// with the 6 input bits to get the correct value. pub const SBOXES: [[u8; 64]; 8] = [ [ 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1, From 1e75cd49cc756cfef25c2ef3da5cda9d52b9cea6 Mon Sep 17 00:00:00 2001 From: Gulshan Singh Date: Tue, 24 Jan 2017 18:59:56 -0800 Subject: [PATCH 08/15] des: implemented key schedule and decryption function --- des/src/consts.rs | 21 ++++++++++ des/src/lib.rs | 98 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 96 insertions(+), 23 deletions(-) diff --git a/des/src/consts.rs b/des/src/consts.rs index 7d4bf204..fca504ae 100644 --- a/des/src/consts.rs +++ b/des/src/consts.rs @@ -36,6 +36,27 @@ pub const ROUND_PBOX: [u8; 32] = [ 18, 12, 29, 5, 21, 10, 3, 24, ]; +pub const SHIFTS: [u8; 16] = [ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 ]; + +pub const PC1: [u8; 56] = [ + 49, 42, 35, 28, 21, 14, 7, 0, + 50, 43, 36, 29, 22, 15, 8, 1, + 51, 44, 37, 30, 23, 16, 9, 2, + 52, 45, 38, 31, 55, 48, 41, 34, + 27, 20, 13, 6, 54, 47, 40, 33, + 26, 19, 12, 5, 53, 46, 39, 32, + 25, 18, 11, 4, 24, 17, 10, 3, +]; + +pub const PC2: [u8; 48] = [ + 13, 16, 10, 23, 0, 4, 2, 27, + 14, 5, 20, 9, 22, 18, 11, 3, + 25, 7, 15, 6, 26, 19, 12, 1, + 40, 51, 30, 36, 46, 54, 29, 39, + 50, 44, 32, 47, 43, 48, 38, 55, + 33, 52, 45, 41, 49, 35, 28, 31, +]; + // These boxes are not the same ones that appear in the literature. Normally, // the first and the last bits of the six input bits are used to choose the row // and the middle four bits are used to choose the column. These sboxes are diff --git a/des/src/lib.rs b/des/src/lib.rs index bf37035b..5adc828d 100644 --- a/des/src/lib.rs +++ b/des/src/lib.rs @@ -6,9 +6,17 @@ mod consts; use block_cipher_trait::{Block, BlockCipher, BlockCipherFixKey}; use generic_array::{ArrayLength, GenericArray}; -use generic_array::typenum::{Cmp, Compare, Less, Same, U8, U32, U48, U64, U65}; - -use consts::{EXPANSION_PBOX, INITIAL_PBOX, FINAL_PBOX, ROUND_PBOX, SBOXES}; +use generic_array::typenum::{ + Cmp, Compare, Less, Same, + U8, U32, U48, U56, U64, U65, +}; + +use consts::{ + EXPANSION_PBOX, + INITIAL_PBOX, FINAL_PBOX, + PC1, PC2, + ROUND_PBOX, SBOXES, SHIFTS, +}; #[derive(Copy, Clone)] struct Des { @@ -16,19 +24,52 @@ struct Des { } impl Des { - fn round(&self, input: u64) -> u64 { + fn do_rounds(&self, input: u64, keys: [u64; 16]) -> u64 { + let mut data = self.apply_pbox::( + input, + GenericArray::from_slice(&INITIAL_PBOX), + ); + for key in keys.iter() { + data = self.round(data, *key); + } + data = self.apply_pbox::( + data, + GenericArray::from_slice(&FINAL_PBOX), + ); + + data + } + + fn get_keys(&self) -> [u64; 16] { + let mut keys: [u64; 16] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + let mut key = self.apply_pbox::( + self.key, + GenericArray::from_slice(&PC1), + ); + + for i in 0..16 { + key = self.get_next_round_key(key, i); + keys[i] = key; + } + + keys + } + + fn round(&self, input: u64, key: u64) -> u64 { let l = input & 0xFFFFFFFF; let r = input >> 32; - ((self.f(r as u32) as u64 ^ l) << 32) & r + ((self.f(r as u32, key) as u64 ^ l) << 32) & r } - fn f(&self, input: u32) -> u32 { + fn f(&self, input: u32, key: u64) -> u32 { let mut val = self.apply_pbox::( input as u64, GenericArray::from_slice(&EXPANSION_PBOX), ); - val ^= self.key; + val ^= key; val = self.apply_sboxes(val); self.apply_pbox::( val, @@ -62,34 +103,45 @@ impl Des { } output } + + fn get_next_round_key(&self, key: u64, round: usize) -> u64 { + let c = self.rotate(key & 0x0FFFFFFF, SHIFTS[round]); + let d = self.rotate(key >> 28, SHIFTS[round]); + + self.apply_pbox::((d << 28) & c, GenericArray::from_slice(&PC2)) + } + + /// Performs a left rotate on a 28 bit number + fn rotate(&self, mut val: u64, shift: u8) -> u64 { + let top_bits = val >> (28 - shift); + val <<= shift; + + val & top_bits & 0x0FFFFFFF + } } impl BlockCipher for Des { type BlockSize = U8; fn encrypt_block(&self, input: &Block, output: &mut Block) { - let rounds = 16; - // TODO: Better way to initialize this + // TODO: Better way to initialize this? let mut data = [0]; byte_tools::read_u64v_be(&mut data, input); - let mut data = data[0]; - data = self.apply_pbox::( - data, - GenericArray::from_slice(&INITIAL_PBOX), - ); - for _ in 0..rounds { - data = self.round(data); - } - data = self.apply_pbox::( - data, - GenericArray::from_slice(&FINAL_PBOX), - ); - byte_tools::write_u64_be(output, data); + let keys = self.get_keys(); + let res = self.do_rounds(data[0], keys); + byte_tools::write_u64_be(output, res); } fn decrypt_block(&self, input: &Block, output: &mut Block) { - unimplemented!() + // TODO: Better way to initialize this? + let mut data = [0]; + byte_tools::read_u64v_be(&mut data, input); + + let mut keys = self.get_keys(); + keys.reverse(); + let res = self.do_rounds(data[0], keys); + byte_tools::write_u64_be(output, res); } } From 8dae2c200bc722f7824b8101064dcaddd80cf5c5 Mon Sep 17 00:00:00 2001 From: Gulshan Singh Date: Wed, 25 Jan 2017 12:07:27 -0800 Subject: [PATCH 09/15] des: fixed remaining bugs --- des/src/consts.rs | 16 ++++----- des/src/lib.rs | 88 ++++++++++++++++++++++++++--------------------- 2 files changed, 57 insertions(+), 47 deletions(-) mode change 100644 => 100755 des/src/lib.rs diff --git a/des/src/consts.rs b/des/src/consts.rs index fca504ae..57ba070b 100644 --- a/des/src/consts.rs +++ b/des/src/consts.rs @@ -36,16 +36,16 @@ pub const ROUND_PBOX: [u8; 32] = [ 18, 12, 29, 5, 21, 10, 3, 24, ]; -pub const SHIFTS: [u8; 16] = [ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 ]; +pub const SHIFTS: [u8; 16] = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]; pub const PC1: [u8; 56] = [ - 49, 42, 35, 28, 21, 14, 7, 0, - 50, 43, 36, 29, 22, 15, 8, 1, - 51, 44, 37, 30, 23, 16, 9, 2, - 52, 45, 38, 31, 55, 48, 41, 34, - 27, 20, 13, 6, 54, 47, 40, 33, - 26, 19, 12, 5, 53, 46, 39, 32, - 25, 18, 11, 4, 24, 17, 10, 3, + 56, 48, 40, 32, 24, 16, 8, 0, + 57, 49, 41, 33, 25, 17, 9, 1, + 58, 50, 42, 34, 26, 18, 10, 2, + 59, 51, 43, 35, 62, 54, 46, 38, + 30, 22, 14, 6, 61, 53, 45, 37, + 29, 21, 13, 5, 60, 52, 44, 36, + 28, 20, 12, 4, 27, 19, 11, 3, ]; pub const PC2: [u8; 48] = [ diff --git a/des/src/lib.rs b/des/src/lib.rs old mode 100644 new mode 100755 index 5adc828d..d325b42a --- a/des/src/lib.rs +++ b/des/src/lib.rs @@ -1,10 +1,12 @@ +#![no_std] + extern crate block_cipher_trait; extern crate byte_tools; extern crate generic_array; mod consts; -use block_cipher_trait::{Block, BlockCipher, BlockCipherFixKey}; +pub use block_cipher_trait::{Block, BlockCipher, BlockCipherFixKey}; use generic_array::{ArrayLength, GenericArray}; use generic_array::typenum::{ Cmp, Compare, Less, Same, @@ -19,11 +21,43 @@ use consts::{ }; #[derive(Copy, Clone)] -struct Des { +pub struct Des { key: u64, } impl Des { + fn get_keys(&self) -> [u64; 16] { + let mut keys: [u64; 16] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + let key = self.apply_pbox::( + self.key, + GenericArray::from_slice(&PC1), + ); + + // The most significant bit is bit zero, and there are only 56 bits in + // the key after applying PC1, so we need to remove the eight least + // significant bits from the key. + let key = key >> 8; + + let mut c = key >> 28; + let mut d = key & 0x0FFFFFFF; + for i in 0..16 { + c = self.rotate(c, SHIFTS[i]); + d = self.rotate(d, SHIFTS[i]); + + keys[i] = self.apply_pbox::( + ((c << 28) | d) << 8, + GenericArray::from_slice(&PC2), + ); + // // Keys are 48 bits starting from the most significant bit, so we + // // need to remove the 16 least significant bits from the key. + // keys[i] >>= 16; + } + + keys + } + fn do_rounds(&self, input: u64, keys: [u64; 16]) -> u64 { let mut data = self.apply_pbox::( input, @@ -32,39 +66,24 @@ impl Des { for key in keys.iter() { data = self.round(data, *key); } + let l = data >> 32; + let r = data & 0x0FFFFFFF; + data = r << 32 | l; data = self.apply_pbox::( data, GenericArray::from_slice(&FINAL_PBOX), ); - data } - fn get_keys(&self) -> [u64; 16] { - let mut keys: [u64; 16] = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; - let mut key = self.apply_pbox::( - self.key, - GenericArray::from_slice(&PC1), - ); - - for i in 0..16 { - key = self.get_next_round_key(key, i); - keys[i] = key; - } - - keys - } - fn round(&self, input: u64, key: u64) -> u64 { - let l = input & 0xFFFFFFFF; - let r = input >> 32; + let l = (input >> 32) << 32; + let r = (input & 0xFFFFFFFF) << 32; - ((self.f(r as u32, key) as u64 ^ l) << 32) & r + r | ((self.f(r, key) ^ l) >> 32) } - fn f(&self, input: u32, key: u64) -> u32 { + fn f(&self, input: u64, key: u64) -> u64 { let mut val = self.apply_pbox::( input as u64, GenericArray::from_slice(&EXPANSION_PBOX), @@ -74,9 +93,7 @@ impl Des { self.apply_pbox::( val, GenericArray::from_slice(&ROUND_PBOX), - ); - - val as u32 + ) } /// Applies all eight sboxes to the input @@ -84,10 +101,9 @@ impl Des { let mut output: u64 = 0; for i in 0..8 { let sbox = SBOXES[i]; - let val = (input >> (i * 6)) & 0x3F; - output |= (sbox[val as usize] as u64) << (i * 6); + let val = (input >> (58 - (i * 6))) & 0x3F; + output |= (sbox[val as usize] as u64) << (60 - (i * 4)); } - output } @@ -99,24 +115,18 @@ impl Des { let len = N::to_usize(); let mut output = 0; for i in 0..len { - output |= ((1 << pbox[i]) & input) << i; + let mask = 1 << (63 - pbox[i]); + output |= if mask & input != 0 { 1 << (63 - i) } else { 0 }; } output } - fn get_next_round_key(&self, key: u64, round: usize) -> u64 { - let c = self.rotate(key & 0x0FFFFFFF, SHIFTS[round]); - let d = self.rotate(key >> 28, SHIFTS[round]); - - self.apply_pbox::((d << 28) & c, GenericArray::from_slice(&PC2)) - } - /// Performs a left rotate on a 28 bit number fn rotate(&self, mut val: u64, shift: u8) -> u64 { let top_bits = val >> (28 - shift); val <<= shift; - val & top_bits & 0x0FFFFFFF + (val | top_bits) & 0x0FFFFFFF } } From 7083dd9c9c7970d9ad3d635440c480b5c1ef9cdf Mon Sep 17 00:00:00 2001 From: Gulshan Singh Date: Wed, 25 Jan 2017 12:07:38 -0800 Subject: [PATCH 10/15] des: added test --- des/tests/lib.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100755 des/tests/lib.rs diff --git a/des/tests/lib.rs b/des/tests/lib.rs new file mode 100755 index 00000000..bb5dbec8 --- /dev/null +++ b/des/tests/lib.rs @@ -0,0 +1,25 @@ +#![no_std] + +extern crate des; +extern crate generic_array; + +use des::{Des, BlockCipher, BlockCipherFixKey}; +use generic_array::GenericArray; + +#[test] +fn test() { + let key = GenericArray::from_slice( + &[0x13, 0x34, 0x57, 0x79, 0x9B, 0xBC, 0xDF, 0xF1], + ); + let input = GenericArray::from_slice( + &[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF], + ); + let expected = GenericArray::from_slice( + &[0x85, 0xE8, 0x13, 0x54, 0x0F, 0x0A, 0xB4, 0x05], + ); + + let d = Des::new(&key); + let mut output = GenericArray::from_slice(&[0; 8]); + d.encrypt_block(&input, &mut output); + assert_eq!(output, expected); +} From 03c945e8c5a59de177a89034afd529f3a147bb39 Mon Sep 17 00:00:00 2001 From: Gulshan Singh Date: Wed, 25 Jan 2017 13:57:42 -0800 Subject: [PATCH 11/15] des: added benchmark --- des/benches/lib.rs | 8 ++++++++ des/src/lib.rs | 5 ++--- des/tests/lib.rs | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) create mode 100755 des/benches/lib.rs diff --git a/des/benches/lib.rs b/des/benches/lib.rs new file mode 100755 index 00000000..0575c5bd --- /dev/null +++ b/des/benches/lib.rs @@ -0,0 +1,8 @@ +#![no_std] +#![feature(test)] + +#[macro_use] +extern crate crypto_tests; +extern crate des; + +bench_block_cipher!(des::Des, &[0u8; 8], &[0u8; 8]); diff --git a/des/src/lib.rs b/des/src/lib.rs index d325b42a..f40f2066 100755 --- a/des/src/lib.rs +++ b/des/src/lib.rs @@ -46,13 +46,12 @@ impl Des { c = self.rotate(c, SHIFTS[i]); d = self.rotate(d, SHIFTS[i]); + // We need the `<< 8` because the most significant bit is bit zero, + // so we need to shift our 56 bit value 8 bits to the left. keys[i] = self.apply_pbox::( ((c << 28) | d) << 8, GenericArray::from_slice(&PC2), ); - // // Keys are 48 bits starting from the most significant bit, so we - // // need to remove the 16 least significant bits from the key. - // keys[i] >>= 16; } keys diff --git a/des/tests/lib.rs b/des/tests/lib.rs index bb5dbec8..b8a115b3 100755 --- a/des/tests/lib.rs +++ b/des/tests/lib.rs @@ -19,7 +19,7 @@ fn test() { ); let d = Des::new(&key); - let mut output = GenericArray::from_slice(&[0; 8]); + let mut output = GenericArray::new(); d.encrypt_block(&input, &mut output); assert_eq!(output, expected); } From 86dd5d324f1dff43cef488c1b35df422a1d7206f Mon Sep 17 00:00:00 2001 From: Gulshan Singh Date: Wed, 25 Jan 2017 14:01:24 -0800 Subject: [PATCH 12/15] des: added license files --- des/LICENSE-APACHE | 201 +++++++++++++++++++++++++++++++++++++++++++++ des/LICENSE-MIT | 25 ++++++ 2 files changed, 226 insertions(+) create mode 100644 des/LICENSE-APACHE create mode 100644 des/LICENSE-MIT diff --git a/des/LICENSE-APACHE b/des/LICENSE-APACHE new file mode 100644 index 00000000..573db22f --- /dev/null +++ b/des/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2017 Gulshan Singh + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/des/LICENSE-MIT b/des/LICENSE-MIT new file mode 100644 index 00000000..3d35f5c6 --- /dev/null +++ b/des/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2017 Gulshan Singh + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. From cb9fb8f40729d567d7cbf78e5f7bbe5a13b39b5f Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sun, 29 Jan 2017 11:21:37 +0400 Subject: [PATCH 13/15] Optimization changes in lib.rs --- des/src/lib.rs | 282 ++++++++++++++++++++++++++++--------------------- 1 file changed, 161 insertions(+), 121 deletions(-) diff --git a/des/src/lib.rs b/des/src/lib.rs index f40f2066..c867f6f2 100755 --- a/des/src/lib.rs +++ b/des/src/lib.rs @@ -1,5 +1,4 @@ #![no_std] - extern crate block_cipher_trait; extern crate byte_tools; extern crate generic_array; @@ -7,125 +6,176 @@ extern crate generic_array; mod consts; pub use block_cipher_trait::{Block, BlockCipher, BlockCipherFixKey}; -use generic_array::{ArrayLength, GenericArray}; -use generic_array::typenum::{ - Cmp, Compare, Less, Same, - U8, U32, U48, U56, U64, U65, -}; - -use consts::{ - EXPANSION_PBOX, - INITIAL_PBOX, FINAL_PBOX, - PC1, PC2, - ROUND_PBOX, SBOXES, SHIFTS, -}; +use byte_tools::{read_u64_be, write_u64_be}; +use generic_array::GenericArray; +use generic_array::typenum::U8; + +use consts::{SBOXES, SHIFTS}; #[derive(Copy, Clone)] pub struct Des { - key: u64, + keys: [u64; 16], } -impl Des { - fn get_keys(&self) -> [u64; 16] { - let mut keys: [u64; 16] = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; - let key = self.apply_pbox::( - self.key, - GenericArray::from_slice(&PC1), - ); - - // The most significant bit is bit zero, and there are only 56 bits in - // the key after applying PC1, so we need to remove the eight least - // significant bits from the key. - let key = key >> 8; - - let mut c = key >> 28; - let mut d = key & 0x0FFFFFFF; - for i in 0..16 { - c = self.rotate(c, SHIFTS[i]); - d = self.rotate(d, SHIFTS[i]); - - // We need the `<< 8` because the most significant bit is bit zero, - // so we need to shift our 56 bit value 8 bits to the left. - keys[i] = self.apply_pbox::( - ((c << 28) | d) << 8, - GenericArray::from_slice(&PC2), - ); - } +/// Swap bits in `a` using a delta swap +fn delta_swap(a: u64, delta: u64, mask: u64) -> u64 { + let b = (a ^ (a >> delta)) & mask; + a ^ b ^ (b << delta) +} - keys - } +/// Swap bits using the PC-1 table +fn pc1(mut key: u64) -> u64 { + key = delta_swap(key, 2, 0x3333000033330000); + key = delta_swap(key, 4, 0x0f0f0f0f00000000); + key = delta_swap(key, 8, 0x009a000a00a200a8); + key = delta_swap(key, 16, 0x00006c6c0000cccc); + key = delta_swap(key, 1, 0x1045500500550550); + key = delta_swap(key, 32, 0x00000000f0f0f5fa); + key = delta_swap(key, 8, 0x00550055006a00aa); + key = delta_swap(key, 2, 0x0000333330000300); + key & 0xFFFFFFFFFFFFFF00 +} - fn do_rounds(&self, input: u64, keys: [u64; 16]) -> u64 { - let mut data = self.apply_pbox::( - input, - GenericArray::from_slice(&INITIAL_PBOX), - ); - for key in keys.iter() { - data = self.round(data, *key); - } - let l = data >> 32; - let r = data & 0x0FFFFFFF; - data = r << 32 | l; - data = self.apply_pbox::( - data, - GenericArray::from_slice(&FINAL_PBOX), - ); - data - } +/// Swap bits using the PC-2 table +fn pc2(key: u64) -> u64 { + let key = key.rotate_left(61); + let b1 = (key & 0x0021000002000000) >> 7; + let b2 = (key & 0x0008020010080000) << 1; + let b3 = key & 0x0002200000000000; + let b4 = (key & 0x0000000000100020) << 19; + let b5 = (key.rotate_left(54) & 0x0005312400000011).wrapping_mul(0x0000000094200201) & 0xea40100880000000; + let b6 = (key.rotate_left(7) & 0x0022110000012001).wrapping_mul(0x0001000000610006) & 0x1185004400000000; + let b7 = (key.rotate_left(6) & 0x0000520040200002).wrapping_mul(0x00000080000000c1) & 0x0028811000200000; + let b8 = (key & 0x01000004c0011100).wrapping_mul(0x0000000000004284) & 0x0400082244400000; + let b9 = (key.rotate_left(60) & 0x0000000000820280).wrapping_mul(0x0000000000089001) & 0x0000000110880000; + let b10 = (key.rotate_left(49) & 0x0000000000024084).wrapping_mul(0x0000000002040005) & 0x000000000a030000; + b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | b9 | b10 +} - fn round(&self, input: u64, key: u64) -> u64 { - let l = (input >> 32) << 32; - let r = (input & 0xFFFFFFFF) << 32; +/// Swap bits using the reverse FP table +fn fp(mut message: u64) -> u64 { + message = delta_swap(message, 24, 0x000000FF000000FF); + message = delta_swap(message, 24, 0x00000000FF00FF00); + message = delta_swap(message, 36, 0x000000000F0F0F0F); + message = delta_swap(message, 18, 0x0000333300003333); + delta_swap(message, 9, 0x0055005500550055) +} - r | ((self.f(r, key) ^ l) >> 32) - } +/// Swap bits using the IP table +fn ip(mut message: u64) -> u64 { + message = delta_swap(message, 9, 0x0055005500550055); + message = delta_swap(message, 18, 0x0000333300003333); + message = delta_swap(message, 36, 0x000000000F0F0F0F); + message = delta_swap(message, 24, 0x00000000FF00FF00); + delta_swap(message, 24, 0x000000FF000000FF) +} + +/// Swap bits using the E table +fn e(block: u64) -> u64 { + const BLOCK_LEN: usize = 32; + const RESULT_LEN: usize = 48; + + let b1 = (block << (BLOCK_LEN - 1)) & 0x8000000000000000; + let b2 = (block >> 1) & 0x7C00000000000000; + let b3 = (block >> 3) & 0x03F0000000000000; + let b4 = (block >> 5) & 0x000FC00000000000; + let b5 = (block >> 7) & 0x00003F0000000000; + let b6 = (block >> 9) & 0x000000FC00000000; + let b7 = (block >> 11) & 0x00000003F0000000; + let b8 = (block >> 13) & 0x000000000FC00000; + let b9 = (block >> 15) & 0x00000000003E0000; + let b10 = (block >> (RESULT_LEN - 1)) & 0x0000000000010000; + b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | b9 | b10 +} + +/// Swap bits using the P table +fn p(block: u64) -> u64 { + let block = block.rotate_left(44); + let b1 = (block & 0x0000000000200000) << 32; + let b2 = (block & 0x0000000000480000) << 13; + let b3 = (block & 0x0000088000000000) << 12; + let b4 = (block & 0x0000002020120000) << 25; + let b5 = (block & 0x0000000442000000) << 14; + let b6 = (block & 0x0000000001800000) << 37; + let b7 = (block & 0x0000000004000000) << 24; + let b8 = (block & 0x0000020280015000).wrapping_mul(0x0000020080800083) & 0x02000a6400000000; + let b9 = (block.rotate_left(29) & 0x01001400000000aa).wrapping_mul(0x0000210210008081) & 0x0902c01200000000; + let b10 = (block & 0x0000000910040000).wrapping_mul(0x0000000c04000020) & 0x8410010000000000; + b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | b9 | b10 +} - fn f(&self, input: u64, key: u64) -> u64 { - let mut val = self.apply_pbox::( - input as u64, - GenericArray::from_slice(&EXPANSION_PBOX), - ); - val ^= key; - val = self.apply_sboxes(val); - self.apply_pbox::( - val, - GenericArray::from_slice(&ROUND_PBOX), - ) +/// Generate the 16 subkeys +fn gen_keys(key: u64) -> [u64; 16] { + let mut keys: [u64; 16] = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + let key = pc1(key); + + // The most significant bit is bit zero, and there are only 56 bits in + // the key after applying PC1, so we need to remove the eight least + // significant bits from the key. + let key = key >> 8; + + let mut c = key >> 28; + let mut d = key & 0x0FFFFFFF; + for i in 0..16 { + c = rotate(c, SHIFTS[i]); + d = rotate(d, SHIFTS[i]); + + // We need the `<< 8` because the most significant bit is bit zero, + // so we need to shift our 56 bit value 8 bits to the left. + keys[i] = pc2(((c << 28) | d) << 8 ); } - /// Applies all eight sboxes to the input - fn apply_sboxes(&self, input: u64) -> u64 { - let mut output: u64 = 0; - for i in 0..8 { - let sbox = SBOXES[i]; - let val = (input >> (58 - (i * 6))) & 0x3F; - output |= (sbox[val as usize] as u64) << (60 - (i * 4)); - } - output + keys +} + +/// Performs a left rotate on a 28 bit number +fn rotate(mut val: u64, shift: u8) -> u64 { + let top_bits = val >> (28 - shift); + val <<= shift; + + (val | top_bits) & 0x0FFFFFFF +} + +fn round(input: u64, key: u64) -> u64 { + let l = (input >> 32) << 32; + let r = (input & 0xFFFFFFFF) << 32; + + r | ((f(r, key) ^ l) >> 32) +} + +fn f(input: u64, key: u64) -> u64 { + let mut val = e(input as u64); + val ^= key; + val = apply_sboxes(val); + p(val) +} + +/// Applies all eight sboxes to the input +fn apply_sboxes(input: u64) -> u64 { + let mut output: u64 = 0; + for i in 0..8 { + let sbox = SBOXES[i]; + let val = (input >> (58 - (i * 6))) & 0x3F; + output |= (sbox[val as usize] as u64) << (60 - (i * 4)); } + output +} - /// Applies the given pbox to the input - fn apply_pbox(&self, input: u64, pbox: GenericArray) -> u64 - where N: ArrayLength + Cmp, - Compare: Same, - { - let len = N::to_usize(); - let mut output = 0; - for i in 0..len { - let mask = 1 << (63 - pbox[i]); - output |= if mask & input != 0 { 1 << (63 - i) } else { 0 }; +impl Des { + fn encrypt(&self, input: u64) -> u64 { + let mut data = ip(input); + for key in self.keys.iter() { + data = round(data, *key); } - output + fp((data & 0x0FFFFFFF) << 32 | (data >> 32)) } - /// Performs a left rotate on a 28 bit number - fn rotate(&self, mut val: u64, shift: u8) -> u64 { - let top_bits = val >> (28 - shift); - val <<= shift; - - (val | top_bits) & 0x0FFFFFFF + fn decrypt(&self, input: u64) -> u64 { + let mut data = ip(input); + for key in self.keys.iter().rev() { + data = round(data, *key); + } + fp((data & 0x0FFFFFFF) << 32 | (data >> 32)) } } @@ -133,24 +183,15 @@ impl BlockCipher for Des { type BlockSize = U8; fn encrypt_block(&self, input: &Block, output: &mut Block) { - // TODO: Better way to initialize this? - let mut data = [0]; - byte_tools::read_u64v_be(&mut data, input); - - let keys = self.get_keys(); - let res = self.do_rounds(data[0], keys); - byte_tools::write_u64_be(output, res); + let block = read_u64_be(input); + let res = self.encrypt(block); + write_u64_be(output, res); } fn decrypt_block(&self, input: &Block, output: &mut Block) { - // TODO: Better way to initialize this? - let mut data = [0]; - byte_tools::read_u64v_be(&mut data, input); - - let mut keys = self.get_keys(); - keys.reverse(); - let res = self.do_rounds(data[0], keys); - byte_tools::write_u64_be(output, res); + let block = read_u64_be(input); + let res = self.decrypt(block); + write_u64_be(output, res); } } @@ -158,8 +199,7 @@ impl BlockCipherFixKey for Des { type KeySize = U8; fn new(key: &GenericArray) -> Self { - let mut key_val = [0]; - byte_tools::read_u64v_be(&mut key_val, key); - Des { key: key_val[0] } + let block = read_u64_be(key); + Des{keys: gen_keys(block)} } } From 3c415cb1e20622900c764d587c5f5d98bfc2738e Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sun, 29 Jan 2017 11:23:28 +0400 Subject: [PATCH 14/15] Removed constants which no more necessary --- des/src/consts.rs | 57 ----------------------------------------------- 1 file changed, 57 deletions(-) diff --git a/des/src/consts.rs b/des/src/consts.rs index 57ba070b..b9346f6d 100644 --- a/des/src/consts.rs +++ b/des/src/consts.rs @@ -1,62 +1,5 @@ -pub const INITIAL_PBOX: [u8; 64] = [ - 57, 49, 41, 33, 25, 17, 9, 1, - 59, 51, 43, 35, 27, 19, 11, 3, - 61, 53, 45, 37, 29, 21, 13, 5, - 63, 55, 47, 39, 31, 23, 15, 7, - 56, 48, 40, 32, 24, 16, 8, 0, - 58, 50, 42, 34, 26, 18, 10, 2, - 60, 52, 44, 36, 28, 20, 12, 4, - 62, 54, 46, 38, 30, 22, 14, 6, -]; - -pub const FINAL_PBOX: [u8; 64] = [ - 39, 7, 47, 15, 55, 23, 63, 31, - 38, 6, 46, 14, 54, 22, 62, 30, - 37, 5, 45, 13, 53, 21, 61, 29, - 36, 4, 44, 12, 52, 20, 60, 28, - 35, 3, 43, 11, 51, 19, 59, 27, - 34, 2, 42, 10, 50, 18, 58, 26, - 33, 1, 41, 9, 49, 17, 57, 25, - 32, 0, 40, 8, 48, 16, 56, 24, -]; - -pub const EXPANSION_PBOX: [u8; 48] = [ - 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, 16, 17, 18, 19, 20, 19, 20, - 21, 22, 23, 24, 23, 24, 25, 26, - 27, 28, 27, 28, 29, 30, 31, 0, -]; - -pub const ROUND_PBOX: [u8; 32] = [ - 15, 6, 19, 20, 28, 11, 27, 16, - 0, 14, 22, 25, 4, 17, 30, 9, - 1, 7, 23, 13, 31, 26, 2, 8, - 18, 12, 29, 5, 21, 10, 3, 24, -]; - pub const SHIFTS: [u8; 16] = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]; -pub const PC1: [u8; 56] = [ - 56, 48, 40, 32, 24, 16, 8, 0, - 57, 49, 41, 33, 25, 17, 9, 1, - 58, 50, 42, 34, 26, 18, 10, 2, - 59, 51, 43, 35, 62, 54, 46, 38, - 30, 22, 14, 6, 61, 53, 45, 37, - 29, 21, 13, 5, 60, 52, 44, 36, - 28, 20, 12, 4, 27, 19, 11, 3, -]; - -pub const PC2: [u8; 48] = [ - 13, 16, 10, 23, 0, 4, 2, 27, - 14, 5, 20, 9, 22, 18, 11, 3, - 25, 7, 15, 6, 26, 19, 12, 1, - 40, 51, 30, 36, 46, 54, 29, 39, - 50, 44, 32, 47, 43, 48, 38, 55, - 33, 52, 45, 41, 49, 35, 28, 31, -]; - // These boxes are not the same ones that appear in the literature. Normally, // the first and the last bits of the six input bits are used to choose the row // and the middle four bits are used to choose the column. These sboxes are From f40647b5a880c185ccf6d109b2f6b39ad7834b6e Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Sun, 29 Jan 2017 11:24:58 +0400 Subject: [PATCH 15/15] Updated copyrights --- des/LICENSE-MIT | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/des/LICENSE-MIT b/des/LICENSE-MIT index 3d35f5c6..a8984a22 100644 --- a/des/LICENSE-MIT +++ b/des/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright (c) 2017 Gulshan Singh +Copyright (c) 2017 Gulshan Singh, Antoni Boucher, Artyom Pavlov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated