From f1f522df90e4af23f442067e269463710193148d Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Tue, 9 Apr 2019 00:06:18 -0400 Subject: get this compiling again --- .rustfmt.toml | 1 + Cargo.lock | 278 +++++++++++++++++++++++++++++++------ Cargo.toml | 7 +- src/aes.rs | 97 ++++++++----- src/base64.rs | 4 +- src/crack.rs | 402 +++++++++++++++++++++++++++++++----------------------- src/data.rs | 29 +--- src/http.rs | 43 +++--- src/lib.rs | 71 +++++----- src/md4.rs | 130 ++++++++---------- src/primitives.rs | 54 ++++---- src/random.rs | 170 ++++++++++++++++------- src/sha1.rs | 109 +++++++-------- tests/set1.rs | 33 +++-- tests/set2.rs | 124 ++++++++--------- tests/set3.rs | 98 ++++++------- tests/set4.rs | 112 ++++++++------- tests/util.rs | 30 ++-- 18 files changed, 1066 insertions(+), 726 deletions(-) create mode 100644 .rustfmt.toml diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..bcad605 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1 @@ +max_width = 78 diff --git a/Cargo.lock b/Cargo.lock index 4060adf..7c7f6da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,103 +1,301 @@ -[root] -name = "matasano" -version = "0.0.1" +[[package]] +name = "autocfg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cc" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "openssl 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "bitflags" +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "foreign-types-shared" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "gcc" -version = "0.3.5" +name = "fuchsia-cprng" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "0.1.10" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.1.7" +version = "0.2.51" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "libressl-pnacl-sys" -version = "2.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" +name = "matasano" +version = "0.0.1" dependencies = [ - "pnacl-build-helper 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.10.20 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "openssl" -version = "0.6.2" +version = "0.10.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "openssl-sys" -version = "0.6.2" +version = "0.9.43" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libressl-pnacl-sys 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pkg-config" -version = "0.3.4" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "pnacl-build-helper" -version = "1.4.0" +name = "rand" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "tempdir 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rand" -version = "0.3.8" +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_jitter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "redox_syscall" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rustc-serialize" -version = "0.3.14" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "tempdir" -version = "0.3.4" +name = "rustc_version" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "time" -version = "0.1.25" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "vcpkg" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" +"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83" +"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" +"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917" +"checksum openssl 0.10.20 (registry+https://github.com/rust-lang/crates.io-index)" = "5a0d6b781aac4ac1bd6cafe2a2f0ad8c16ae8e1dd5184822a16c50139f8838d9" +"checksum openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)" = "33c86834957dd5b915623e94f2f4ab2c70dd8f6b70679824155d5ae21dbd495d" +"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" +"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832" +"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" +"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d" +"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index f18ef09..9246928 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,8 @@ name = "matasano" version = "0.0.1" authors = ["Jesse Luehrs "] +edition = "2018" +autotests = false [[test]] name = "set1" @@ -21,6 +23,7 @@ path = "tests/set4.rs" [dependencies] rustc-serialize = "0.3" -openssl = "0.6" -rand = "0.3" +openssl = "0.10" +rand = "0.6" +rand_core = "0.4" time = "0.1" diff --git a/src/aes.rs b/src/aes.rs index ffd40d9..5dad753 100644 --- a/src/aes.rs +++ b/src/aes.rs @@ -1,24 +1,42 @@ -use primitives::{fixed_xor, pad_pkcs7, unpad_pkcs7}; +use crate::primitives::{fixed_xor, pad_pkcs7, unpad_pkcs7}; -pub fn decrypt_aes_128_ecb (bytes: &[u8], key: &[u8]) -> Option> { - // openssl already doesn't return differentiable results for invalid - // padding, so we can't either - return Some(::openssl::crypto::symm::decrypt( - ::openssl::crypto::symm::Type::AES_128_ECB, +fn decrypt_aes_128_ecb_nopad(bytes: &[u8], key: &[u8]) -> Vec { + let t = openssl::symm::Cipher::aes_128_ecb(); + let mut c = openssl::symm::Crypter::new( + t, + openssl::symm::Mode::Decrypt, key, - vec![], - bytes - )); + None, + ) + .unwrap(); + c.pad(false); + let mut out = vec![0; bytes.len() + t.block_size()]; + let count = c.update(bytes, &mut out).unwrap(); + let rest = c.finalize(&mut out[count..]).unwrap(); + out.truncate(count + rest); + out +} + +pub fn decrypt_aes_128_ecb(bytes: &[u8], key: &[u8]) -> Vec { + return openssl::symm::decrypt( + openssl::symm::Cipher::aes_128_ecb(), + key, + None, + bytes, + ) + .unwrap(); } -pub fn decrypt_aes_128_cbc (bytes: &[u8], key: &[u8], iv: &[u8]) -> Option> { +pub fn decrypt_aes_128_cbc( + bytes: &[u8], + key: &[u8], + iv: &[u8], +) -> Option> { let mut prev = iv.clone(); let mut plaintext = vec![]; for block in bytes.chunks(16) { - let plaintext_block = fixed_xor( - &decrypt_aes_128_ecb(&pad_pkcs7(block, 16)[..], key).unwrap()[..], - prev - ); + let plaintext_block = + fixed_xor(&decrypt_aes_128_ecb_nopad(&block, key)[..], prev); for c in plaintext_block { plaintext.push(c); } @@ -27,21 +45,23 @@ pub fn decrypt_aes_128_cbc (bytes: &[u8], key: &[u8], iv: &[u8]) -> Option Vec { - return ::openssl::crypto::symm::encrypt( - ::openssl::crypto::symm::Type::AES_128_ECB, +pub fn encrypt_aes_128_ecb(bytes: &[u8], key: &[u8]) -> Vec { + return openssl::symm::encrypt( + openssl::symm::Cipher::aes_128_ecb(), key, - vec![], - bytes + None, + bytes, ) + .unwrap(); } -pub fn encrypt_aes_128_cbc (bytes: &[u8], key: &[u8], iv: &[u8]) -> Vec { +pub fn encrypt_aes_128_cbc(bytes: &[u8], key: &[u8], iv: &[u8]) -> Vec { let mut prev = iv.to_vec(); let mut ciphertext = vec![]; for block in pad_pkcs7(bytes, 16).chunks(16) { let plaintext_block = fixed_xor(&block[..], &prev[..]); - let mut ciphertext_block = encrypt_aes_128_ecb(&plaintext_block[..], key); + let mut ciphertext_block = + encrypt_aes_128_ecb(&plaintext_block[..], key); ciphertext_block.truncate(16); for &c in ciphertext_block.iter() { ciphertext.push(c); @@ -51,20 +71,22 @@ pub fn encrypt_aes_128_cbc (bytes: &[u8], key: &[u8], iv: &[u8]) -> Vec { return ciphertext; } -pub fn aes_128_ctr (bytes: &[u8], key: &[u8], nonce: u64) -> Vec { +pub fn aes_128_ctr(bytes: &[u8], key: &[u8], nonce: u64) -> Vec { aes_128_ctr_with_counter(bytes, key, nonce, 0) } -pub fn aes_128_ctr_with_counter (bytes: &[u8], key: &[u8], nonce: u64, counter_start: u64) -> Vec { - let nonce_array: [u8; 8] = unsafe { - ::std::mem::transmute(nonce.to_le()) - }; +pub fn aes_128_ctr_with_counter( + bytes: &[u8], + key: &[u8], + nonce: u64, + counter_start: u64, +) -> Vec { + let nonce_array: [u8; 8] = unsafe { std::mem::transmute(nonce.to_le()) }; let mut counter = counter_start; let mut ret = vec![]; for block in bytes.chunks(16) { - let counter_array: [u8; 8] = unsafe { - ::std::mem::transmute(counter.to_le()) - }; + let counter_array: [u8; 8] = + unsafe { std::mem::transmute(counter.to_le()) }; let keystream = encrypt_aes_128_ecb( &pad_pkcs7( &nonce_array @@ -72,9 +94,9 @@ pub fn aes_128_ctr_with_counter (bytes: &[u8], key: &[u8], nonce: u64, counter_s .chain(counter_array.iter()) .map(|x| *x) .collect::>()[..], - 16 + 16, )[..], - key + key, ); for c in fixed_xor(block, &keystream[..]) { ret.push(c); @@ -85,7 +107,7 @@ pub fn aes_128_ctr_with_counter (bytes: &[u8], key: &[u8], nonce: u64, counter_s } #[test] -fn test_encrypt_decrypt () { +fn test_encrypt_decrypt() { let plaintext = b"Summertime and the wind is blowing outside in lower \ Chelsea and I don't know what I'm doing in the city, the \ sun is always in my eyes"; @@ -93,13 +115,16 @@ fn test_encrypt_decrypt () { let iv = [0; 16]; let ciphertext_ecb = encrypt_aes_128_ecb(&plaintext[..], &key[..]); - let ciphertext_cbc = encrypt_aes_128_cbc(&plaintext[..], &key[..], &iv[..]); + let ciphertext_cbc = + encrypt_aes_128_cbc(&plaintext[..], &key[..], &iv[..]); - let plaintext2_ecb = decrypt_aes_128_ecb(&ciphertext_ecb[..], &key[..]).unwrap(); - let plaintext2_cbc = decrypt_aes_128_cbc(&ciphertext_cbc[..], &key[..], &iv[..]).unwrap(); + let plaintext2_ecb = decrypt_aes_128_ecb(&ciphertext_ecb[..], &key[..]); + let plaintext2_cbc = + decrypt_aes_128_cbc(&ciphertext_cbc[..], &key[..], &iv[..]).unwrap(); let ciphertext2_ecb = encrypt_aes_128_ecb(&plaintext2_ecb[..], &key[..]); - let ciphertext2_cbc = encrypt_aes_128_cbc(&plaintext2_cbc[..], &key[..], &iv[..]); + let ciphertext2_cbc = + encrypt_aes_128_cbc(&plaintext2_cbc[..], &key[..], &iv[..]); assert_eq!(&plaintext[..], &plaintext2_ecb[..]); assert_eq!(&plaintext[..], &plaintext2_cbc[..]); diff --git a/src/base64.rs b/src/base64.rs index cc0f787..9b01da8 100644 --- a/src/base64.rs +++ b/src/base64.rs @@ -1,5 +1,5 @@ -use serialize::base64::{ToBase64, STANDARD}; +use rustc_serialize::base64::{ToBase64, STANDARD}; -pub fn to_base64 (bytes: &[u8]) -> String { +pub fn to_base64(bytes: &[u8]) -> String { return bytes.to_base64(STANDARD); } diff --git a/src/crack.rs b/src/crack.rs index acc059b..9d56980 100644 --- a/src/crack.rs +++ b/src/crack.rs @@ -1,20 +1,19 @@ -use std::ascii::AsciiExt; +use rand::Rng; use std::borrow::ToOwned; use std::collections::{HashMap, HashSet}; -use rand::{Rng, SeedableRng}; -use aes::encrypt_aes_128_cbc; -use data::ENGLISH_FREQUENCIES; -use primitives::{fixed_xor, unpad_pkcs7, hamming, repeating_key_xor}; -use random::MersenneTwister; +use crate::aes::encrypt_aes_128_cbc; +use crate::data::ENGLISH_FREQUENCIES; +use crate::primitives::{fixed_xor, hamming, repeating_key_xor, unpad_pkcs7}; +use crate::random::MersenneTwister; -#[derive(PartialEq,Eq,Debug)] +#[derive(PartialEq, Eq, Debug)] pub enum BlockCipherMode { ECB, CBC, } -pub fn find_single_byte_xor_encrypted_string (inputs: &[Vec]) -> Vec { +pub fn find_single_byte_xor_encrypted_string(inputs: &[Vec]) -> Vec { let mut min_diff = 100.0; let mut best_decrypted = vec![]; for input in inputs { @@ -27,44 +26,40 @@ pub fn find_single_byte_xor_encrypted_string (inputs: &[Vec]) -> Vec { return best_decrypted; } -pub fn crack_single_byte_xor (input: &[u8]) -> Vec { +pub fn crack_single_byte_xor(input: &[u8]) -> Vec { let (key, _) = crack_single_byte_xor_with_confidence(input); return repeating_key_xor(input, &[key]); } -pub fn crack_repeating_key_xor (input: &[u8]) -> Vec { +pub fn crack_repeating_key_xor(input: &[u8]) -> Vec { let mut keysizes = vec![]; for keysize in 2..40 { let distance1 = hamming( &input[(keysize * 0)..(keysize * 1)], - &input[(keysize * 1)..(keysize * 2)] + &input[(keysize * 1)..(keysize * 2)], ) as f64; let distance2 = hamming( &input[(keysize * 1)..(keysize * 2)], - &input[(keysize * 2)..(keysize * 3)] + &input[(keysize * 2)..(keysize * 3)], ) as f64; let distance3 = hamming( &input[(keysize * 2)..(keysize * 3)], - &input[(keysize * 3)..(keysize * 4)] + &input[(keysize * 3)..(keysize * 4)], ) as f64; let distance = distance1 + distance2 + distance3 / 3.0; let normal_distance = distance / (keysize as f64); keysizes.push((keysize, normal_distance)); if keysizes.len() > 5 { - let (idx, _) = keysizes - .iter() - .enumerate() - .fold( - (0, (0, 0.0)), - |(accidx, (accsize, accdist)), (idx, &(size, dist))| { - if dist > accdist { - (idx, (size, dist)) - } - else { - (accidx, (accsize, accdist)) - } + let (idx, _) = keysizes.iter().enumerate().fold( + (0, (0, 0.0)), + |(accidx, (accsize, accdist)), (idx, &(size, dist))| { + if dist > accdist { + (idx, (size, dist)) + } else { + (accidx, (accsize, accdist)) } - ); + }, + ); keysizes.swap_remove(idx); } } @@ -72,7 +67,8 @@ pub fn crack_repeating_key_xor (input: &[u8]) -> Vec { let mut min_diff = 100.0; let mut best_key = vec![]; for (keysize, _) in keysizes { - let (key, diff) = crack_repeating_key_xor_with_keysize(input, keysize); + let (key, diff) = + crack_repeating_key_xor_with_keysize(input, keysize); if diff < min_diff { min_diff = diff; best_key = key; @@ -82,7 +78,7 @@ pub fn crack_repeating_key_xor (input: &[u8]) -> Vec { return best_key; } -pub fn find_aes_128_ecb_encrypted_string (inputs: &[Vec]) -> Vec { +pub fn find_aes_128_ecb_encrypted_string(inputs: &[Vec]) -> Vec { let mut max_dups = 0; let mut found = vec![]; for input in inputs { @@ -95,27 +91,32 @@ pub fn find_aes_128_ecb_encrypted_string (inputs: &[Vec]) -> Vec { return found; } -pub fn detect_ecb_cbc (f: &F, block_size: usize) -> BlockCipherMode where F: Fn(&[u8]) -> Vec { - if block_size >= ::std::u8::MAX as usize { +pub fn detect_ecb_cbc(f: &F, block_size: usize) -> BlockCipherMode +where + F: Fn(&[u8]) -> Vec, +{ + if block_size >= std::u8::MAX as usize { panic!("invalid block size: {}", block_size); } let block_size_byte = block_size as u8; let plaintext: Vec = (0..block_size_byte) .cycle() .take(block_size * 2) - .flat_map(|n| ::std::iter::repeat(n).take(block_size + 1)) + .flat_map(|n| std::iter::repeat(n).take(block_size + 1)) .collect(); let ciphertext = f(&plaintext[..]); if count_duplicate_blocks(&ciphertext[..], block_size) >= block_size { return BlockCipherMode::ECB; - } - else { + } else { return BlockCipherMode::CBC; } } -pub fn crack_padded_aes_128_ecb (f: &F) -> Vec where F: Fn(&[u8]) -> Vec { +pub fn crack_padded_aes_128_ecb(f: &F) -> Vec +where + F: Fn(&[u8]) -> Vec, +{ let block_size = find_block_size(f); if detect_ecb_cbc(f, block_size) != BlockCipherMode::ECB { panic!("Can only crack ECB-encrypted data"); @@ -135,7 +136,7 @@ pub fn crack_padded_aes_128_ecb (f: &F) -> Vec where F: Fn(&[u8]) -> Vec< loop { let mut map = HashMap::new(); - let prefix: Vec = ::std::iter::repeat(b'A') + let prefix: Vec = std::iter::repeat(b'A') .take(block_size - ((i % block_size) + 1)) .collect(); for c in 0..256 { @@ -150,22 +151,26 @@ pub fn crack_padded_aes_128_ecb (f: &F) -> Vec where F: Fn(&[u8]) -> Vec< let next_char = map.get(&get_block(&prefix[..], i)); if next_char.is_some() { plaintext.push(*next_char.unwrap()); - } - else { + } else { break; } i += 1; } - return unpad_pkcs7(&plaintext[..]).expect("invalid padding").to_vec(); + return unpad_pkcs7(&plaintext[..]) + .expect("invalid padding") + .to_vec(); } -pub fn crack_padded_aes_128_ecb_with_prefix (f: &F) -> Vec where F: Fn(&[u8]) -> Vec { +pub fn crack_padded_aes_128_ecb_with_prefix(f: &F) -> Vec +where + F: Fn(&[u8]) -> Vec, +{ let (block_size, prefix_len) = find_block_size_and_fixed_prefix_len(f); let wrapped_f = |input: &[u8]| { let alignment_padding = block_size - (prefix_len % block_size); - let padded_input: Vec = ::std::iter::repeat(b'A') + let padded_input: Vec = std::iter::repeat(b'A') .take(alignment_padding) .chain(input.iter().map(|x| *x)) .collect(); @@ -178,8 +183,13 @@ pub fn crack_padded_aes_128_ecb_with_prefix (f: &F) -> Vec where F: Fn(&[ return crack_padded_aes_128_ecb(&wrapped_f); } -pub fn crack_querystring_aes_128_ecb (encrypter: &F) -> (String, Vec>) where F: Fn(&str) -> Vec { - fn incr_map_element (map: &mut HashMap, usize>, key: Vec) { +pub fn crack_querystring_aes_128_ecb( + encrypter: &F, +) -> (String, Vec>) +where + F: Fn(&str) -> Vec, +{ + fn incr_map_element(map: &mut HashMap, usize>, key: Vec) { if let Some(val) = map.get_mut(&key) { *val += 1; return; @@ -191,8 +201,8 @@ pub fn crack_querystring_aes_128_ecb (encrypter: &F) -> (String, Vec> let find_uid_role_blocks = || { let mut map = HashMap::new(); for c in 32..127 { - let email_bytes: Vec = ::std::iter::repeat(c).take(9).collect(); - let email = ::std::str::from_utf8(&email_bytes[..]).unwrap(); + let email_bytes: Vec = std::iter::repeat(c).take(9).collect(); + let email = std::str::from_utf8(&email_bytes[..]).unwrap(); let ciphertext = encrypter(email); incr_map_element(&mut map, ciphertext[..16].to_vec()); incr_map_element(&mut map, ciphertext[16..32].to_vec()); @@ -202,20 +212,16 @@ pub fn crack_querystring_aes_128_ecb (encrypter: &F) -> (String, Vec> for (k, v) in map { most_common_blocks.push((k, v)); if most_common_blocks.len() > 2 { - let (idx, _) = most_common_blocks - .iter() - .enumerate() - .fold( - (0, (vec![], 10000)), - |(aidx, (ablock, acount)), (idx, &(ref block, count))| { - if count < acount { - (idx, (block.clone(), count)) - } - else { - (aidx, (ablock.clone(), acount)) - } + let (idx, _) = most_common_blocks.iter().enumerate().fold( + (0, (vec![], 10000)), + |(aidx, (ablock, acount)), (idx, &(ref block, count))| { + if count < acount { + (idx, (block.clone(), count)) + } else { + (aidx, (ablock.clone(), acount)) } - ); + }, + ); most_common_blocks.swap_remove(idx); } } @@ -224,8 +230,7 @@ pub fn crack_querystring_aes_128_ecb (encrypter: &F) -> (String, Vec> let (ref block1, _) = most_common_blocks[0]; let (ref block2, _) = most_common_blocks[1]; return (block1.clone(), block2.clone()); - } - else { + } else { panic!("couldn't find most common blocks"); } }; @@ -234,9 +239,12 @@ pub fn crack_querystring_aes_128_ecb (encrypter: &F) -> (String, Vec> // email=..........admin...............&uid=10&role=user let calculate_admin_block = |block1: Vec, block2: Vec| { for _ in 0..1000 { - let email = "blorg@bar.admin\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b..............."; + let email = + "blorg@bar.admin\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b..............."; let ciphertext = encrypter(email); - if &ciphertext[48..64] == &block1[..] || &ciphertext[48..64] == &block2[..] { + if &ciphertext[48..64] == &block1[..] + || &ciphertext[48..64] == &block2[..] + { return ciphertext[16..32].to_vec(); } } @@ -256,7 +264,10 @@ pub fn crack_querystring_aes_128_ecb (encrypter: &F) -> (String, Vec> .chain(admin_block.iter()) .map(|x| *x) .collect(); - if !possibles.iter().any(|possible| possible == &modified_ciphertext) { + if !possibles + .iter() + .any(|possible| possible == &modified_ciphertext) + { possibles.push(modified_ciphertext); } } @@ -268,7 +279,10 @@ pub fn crack_querystring_aes_128_ecb (encrypter: &F) -> (String, Vec> return calculate_possible_admin_ciphertexts(admin_block); } -pub fn crack_cbc_bitflipping (f: &F) -> Vec where F: Fn(&str) -> Vec { +pub fn crack_cbc_bitflipping(f: &F) -> Vec +where + F: Fn(&str) -> Vec, +{ let mut ciphertext = f("AAAAAAAAAAAAAAAA:admin (f: &F) -> Vec where F: Fn(&str) -> Vec return ciphertext; } -pub fn crack_cbc_padding_oracle (iv: &[u8], ciphertext: &[u8], f: &F) -> Vec where F: Fn(&[u8], &[u8]) -> bool { +pub fn crack_cbc_padding_oracle( + iv: &[u8], + ciphertext: &[u8], + f: &F, +) -> Vec +where + F: Fn(&[u8], &[u8]) -> bool, +{ let mut prev = iv; let mut plaintext = vec![]; for block in ciphertext.chunks(16) { @@ -285,14 +306,15 @@ pub fn crack_cbc_padding_oracle (iv: &[u8], ciphertext: &[u8], f: &F) -> Vec< for c_int in 0..256 { let c = (255 - c_int) as u8; let offset = (16 - byte - 1) as usize; - let mut iv: Vec = prev - .iter() - .take(offset) - .map(|x| *x) - .collect(); + let mut iv: Vec = + prev.iter().take(offset).map(|x| *x).collect(); iv.push(prev[offset] ^ c ^ (byte + 1)); for i in 0..(byte as usize) { - iv.push(prev[offset + i + 1] ^ plaintext_block[i] ^ (byte + 1)); + iv.push( + prev[offset + i + 1] + ^ plaintext_block[i] + ^ (byte + 1), + ); } if f(&iv[..], block) { plaintext_block.insert(0, c); @@ -309,7 +331,9 @@ pub fn crack_cbc_padding_oracle (iv: &[u8], ciphertext: &[u8], f: &F) -> Vec< return unpad_pkcs7(&plaintext[..]).unwrap().to_vec(); } -pub fn crack_fixed_nonce_ctr_statistically (input: Vec>) -> Vec> { +pub fn crack_fixed_nonce_ctr_statistically( + input: Vec>, +) -> Vec> { let min_len = input.iter().map(|line| line.len()).min().unwrap(); let max_len = input.iter().map(|line| line.len()).max().unwrap(); @@ -328,8 +352,7 @@ pub fn crack_fixed_nonce_ctr_statistically (input: Vec>) -> Vec> if line.len() >= len { idxs.push(idx); true - } - else { + } else { false } }) @@ -337,10 +360,8 @@ pub fn crack_fixed_nonce_ctr_statistically (input: Vec>) -> Vec> .map(|x| *x) .collect(); - let (key, _) = crack_repeating_key_xor_with_keysize( - &ciphertext[..], - len - ); + let (key, _) = + crack_repeating_key_xor_with_keysize(&ciphertext[..], len); for i in full_key.len()..key.len() { full_key.push(key[i]) } @@ -358,11 +379,11 @@ pub fn crack_fixed_nonce_ctr_statistically (input: Vec>) -> Vec> return plaintext_lines; } -pub fn recover_mersenne_twister_seed_from_time (output: u32) -> Option { - let now = ::time::now().to_timespec().sec as u32; +pub fn recover_mersenne_twister_seed_from_time(output: u32) -> Option { + let now = time::now().to_timespec().sec as u32; for i in -10000..10000i32 { let seed = (now as i32).wrapping_add(i) as u32; - let mut mt = MersenneTwister::from_seed(seed); + let mut mt = MersenneTwister::from_u32(seed); let test_output: u32 = mt.gen(); if test_output == output { return Some(seed); @@ -371,9 +392,14 @@ pub fn recover_mersenne_twister_seed_from_time (output: u32) -> Option { return None; } -pub fn clone_mersenne_twister_from_output (outputs: &[u32]) -> MersenneTwister { - fn untemper (val: u32) -> u32 { - fn unxorshift (f: F, mut y: u32, n: usize, mask: u32) -> u32 where F: Fn(u32, usize) -> u32 { +pub fn clone_mersenne_twister_from_output( + outputs: &[u32], +) -> MersenneTwister { + fn untemper(val: u32) -> u32 { + fn unxorshift(f: F, mut y: u32, n: usize, mask: u32) -> u32 + where + F: Fn(u32, usize) -> u32, + { let mut a = y; for _ in 0..(32 / n) { y = f(y, n) & mask; @@ -384,10 +410,10 @@ pub fn clone_mersenne_twister_from_output (outputs: &[u32]) -> MersenneTwister { let mut y = val; - y = unxorshift(|a, n| {a >> n}, y, 18, 0xffffffff); - y = unxorshift(|a, n| {a << n}, y, 15, 0xefc60000); - y = unxorshift(|a, n| {a << n}, y, 7, 0x9d2c5680); - y = unxorshift(|a, n| {a >> n}, y, 11, 0xffffffff); + y = unxorshift(|a, n| a >> n, y, 18, 0xffffffff); + y = unxorshift(|a, n| a << n, y, 15, 0xefc60000); + y = unxorshift(|a, n| a << n, y, 7, 0x9d2c5680); + y = unxorshift(|a, n| a >> n, y, 11, 0xffffffff); y } @@ -397,16 +423,17 @@ pub fn clone_mersenne_twister_from_output (outputs: &[u32]) -> MersenneTwister { state[i] = untemper(output); } - return MersenneTwister::from_seed((state, 0)); + return MersenneTwister::from_state(state, 0); } -pub fn recover_16_bit_mt19937_key (ciphertext: &[u8], suffix: &[u8]) -> Option { +pub fn recover_16_bit_mt19937_key( + ciphertext: &[u8], + suffix: &[u8], +) -> Option { for _key in 0..65536u32 { let key = _key as u16; - let plaintext = ::random::mt19937_stream_cipher( - ciphertext, - key as u32 - ); + let plaintext = + crate::random::mt19937_stream_cipher(ciphertext, key as u32); if &plaintext[(ciphertext.len() - suffix.len())..] == suffix { return Some(key); } @@ -415,12 +442,15 @@ pub fn recover_16_bit_mt19937_key (ciphertext: &[u8], suffix: &[u8]) -> Option Option { - let now = ::time::now().to_timespec().sec as u32; +pub fn recover_mt19937_key_from_time(token: &[u8]) -> Option { + let now = time::now().to_timespec().sec as u32; for i in -500..500i32 { let seed = (now as i32).wrapping_add(i) as u32; - let mut mt = MersenneTwister::from_seed(seed); - let test_token: Vec = mt.gen_iter().take(16).collect(); + let mut mt = MersenneTwister::from_u32(seed); + let test_token: Vec = mt + .sample_iter(&rand::distributions::Standard) + .take(16) + .collect(); if &test_token[..] == token { return Some(seed); } @@ -428,15 +458,23 @@ pub fn recover_mt19937_key_from_time (token: &[u8]) -> Option { return None; } -pub fn crack_aes_128_ctr_random_access (ciphertext: &[u8], edit: F) -> Vec where F: Fn(&[u8], usize, &[u8]) -> Vec { - let empty_plaintext: Vec = ::std::iter::repeat(b'\x00') - .take(ciphertext.len()) - .collect(); +pub fn crack_aes_128_ctr_random_access( + ciphertext: &[u8], + edit: F, +) -> Vec +where + F: Fn(&[u8], usize, &[u8]) -> Vec, +{ + let empty_plaintext: Vec = + std::iter::repeat(b'\x00').take(ciphertext.len()).collect(); let keystream = edit(ciphertext, 0, &empty_plaintext[..]); return fixed_xor(&keystream[..], ciphertext); } -pub fn crack_ctr_bitflipping (f: &F) -> Vec where F: Fn(&str) -> Vec { +pub fn crack_ctr_bitflipping(f: &F) -> Vec +where + F: Fn(&str) -> Vec, +{ let ciphertext = f("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"); let replacement = fixed_xor(&ciphertext[32..44], b";admin=true;"); return ciphertext[..32] @@ -447,14 +485,18 @@ pub fn crack_ctr_bitflipping (f: &F) -> Vec where F: Fn(&str) -> Vec .collect(); } -pub fn crack_cbc_iv_key (encrypt: &F1, verify: &F2) -> Vec where F1: Fn(&str) -> Vec, F2: Fn(&[u8]) -> Result> { +pub fn crack_cbc_iv_key(encrypt: &F1, verify: &F2) -> Vec +where + F1: Fn(&str) -> Vec, + F2: Fn(&[u8]) -> Result>, +{ loop { - let plaintext_bytes: Vec = ::rand::thread_rng() - .gen_iter() + let plaintext_bytes: Vec = rand::thread_rng() + .sample_iter(&rand::distributions::Standard) .filter(|&c| c >= 32 && c < 127) - .take(16*5) + .take(16 * 5) .collect(); - let plaintext = ::std::str::from_utf8(&plaintext_bytes).unwrap(); + let plaintext = std::str::from_utf8(&plaintext_bytes).unwrap(); let ciphertext = encrypt(plaintext); let modified_ciphertext: Vec = ciphertext[..16] .iter() @@ -466,7 +508,7 @@ pub fn crack_cbc_iv_key (encrypt: &F1, verify: &F2) -> Vec where F1: if let Err(modified_plaintext) = verify(&modified_ciphertext[..]) { let key = fixed_xor( &modified_plaintext[..16], - &modified_plaintext[32..48] + &modified_plaintext[32..48], ); let desired_plaintext = b"comment1=cooking%20MCs;userdata=;admin=true;comment2=%20like%20a%20pound%20of%20bacon"; return encrypt_aes_128_cbc(desired_plaintext, &key[..], &key[..]); @@ -474,51 +516,65 @@ pub fn crack_cbc_iv_key (encrypt: &F1, verify: &F2) -> Vec where F1: } } -pub fn crack_sha1_mac_length_extension (input: &[u8], mac: [u8; 20], extension: &[u8]) -> Vec<(Vec, [u8; 20])> { - let mut sha1_state: [u32; 5] = unsafe { ::std::mem::transmute(mac) }; +pub fn crack_sha1_mac_length_extension( + input: &[u8], + mac: [u8; 20], + extension: &[u8], +) -> Vec<(Vec, [u8; 20])> { + let mut sha1_state: [u32; 5] = unsafe { std::mem::transmute(mac) }; for word in sha1_state.iter_mut() { *word = u32::from_be(*word); } - (0..100).map(|i| { - let new_input: Vec = input - .iter() - .chain(::sha1::sha1_padding(i + input.len() as u64).iter()) - .chain(extension.iter()) - .map(|x| *x) - .collect(); - let new_hash = ::sha1::sha1_with_state( - extension, - sha1_state, - i + new_input.len() as u64 - ); - (new_input, new_hash) - }).collect() + (0..100) + .map(|i| { + let new_input: Vec = input + .iter() + .chain( + crate::sha1::sha1_padding(i + input.len() as u64).iter(), + ) + .chain(extension.iter()) + .map(|x| *x) + .collect(); + let new_hash = crate::sha1::sha1_with_state( + extension, + sha1_state, + i + new_input.len() as u64, + ); + (new_input, new_hash) + }) + .collect() } -pub fn crack_md4_mac_length_extension (input: &[u8], mac: [u8; 16], extension: &[u8]) -> Vec<(Vec, [u8; 16])> { - let mut md4_state: [u32; 4] = unsafe { ::std::mem::transmute(mac) }; +pub fn crack_md4_mac_length_extension( + input: &[u8], + mac: [u8; 16], + extension: &[u8], +) -> Vec<(Vec, [u8; 16])> { + let mut md4_state: [u32; 4] = unsafe { std::mem::transmute(mac) }; for word in md4_state.iter_mut() { *word = u32::from_le(*word); } - (0..100).map(|i| { - let new_input: Vec = input - .iter() - .chain(::md4::md4_padding(i + input.len() as u64).iter()) - .chain(extension.iter()) - .map(|x| *x) - .collect(); - let new_hash = ::md4::md4_with_state( - extension, - md4_state, - i + new_input.len() as u64 - ); - (new_input, new_hash) - }).collect() + (0..100) + .map(|i| { + let new_input: Vec = input + .iter() + .chain(crate::md4::md4_padding(i + input.len() as u64).iter()) + .chain(extension.iter()) + .map(|x| *x) + .collect(); + let new_hash = crate::md4::md4_with_state( + extension, + md4_state, + i + new_input.len() as u64, + ); + (new_input, new_hash) + }) + .collect() } -fn crack_single_byte_xor_with_confidence (input: &[u8]) -> (u8, f64) { +fn crack_single_byte_xor_with_confidence(input: &[u8]) -> (u8, f64) { let mut min_diff = 100.0; let mut best_key = 0; for a in 0..256u16 { @@ -526,12 +582,15 @@ fn crack_single_byte_xor_with_confidence (input: &[u8]) -> (u8, f64) { input, &::std::iter::repeat(a as u8) .take(input.len()) - .collect::>()[..] + .collect::>()[..], ); if !decrypted.is_ascii() { continue; } - if decrypted.iter().any(|&c| c != b'\n' && (c < 0x20 || c > 0x7E)) { + if decrypted + .iter() + .any(|&c| c != b'\n' && (c < 0x20 || c > 0x7E)) + { continue; } let lowercase = decrypted.to_ascii_lowercase(); @@ -542,15 +601,17 @@ fn crack_single_byte_xor_with_confidence (input: &[u8]) -> (u8, f64) { total_frequency += 1; if c >= 0x61 && c <= 0x7A { frequencies[(c - 0x61) as usize] += 1; - } - else { + } else { extra_frequencies += 1; } } let mut total_diff = 0.0; - for (&english, &crypt) in ENGLISH_FREQUENCIES.iter().zip(frequencies.iter()) { - let relative_frequency = (crypt as f64) / (total_frequency as f64); + for (&english, &crypt) in + ENGLISH_FREQUENCIES.iter().zip(frequencies.iter()) + { + let relative_frequency = + (crypt as f64) / (total_frequency as f64); total_diff += (english - relative_frequency).abs(); } total_diff += (extra_frequencies as f64) / (total_frequency as f64); @@ -564,7 +625,10 @@ fn crack_single_byte_xor_with_confidence (input: &[u8]) -> (u8, f64) { return (best_key, min_diff); } -fn crack_repeating_key_xor_with_keysize (input: &[u8], keysize: usize) -> (Vec, f64) { +fn crack_repeating_key_xor_with_keysize( + input: &[u8], + keysize: usize, +) -> (Vec, f64) { let strides: Vec> = (0..keysize) .map(|n| { // XXX sigh ): @@ -585,14 +649,11 @@ fn crack_repeating_key_xor_with_keysize (input: &[u8], keysize: usize) -> (Vec usize { +fn count_duplicate_blocks(input: &[u8], block_size: usize) -> usize { let mut set = HashSet::new(); let mut dups = 0; for block in input.chunks(block_size) { @@ -603,26 +664,27 @@ fn count_duplicate_blocks (input: &[u8], block_size: usize) -> usize { return dups; } -fn find_block_size (f: &F) -> usize where F: Fn(&[u8]) -> Vec { +fn find_block_size(f: &F) -> usize +where + F: Fn(&[u8]) -> Vec, +{ let (block_size, _) = find_block_size_and_fixed_prefix_len(f); return block_size; } -fn find_block_size_and_fixed_prefix_len (f: &F) -> (usize, usize) where F: Fn(&[u8]) -> Vec { +fn find_block_size_and_fixed_prefix_len(f: &F) -> (usize, usize) +where + F: Fn(&[u8]) -> Vec, +{ let fixed_prefix_len = find_fixed_block_prefix_len(f); let byte = b'A'; let mut prev = f(&[b'f']); let mut len = 0; loop { - let prefix: Vec = ::std::iter::repeat(byte) - .take(len) - .collect(); + let prefix: Vec = std::iter::repeat(byte).take(len).collect(); let next = f(&prefix[..]); - let prefix_len = shared_prefix_len( - prev.iter(), - next.iter() - ); + let prefix_len = shared_prefix_len(prev.iter(), next.iter()); if prefix_len > fixed_prefix_len { let block_size = prefix_len - fixed_prefix_len; return (block_size, fixed_prefix_len + block_size - (len - 1)); @@ -633,15 +695,19 @@ fn find_block_size_and_fixed_prefix_len (f: &F) -> (usize, usize) where F: Fn } } -fn find_fixed_block_prefix_len (f: &F) -> usize where F: Fn(&[u8]) -> Vec { +fn find_fixed_block_prefix_len(f: &F) -> usize +where + F: Fn(&[u8]) -> Vec, +{ let ciphertext1 = f(b""); let ciphertext2 = f(b"A"); return shared_prefix_len(ciphertext1.iter(), ciphertext2.iter()); } -fn shared_prefix_len (i1: I, i2: I) -> usize where I: Iterator, ::Item: PartialEq { - return i1 - .zip(i2) - .take_while(|&(ref c1, ref c2)| { c1 == c2 }) - .count(); +fn shared_prefix_len(i1: I, i2: I) -> usize +where + I: Iterator, + ::Item: PartialEq, +{ + return i1.zip(i2).take_while(|&(ref c1, ref c2)| c1 == c2).count(); } diff --git a/src/data.rs b/src/data.rs index 6fb0272..0e8f9ae 100644 --- a/src/data.rs +++ b/src/data.rs @@ -1,28 +1,5 @@ pub const ENGLISH_FREQUENCIES: [f64; 26] = [ - 0.0804, - 0.0148, - 0.0334, - 0.0382, - 0.1249, - 0.0240, - 0.0187, - 0.0505, - 0.0757, - 0.0016, - 0.0054, - 0.0407, - 0.0251, - 0.0723, - 0.0764, - 0.0214, - 0.0012, - 0.0628, - 0.0651, - 0.0928, - 0.0273, - 0.0105, - 0.0168, - 0.0023, - 0.0166, - 0.0009, + 0.0804, 0.0148, 0.0334, 0.0382, 0.1249, 0.0240, 0.0187, 0.0505, 0.0757, + 0.0016, 0.0054, 0.0407, 0.0251, 0.0723, 0.0764, 0.0214, 0.0012, 0.0628, + 0.0651, 0.0928, 0.0273, 0.0105, 0.0168, 0.0023, 0.0166, 0.0009, ]; diff --git a/src/http.rs b/src/http.rs index 9096298..10b0eca 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -pub fn parse_query_string (string: &str) -> Option> { +pub fn parse_query_string(string: &str) -> Option> { let mut map = HashMap::new(); let mut offset = 0; let len = string.as_bytes().len(); @@ -10,14 +10,14 @@ pub fn parse_query_string (string: &str) -> Option> { let key_end = key_start + found; let key = &string[key_start..key_end]; let value_start = key_end + 1; - let value_end = value_start + string[value_start..] - .find('&') - .unwrap_or_else(|| string[value_start..].as_bytes().len()); + let value_end = value_start + + string[value_start..].find('&').unwrap_or_else(|| { + string[value_start..].as_bytes().len() + }); let value = &string[value_start..value_end]; map.insert(key, value); offset = value_end + 1; - } - else { + } else { return None; } } @@ -25,9 +25,11 @@ pub fn parse_query_string (string: &str) -> Option> { return Some(map); } -pub fn create_query_string (params: HashMap<&str, &str>) -> String { - fn escape (s: &str) -> String { - s.replace("%", "%25").replace("&", "%26").replace("=", "%3D") +pub fn create_query_string(params: HashMap<&str, &str>) -> String { + fn escape(s: &str) -> String { + s.replace("%", "%25") + .replace("&", "%26") + .replace("=", "%3D") } let mut parts = vec![]; @@ -37,11 +39,11 @@ pub fn create_query_string (params: HashMap<&str, &str>) -> String { part.push_str(&escape(v)[..]); parts.push(part); } - return parts.connect("&"); + return parts.join("&"); } #[test] -fn test_parse_query_string () { +fn test_parse_query_string() { let got = parse_query_string("foo=bar&baz=qux&zap=zazzle"); let mut expected = HashMap::new(); expected.insert("foo", "bar"); @@ -53,7 +55,7 @@ fn test_parse_query_string () { } #[test] -fn test_create_query_string () { +fn test_create_query_string() { let mut params = HashMap::new(); params.insert("foo", "bar"); params.insert("baz", "qux"); @@ -66,18 +68,19 @@ fn test_create_query_string () { let expected5 = "zap=zazzle&foo=bar&baz=qux"; let expected6 = "zap=zazzle&baz=qux&foo=bar"; assert!( - got == expected1 || - got == expected2 || - got == expected3 || - got == expected4 || - got == expected5 || - got == expected6, - "didn't parse query string correctly: {}", got + got == expected1 + || got == expected2 + || got == expected3 + || got == expected4 + || got == expected5 + || got == expected6, + "didn't parse query string correctly: {}", + got ); } #[test] -fn test_create_query_string_malicious () { +fn test_create_query_string_malicious() { let mut params = HashMap::new(); params.insert("email", "foo@bar.com&role=admin"); let got = create_query_string(params); diff --git a/src/lib.rs b/src/lib.rs index 151a323..51fc134 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,3 @@ -extern crate rustc_serialize as serialize; -extern crate openssl; -extern crate rand; -extern crate time; - mod aes; mod base64; mod crack; @@ -13,50 +8,50 @@ mod primitives; mod random; mod sha1; -pub use aes::decrypt_aes_128_ecb; -pub use aes::decrypt_aes_128_cbc; -pub use aes::encrypt_aes_128_ecb; -pub use aes::encrypt_aes_128_cbc; pub use aes::aes_128_ctr; pub use aes::aes_128_ctr_with_counter; +pub use aes::decrypt_aes_128_cbc; +pub use aes::decrypt_aes_128_ecb; +pub use aes::encrypt_aes_128_cbc; +pub use aes::encrypt_aes_128_ecb; pub use base64::to_base64; -pub use http::parse_query_string; +pub use crack::clone_mersenne_twister_from_output; +pub use crack::crack_aes_128_ctr_random_access; +pub use crack::crack_cbc_bitflipping; +pub use crack::crack_cbc_iv_key; +pub use crack::crack_cbc_padding_oracle; +pub use crack::crack_ctr_bitflipping; +pub use crack::crack_fixed_nonce_ctr_statistically; +pub use crack::crack_md4_mac_length_extension; +pub use crack::crack_padded_aes_128_ecb; +pub use crack::crack_padded_aes_128_ecb_with_prefix; +pub use crack::crack_querystring_aes_128_ecb; +pub use crack::crack_repeating_key_xor; +pub use crack::crack_sha1_mac_length_extension; +pub use crack::crack_single_byte_xor; +pub use crack::detect_ecb_cbc; +pub use crack::find_aes_128_ecb_encrypted_string; +pub use crack::find_single_byte_xor_encrypted_string; +pub use crack::recover_16_bit_mt19937_key; +pub use crack::recover_mersenne_twister_seed_from_time; +pub use crack::recover_mt19937_key_from_time; +pub use crack::BlockCipherMode; pub use http::create_query_string; +pub use http::parse_query_string; pub use md4::md4; -pub use md4::pad_md4; +pub use md4::md4_mac; pub use md4::md4_padding; pub use md4::md4_with_state; -pub use md4::md4_mac; +pub use md4::pad_md4; pub use primitives::fixed_xor; pub use primitives::pad_pkcs7; -pub use primitives::unpad_pkcs7; pub use primitives::repeating_key_xor; -pub use random::MersenneTwister; +pub use primitives::unpad_pkcs7; pub use random::mt19937_stream_cipher; -pub use sha1::sha1; +pub use random::MersenneTwister; pub use sha1::pad_sha1; +pub use sha1::sha1; +pub use sha1::sha1_hmac; +pub use sha1::sha1_mac; pub use sha1::sha1_padding; pub use sha1::sha1_with_state; -pub use sha1::sha1_mac; -pub use sha1::sha1_hmac; -pub use crack::BlockCipherMode; -pub use crack::find_aes_128_ecb_encrypted_string; -pub use crack::detect_ecb_cbc; -pub use crack::crack_padded_aes_128_ecb; -pub use crack::crack_padded_aes_128_ecb_with_prefix; -pub use crack::crack_querystring_aes_128_ecb; -pub use crack::crack_cbc_bitflipping; -pub use crack::crack_cbc_padding_oracle; -pub use crack::find_single_byte_xor_encrypted_string; -pub use crack::crack_single_byte_xor; -pub use crack::crack_repeating_key_xor; -pub use crack::crack_fixed_nonce_ctr_statistically; -pub use crack::recover_mersenne_twister_seed_from_time; -pub use crack::clone_mersenne_twister_from_output; -pub use crack::recover_16_bit_mt19937_key; -pub use crack::recover_mt19937_key_from_time; -pub use crack::crack_aes_128_ctr_random_access; -pub use crack::crack_ctr_bitflipping; -pub use crack::crack_cbc_iv_key; -pub use crack::crack_sha1_mac_length_extension; -pub use crack::crack_md4_mac_length_extension; diff --git a/src/md4.rs b/src/md4.rs index 4fd9121..6495ee2 100644 --- a/src/md4.rs +++ b/src/md4.rs @@ -1,40 +1,30 @@ -#[cfg(test)] use serialize::hex::ToHex; +#[cfg(test)] +use rustc_serialize::hex::ToHex; -pub fn md4 (bytes: &[u8]) -> [u8; 16] { +pub fn md4(bytes: &[u8]) -> [u8; 16] { md4_with_state( bytes, - [ - 0x67452301, - 0xEFCDAB89, - 0x98BADCFE, - 0x10325476, - ], - bytes.len() as u64 + [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476], + bytes.len() as u64, ) } -pub fn pad_md4 (bytes: &[u8], len: u64) -> Vec { - return bytes - .iter() - .map(|x| *x) - .chain(md4_padding(len)) - .collect(); +pub fn pad_md4(bytes: &[u8], len: u64) -> Vec { + return bytes.iter().map(|x| *x).chain(md4_padding(len)).collect(); } -pub fn md4_padding (len: u64) -> Vec { +pub fn md4_padding(len: u64) -> Vec { let ml: u64 = len * 8; - let ml_bytes: [u8; 8] = unsafe { - ::std::mem::transmute(ml.to_le()) - }; + let ml_bytes: [u8; 8] = unsafe { std::mem::transmute(ml.to_le()) }; return [0x80u8] .iter() .map(|x| *x) - .chain(::std::iter::repeat(0x00).take((119 - (len % 64) as usize) % 64)) + .chain(std::iter::repeat(0x00).take((119 - (len % 64) as usize) % 64)) .chain(ml_bytes.iter().map(|x| *x)) .collect(); } -fn round1 (offset: u32, x: u32, s: u32, h: &mut [u32; 4]) { +fn round1(offset: u32, x: u32, s: u32, h: &mut [u32; 4]) { let a = (4 - offset as usize) % 4; let b = (5 - offset as usize) % 4; let c = (6 - offset as usize) % 4; @@ -46,7 +36,7 @@ fn round1 (offset: u32, x: u32, s: u32, h: &mut [u32; 4]) { .rotate_left(s) } -fn round2 (offset: u32, x: u32, s: u32, h: &mut [u32; 4]) { +fn round2(offset: u32, x: u32, s: u32, h: &mut [u32; 4]) { let a = (4 - offset as usize) % 4; let b = (5 - offset as usize) % 4; let c = (6 - offset as usize) % 4; @@ -59,7 +49,7 @@ fn round2 (offset: u32, x: u32, s: u32, h: &mut [u32; 4]) { .rotate_left(s) } -fn round3 (offset: u32, x: u32, s: u32, h: &mut [u32; 4]) { +fn round3(offset: u32, x: u32, s: u32, h: &mut [u32; 4]) { let a = (4 - offset as usize) % 4; let b = (5 - offset as usize) % 4; let c = (6 - offset as usize) % 4; @@ -72,67 +62,66 @@ fn round3 (offset: u32, x: u32, s: u32, h: &mut [u32; 4]) { .rotate_left(s) } -pub fn md4_with_state (bytes: &[u8], mut h: [u32; 4], len: u64) -> [u8; 16] { +pub fn md4_with_state(bytes: &[u8], mut h: [u32; 4], len: u64) -> [u8; 16] { for chunk in pad_md4(bytes, len).chunks(64) { - let chunk_words: &[u32; 16] = unsafe { - ::std::mem::transmute(chunk.as_ptr()) - }; - let mut x: [u32; 16] = unsafe { ::std::mem::uninitialized() }; + let chunk_words: &[u32; 16] = + unsafe { std::mem::transmute(chunk.as_ptr()) }; + let mut x: [u32; 16] = unsafe { std::mem::uninitialized() }; for i in 0..16 { x[i] = u32::from_le(chunk_words[i]); } let mut hh = h; - round1(0, x[ 0], 3, &mut hh); - round1(1, x[ 1], 7, &mut hh); - round1(2, x[ 2], 11, &mut hh); - round1(3, x[ 3], 19, &mut hh); - round1(0, x[ 4], 3, &mut hh); - round1(1, x[ 5], 7, &mut hh); - round1(2, x[ 6], 11, &mut hh); - round1(3, x[ 7], 19, &mut hh); - round1(0, x[ 8], 3, &mut hh); - round1(1, x[ 9], 7, &mut hh); + round1(0, x[0], 3, &mut hh); + round1(1, x[1], 7, &mut hh); + round1(2, x[2], 11, &mut hh); + round1(3, x[3], 19, &mut hh); + round1(0, x[4], 3, &mut hh); + round1(1, x[5], 7, &mut hh); + round1(2, x[6], 11, &mut hh); + round1(3, x[7], 19, &mut hh); + round1(0, x[8], 3, &mut hh); + round1(1, x[9], 7, &mut hh); round1(2, x[10], 11, &mut hh); round1(3, x[11], 19, &mut hh); - round1(0, x[12], 3, &mut hh); - round1(1, x[13], 7, &mut hh); + round1(0, x[12], 3, &mut hh); + round1(1, x[13], 7, &mut hh); round1(2, x[14], 11, &mut hh); round1(3, x[15], 19, &mut hh); - round2(0, x[ 0], 3, &mut hh); - round2(1, x[ 4], 5, &mut hh); - round2(2, x[ 8], 9, &mut hh); + round2(0, x[0], 3, &mut hh); + round2(1, x[4], 5, &mut hh); + round2(2, x[8], 9, &mut hh); round2(3, x[12], 13, &mut hh); - round2(0, x[ 1], 3, &mut hh); - round2(1, x[ 5], 5, &mut hh); - round2(2, x[ 9], 9, &mut hh); + round2(0, x[1], 3, &mut hh); + round2(1, x[5], 5, &mut hh); + round2(2, x[9], 9, &mut hh); round2(3, x[13], 13, &mut hh); - round2(0, x[ 2], 3, &mut hh); - round2(1, x[ 6], 5, &mut hh); - round2(2, x[10], 9, &mut hh); + round2(0, x[2], 3, &mut hh); + round2(1, x[6], 5, &mut hh); + round2(2, x[10], 9, &mut hh); round2(3, x[14], 13, &mut hh); - round2(0, x[ 3], 3, &mut hh); - round2(1, x[ 7], 5, &mut hh); - round2(2, x[11], 9, &mut hh); + round2(0, x[3], 3, &mut hh); + round2(1, x[7], 5, &mut hh); + round2(2, x[11], 9, &mut hh); round2(3, x[15], 13, &mut hh); - round3(0, x[ 0], 3, &mut hh); - round3(1, x[ 8], 9, &mut hh); - round3(2, x[ 4], 11, &mut hh); + round3(0, x[0], 3, &mut hh); + round3(1, x[8], 9, &mut hh); + round3(2, x[4], 11, &mut hh); round3(3, x[12], 15, &mut hh); - round3(0, x[ 2], 3, &mut hh); - round3(1, x[10], 9, &mut hh); - round3(2, x[ 6], 11, &mut hh); + round3(0, x[2], 3, &mut hh); + round3(1, x[10], 9, &mut hh); + round3(2, x[6], 11, &mut hh); round3(3, x[14], 15, &mut hh); - round3(0, x[ 1], 3, &mut hh); - round3(1, x[ 9], 9, &mut hh); - round3(2, x[ 5], 11, &mut hh); + round3(0, x[1], 3, &mut hh); + round3(1, x[9], 9, &mut hh); + round3(2, x[5], 11, &mut hh); round3(3, x[13], 15, &mut hh); - round3(0, x[ 3], 3, &mut hh); - round3(1, x[11], 9, &mut hh); - round3(2, x[ 7], 11, &mut hh); + round3(0, x[3], 3, &mut hh); + round3(1, x[11], 9, &mut hh); + round3(2, x[7], 11, &mut hh); round3(3, x[15], 15, &mut hh); h[0] = h[0].wrapping_add(hh[0]); @@ -145,20 +134,17 @@ pub fn md4_with_state (bytes: &[u8], mut h: [u32; 4], len: u64) -> [u8; 16] { *word = word.to_le(); } - return unsafe { ::std::mem::transmute(h) }; + return unsafe { std::mem::transmute(h) }; } -pub fn md4_mac (bytes: &[u8], key: &[u8]) -> [u8; 16] { - let full_bytes: Vec = key - .iter() - .chain(bytes.iter()) - .map(|x| *x) - .collect(); +pub fn md4_mac(bytes: &[u8], key: &[u8]) -> [u8; 16] { + let full_bytes: Vec = + key.iter().chain(bytes.iter()).map(|x| *x).collect(); return md4(&full_bytes[..]); } #[test] -fn test_md4 () { +fn test_md4() { let tests = [ ( &b""[..], diff --git a/src/primitives.rs b/src/primitives.rs index d537081..6f178cc 100644 --- a/src/primitives.rs +++ b/src/primitives.rs @@ -1,36 +1,36 @@ -pub fn fixed_xor (bytes1: &[u8], bytes2: &[u8]) -> Vec { - return bytes1.iter() +pub fn fixed_xor(bytes1: &[u8], bytes2: &[u8]) -> Vec { + return bytes1 + .iter() .zip(bytes2.iter()) - .map(|(&a, &b)| { a ^ b }) + .map(|(&a, &b)| a ^ b) .collect(); } -pub fn repeating_key_xor (plaintext: &[u8], key: &[u8]) -> Vec { +pub fn repeating_key_xor(plaintext: &[u8], key: &[u8]) -> Vec { return fixed_xor( plaintext, - &key - .iter() + &key.iter() .cycle() .take(plaintext.len()) - .map(|c| *c) - .collect::>()[..] + .cloned() + .collect::>()[..], ); } -pub fn hamming (bytes1: &[u8], bytes2: &[u8]) -> u64 { +pub fn hamming(bytes1: &[u8], bytes2: &[u8]) -> u64 { count_bits(&fixed_xor(bytes1, bytes2)[..]) } -pub fn pad_pkcs7 (block: &[u8], blocksize: u8) -> Vec { +pub fn pad_pkcs7(block: &[u8], blocksize: u8) -> Vec { let padding_bytes = blocksize - (block.len() % blocksize as usize) as u8; return block .iter() - .map(|c| *c) - .chain(::std::iter::repeat(padding_bytes).take(padding_bytes as usize)) + .cloned() + .chain(std::iter::repeat(padding_bytes).take(padding_bytes as usize)) .collect(); } -pub fn unpad_pkcs7 (block: &[u8]) -> Option<&[u8]> { +pub fn unpad_pkcs7(block: &[u8]) -> Option<&[u8]> { let padding_byte = block[block.len() - 1]; let padding_len = padding_byte as usize; if padding_len > block.len() || padding_len == 0 { @@ -40,28 +40,30 @@ pub fn unpad_pkcs7 (block: &[u8]) -> Option<&[u8]> { let real_len = block.len() - padding_len; if block[real_len..].iter().all(|&c| c == padding_byte) { return Some(&block[..real_len]); - } - else { + } else { return None; } } -fn count_bits (bytes: &[u8]) -> u64 { - bytes.iter().map(|&c| { count_bits_byte(c) }).fold(0, |acc, n| acc + n) +fn count_bits(bytes: &[u8]) -> u64 { + bytes + .iter() + .map(|&c| count_bits_byte(c)) + .fold(0, |acc, n| acc + n) } -fn count_bits_byte (byte: u8) -> u64 { +fn count_bits_byte(byte: u8) -> u64 { (((byte & (0x01 << 0)) >> 0) - + ((byte & (0x01 << 1)) >> 1) - + ((byte & (0x01 << 2)) >> 2) - + ((byte & (0x01 << 3)) >> 3) - + ((byte & (0x01 << 4)) >> 4) - + ((byte & (0x01 << 5)) >> 5) - + ((byte & (0x01 << 6)) >> 6) - + ((byte & (0x01 << 7)) >> 7)) as u64 + + ((byte & (0x01 << 1)) >> 1) + + ((byte & (0x01 << 2)) >> 2) + + ((byte & (0x01 << 3)) >> 3) + + ((byte & (0x01 << 4)) >> 4) + + ((byte & (0x01 << 5)) >> 5) + + ((byte & (0x01 << 6)) >> 6) + + ((byte & (0x01 << 7)) >> 7)) as u64 } #[test] -fn test_hamming () { +fn test_hamming() { assert_eq!(hamming(b"this is a test", b"wokka wokka!!!"), 37); } diff --git a/src/random.rs b/src/random.rs index e248293..69bab3f 100644 --- a/src/random.rs +++ b/src/random.rs @@ -1,18 +1,91 @@ -use rand::{Rand, Rng, SeedableRng}; +use rand::{Rng, RngCore, SeedableRng}; pub struct MersenneTwister { state: [u32; 624], - index: usize, + index: u32, +} + +pub struct MersenneTwisterSeed([u8; 2500]); + +impl Default for MersenneTwisterSeed { + fn default() -> MersenneTwisterSeed { + MersenneTwisterSeed([0; 2500]) + } +} + +impl AsMut<[u8]> for MersenneTwisterSeed { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +fn mt_seed_to_state(seed: MersenneTwisterSeed) -> MersenneTwister { + let mut state = [0; 624]; + for i in 0..624 { + let idx = i * 4; + state[i] = u32::from_ne_bytes([ + seed.0[idx], + seed.0[idx + 1], + seed.0[idx + 2], + seed.0[idx + 3], + ]); + } + let index = u32::from_ne_bytes([ + seed.0[2496], + seed.0[2497], + seed.0[2498], + seed.0[2499], + ]) % 624; + MersenneTwister { state, index } +} + +fn mt_state_to_seed(state: [u32; 624], index: u32) -> MersenneTwisterSeed { + let mut seed = MersenneTwisterSeed([0; 2500]); + let mut idx = 0; + for i in &state[..] { + let bytes = u32::to_ne_bytes(*i); + seed.0[idx as usize] = bytes[0]; + seed.0[(idx + 1) as usize] = bytes[1]; + seed.0[(idx + 2) as usize] = bytes[2]; + seed.0[(idx + 3) as usize] = bytes[3]; + idx += 4; + } + let bytes = u32::to_ne_bytes(index); + seed.0[2496] = bytes[0]; + seed.0[2497] = bytes[1]; + seed.0[2498] = bytes[2]; + seed.0[2499] = bytes[3]; + seed } impl MersenneTwister { - fn new_unseeded () -> MersenneTwister { - MersenneTwister { state: [0; 624], index: 0 } + fn new_unseeded() -> MersenneTwister { + MersenneTwister { + state: [0; 624], + index: 0, + } + } + + pub fn from_u32(seed: u32) -> MersenneTwister { + let mut state = [0; 624]; + state[0] = seed; + for i in 1..624 { + let prev = state[i - 1]; + state[i] = 1812433253u32 + .wrapping_mul(prev ^ (prev >> 30)) + .wrapping_add(i as u32); + } + + MersenneTwister::from_seed(mt_state_to_seed(state, 0)) + } + + pub fn from_state(state: [u32; 624], index: u32) -> MersenneTwister { + MersenneTwister::from_seed(mt_state_to_seed(state, index)) } } -impl Rng for MersenneTwister { - fn next_u32 (&mut self) -> u32 { +impl RngCore for MersenneTwister { + fn next_u32(&mut self) -> u32 { if self.index == 0 { for i in 0..624 { let y = (self.state[i] & 0x80000000) @@ -24,7 +97,7 @@ impl Rng for MersenneTwister { } } - let mut y = self.state[self.index]; + let mut y = self.state[self.index as usize]; y = y ^ (y >> 11); y = y ^ ((y << 7) & 0x9d2c5680); y = y ^ ((y << 15) & 0xefc60000); @@ -34,73 +107,68 @@ impl Rng for MersenneTwister { return y; } -} -impl SeedableRng for MersenneTwister { - fn reseed (&mut self, seed: u32) { - self.state[0] = seed; - for i in 1..624 { - let prev = self.state[i - 1]; - self.state[i] = 1812433253u32 - .wrapping_mul(prev ^ (prev >> 30)) - .wrapping_add(i as u32); - } + fn next_u64(&mut self) -> u64 { + rand_core::impls::next_u64_via_u32(self) } - fn from_seed (seed: u32) -> MersenneTwister { - let mut mt = MersenneTwister::new_unseeded(); - mt.reseed(seed); - mt + fn fill_bytes(&mut self, dest: &mut [u8]) { + rand_core::impls::fill_bytes_via_next(self, dest) } -} -impl SeedableRng<([u32; 624], usize)> for MersenneTwister { - fn reseed (&mut self, seed: ([u32; 624], usize)) { - let (state, index) = seed; - for i in 0..624 { - self.state[i] = state[i]; - } - self.index = index; + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> { + Ok(rand_core::impls::fill_bytes_via_next(self, dest)) } +} - fn from_seed (seed: ([u32; 624], usize)) -> MersenneTwister { +impl SeedableRng for MersenneTwister { + type Seed = MersenneTwisterSeed; + + fn from_seed(seed: MersenneTwisterSeed) -> MersenneTwister { let mut mt = MersenneTwister::new_unseeded(); - mt.reseed(seed); + let MersenneTwister { state, index } = mt_seed_to_state(seed); + for i in 0..624 { + mt.state[i] = state[i]; + } + mt.index = index; mt } } -impl Rand for MersenneTwister { - fn rand (other: &mut R) -> MersenneTwister { - MersenneTwister::from_seed(other.next_u32()) - } -} - impl Clone for MersenneTwister { - fn clone (&self) -> MersenneTwister { - MersenneTwister { state: self.state, index: self.index } + fn clone(&self) -> MersenneTwister { + MersenneTwister { + state: self.state, + index: self.index, + } } } -impl ::std::fmt::Debug for MersenneTwister { - fn fmt (&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { - try!(write!(f, "MersenneTwister {{ ")); - try!(::std::fmt::Debug::fmt(&&self.state[..], f)); - try!(write!(f, ", ")); - try!(::std::fmt::Debug::fmt(&self.index, f)); +impl std::fmt::Debug for MersenneTwister { + fn fmt( + &self, + f: &mut std::fmt::Formatter, + ) -> Result<(), std::fmt::Error> { + write!(f, "MersenneTwister {{ ")?; + std::fmt::Debug::fmt(&&self.state[..], f)?; + write!(f, ", ")?; + std::fmt::Debug::fmt(&self.index, f)?; write!(f, " }}") } } -pub fn mt19937_stream_cipher (ciphertext: &[u8], key: u32) -> Vec { - let mut mt = MersenneTwister::from_seed(key); - let keystream: Vec = mt.gen_iter().take(ciphertext.len()).collect(); - return ::primitives::fixed_xor(ciphertext, &keystream[..]); +pub fn mt19937_stream_cipher(ciphertext: &[u8], key: u32) -> Vec { + let mut mt = MersenneTwister::from_u32(key); + let keystream: Vec = mt + .sample_iter(&rand::distributions::Standard) + .take(ciphertext.len()) + .collect(); + return crate::primitives::fixed_xor(ciphertext, &keystream[..]); } #[test] -fn test_mt19937_stream_cipher () { - let key = ::rand::thread_rng().gen(); +fn test_mt19937_stream_cipher() { + let key = rand::thread_rng().gen(); let plaintext = b"Summertime and the wind is blowing outside in lower \ Chelsea and I don't know what I'm doing in the city, the \ sun is always in my eyes"; diff --git a/src/sha1.rs b/src/sha1.rs index 95270b0..7969b21 100644 --- a/src/sha1.rs +++ b/src/sha1.rs @@ -1,53 +1,42 @@ -#[cfg(test)] use serialize::hex::ToHex; +#[cfg(test)] +use rustc_serialize::hex::ToHex; -use primitives::fixed_xor; +use crate::primitives::fixed_xor; -pub fn sha1 (bytes: &[u8]) -> [u8; 20] { +pub fn sha1(bytes: &[u8]) -> [u8; 20] { sha1_with_state( bytes, - [ - 0x67452301, - 0xEFCDAB89, - 0x98BADCFE, - 0x10325476, - 0xC3D2E1F0, - ], - bytes.len() as u64 + [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0], + bytes.len() as u64, ) } -pub fn pad_sha1 (bytes: &[u8], len: u64) -> Vec { - return bytes - .iter() - .map(|x| *x) - .chain(sha1_padding(len)) - .collect(); +pub fn pad_sha1(bytes: &[u8], len: u64) -> Vec { + return bytes.iter().map(|x| *x).chain(sha1_padding(len)).collect(); } -pub fn sha1_padding (len: u64) -> Vec { +pub fn sha1_padding(len: u64) -> Vec { let ml: u64 = len * 8; - let ml_bytes: [u8; 8] = unsafe { - ::std::mem::transmute(ml.to_be()) - }; + let ml_bytes: [u8; 8] = unsafe { std::mem::transmute(ml.to_be()) }; return [0x80u8] .iter() .map(|x| *x) - .chain(::std::iter::repeat(0x00).take((119 - (len % 64) as usize) % 64)) + .chain(std::iter::repeat(0x00).take((119 - (len % 64) as usize) % 64)) .chain(ml_bytes.iter().map(|x| *x)) .collect(); } -pub fn sha1_with_state (bytes: &[u8], mut h: [u32; 5], len: u64) -> [u8; 20] { +pub fn sha1_with_state(bytes: &[u8], mut h: [u32; 5], len: u64) -> [u8; 20] { for chunk in pad_sha1(bytes, len).chunks(64) { - let chunk_words: &[u32; 16] = unsafe { - ::std::mem::transmute(chunk.as_ptr()) - }; - let mut w: [u32; 80] = unsafe { ::std::mem::uninitialized() }; + let chunk_words: &[u32; 16] = + unsafe { std::mem::transmute(chunk.as_ptr()) }; + let mut w: [u32; 80] = unsafe { std::mem::uninitialized() }; for i in 0..16 { w[i] = u32::from_be(chunk_words[i]); } for i in 16..80 { - w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1); + w[i] = + (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1); } let mut a = h[0]; @@ -58,14 +47,15 @@ pub fn sha1_with_state (bytes: &[u8], mut h: [u32; 5], len: u64) -> [u8; 20] { for i in 0..80 { let (f, k) = match i { - 0...19 => ((b & c) | (!b & d), 0x5A827999), - 20...39 => (b ^ c ^ d, 0x6ED9EBA1), + 0...19 => ((b & c) | (!b & d), 0x5A827999), + 20...39 => (b ^ c ^ d, 0x6ED9EBA1), 40...59 => ((b & c) | (b & d) | (c & d), 0x8F1BBCDC), - 60...79 => (b ^ c ^ d, 0xCA62C1D6), + 60...79 => (b ^ c ^ d, 0xCA62C1D6), _ => panic!(), }; - let temp = a.rotate_left(5) + let temp = a + .rotate_left(5) .wrapping_add(f) .wrapping_add(e) .wrapping_add(k) @@ -89,60 +79,62 @@ pub fn sha1_with_state (bytes: &[u8], mut h: [u32; 5], len: u64) -> [u8; 20] { *word = word.to_be(); } - return unsafe { ::std::mem::transmute(h) }; + return unsafe { std::mem::transmute(h) }; } -pub fn sha1_mac (bytes: &[u8], key: &[u8]) -> [u8; 20] { - let full_bytes: Vec = key - .iter() - .chain(bytes.iter()) - .map(|x| *x) - .collect(); +pub fn sha1_mac(bytes: &[u8], key: &[u8]) -> [u8; 20] { + let full_bytes: Vec = + key.iter().chain(bytes.iter()).map(|x| *x).collect(); return sha1(&full_bytes[..]); } -pub fn sha1_hmac (bytes: &[u8], key: &[u8]) -> [u8; 20] { +pub fn sha1_hmac(bytes: &[u8], key: &[u8]) -> [u8; 20] { let blocksize = 64; let fixed_key: Vec = if key.len() > blocksize { - sha1(key).iter() + sha1(key) + .iter() .map(|x| *x) .chain(::std::iter::repeat(0x00u8).take(44)) .collect() - } - else { + } else { key.iter() .map(|x| *x) .chain(::std::iter::repeat(0x00u8).take(blocksize - key.len())) .collect() }; - let ipad: Vec = ::std::iter::repeat(0x36u8).take(blocksize).collect(); - let opad: Vec = ::std::iter::repeat(0x5cu8).take(blocksize).collect(); + let ipad: Vec = std::iter::repeat(0x36u8).take(blocksize).collect(); + let opad: Vec = std::iter::repeat(0x5cu8).take(blocksize).collect(); let k_ipad = fixed_xor(&ipad[..], &fixed_key[..]); let k_opad = fixed_xor(&opad[..], &fixed_key[..]); let inner = sha1( - &k_ipad.iter().chain(bytes.iter()).map(|x| *x).collect::>()[..] + &k_ipad + .iter() + .chain(bytes.iter()) + .map(|x| *x) + .collect::>()[..], ); return sha1( - &k_opad.iter().chain(inner.iter()).map(|x| *x).collect::>()[..] - ) + &k_opad + .iter() + .chain(inner.iter()) + .map(|x| *x) + .collect::>()[..], + ); } #[test] -fn test_sha1 () { +fn test_sha1() { let tests = [ - ( - &b""[..], - "da39a3ee5e6b4b0d3255bfef95601890afd80709" - ), + (&b""[..], "da39a3ee5e6b4b0d3255bfef95601890afd80709"), ( &b"The quick brown fox jumps over the lazy dog"[..], - "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12" + "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", ), ( &b"The quick brown fox jumps over the lazy cog"[..], - "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3" + "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3", ), ]; for &(input, expected) in tests.iter() { @@ -152,7 +144,10 @@ fn test_sha1 () { } #[test] -fn test_sha1_hmac () { - assert_eq!(&sha1_hmac(b"", b"")[..].to_hex(), "fbdb1d1b18aa6c08324b7d64b71fb76370690e1d"); +fn test_sha1_hmac() { + assert_eq!( + &sha1_hmac(b"", b"")[..].to_hex(), + "fbdb1d1b18aa6c08324b7d64b71fb76370690e1d" + ); assert_eq!(&sha1_hmac(b"The quick brown fox jumps over the lazy dog", b"key")[..].to_hex(), "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"); } diff --git a/tests/set1.rs b/tests/set1.rs index c9eece7..e1dacd1 100644 --- a/tests/set1.rs +++ b/tests/set1.rs @@ -6,10 +6,12 @@ use serialize::hex::FromHex; mod util; #[test] -fn problem_1 () { +fn problem_1() { let hex = "49276d206b696c6c696e6720796f757220627261\ 696e206c696b65206120706f69736f6e6f757320\ - 6d757368726f6f6d".from_hex().unwrap(); + 6d757368726f6f6d" + .from_hex() + .unwrap(); let base64 = "SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEg\ cG9pc29ub3VzIG11c2hyb29t"; let got = matasano::to_base64(&hex[..]); @@ -17,7 +19,7 @@ fn problem_1 () { } #[test] -fn problem_2 () { +fn problem_2() { let bytes1 = "1c0111001f010100061a024b53535009181c".from_hex().unwrap(); let bytes2 = "686974207468652062756c6c277320657965".from_hex().unwrap(); let expected = "746865206b696420646f6e277420706c6179".from_hex().unwrap(); @@ -26,16 +28,18 @@ fn problem_2 () { } #[test] -fn problem_3 () { +fn problem_3() { let ciphertext = "1b37373331363f78151b7f2b783431333d783978\ - 28372d363c78373e783a393b3736".from_hex().unwrap(); + 28372d363c78373e783a393b3736" + .from_hex() + .unwrap(); let plaintext = b"Cooking MC's like a pound of bacon"; let got = matasano::crack_single_byte_xor(&ciphertext[..]); assert_eq!(got, &plaintext[..]); } #[test] -fn problem_4 () { +fn problem_4() { let possibles = util::read_as_hex_lines("data/4.txt"); let plaintext = b"Now that the party is jumping\n"; let got = matasano::find_single_byte_xor_encrypted_string(&possibles[..]); @@ -43,20 +47,22 @@ fn problem_4 () { } #[test] -fn problem_5 () { +fn problem_5() { let plaintext = b"Burning 'em, if you ain't quick and nimble\n\ I go crazy when I hear a cymbal"; let key = b"ICE"; let ciphertext = "0b3637272a2b2e63622c2e69692a23693a2a3c63\ 24202d623d63343c2a26226324272765272a282b\ 2f20430a652e2c652a3124333a653e2b2027630c\ - 692b20283165286326302e27282f".from_hex().unwrap(); + 692b20283165286326302e27282f" + .from_hex() + .unwrap(); let got = matasano::repeating_key_xor(plaintext, key); assert_eq!(got, ciphertext); } #[test] -fn problem_6 () { +fn problem_6() { let ciphertext = util::read_as_base64("data/6.txt"); let plaintext = util::read("data/6.out.txt"); let key = matasano::crack_repeating_key_xor(&ciphertext[..]); @@ -65,16 +71,16 @@ fn problem_6 () { } #[test] -fn problem_7 () { +fn problem_7() { let ciphertext = util::read_as_base64("data/7.txt"); let key = b"YELLOW SUBMARINE"; let plaintext = util::read("data/7.out.txt"); let got = matasano::decrypt_aes_128_ecb(&ciphertext[..], key); - assert_eq!(got, Some(plaintext)); + assert_eq!(got, plaintext); } #[test] -fn problem_8 () { +fn problem_8() { let possibles = util::read_as_hex_lines("data/8.txt"); let ciphertext = "d880619740a8a19b7840a8a31c810a3d08649af7\ 0dc06f4fd5d2d69c744cd283e2dd052f6b641dbf\ @@ -84,7 +90,8 @@ fn problem_8 () { 8d6aecd566489154789a6b0308649af70dc06f4f\ d5d2d69c744cd283d403180c98c8f6db1f2a3f9c\ 4040deb0ab51b29933f2c123c58386b06fba186a" - .from_hex().unwrap(); + .from_hex() + .unwrap(); let got = matasano::find_aes_128_ecb_encrypted_string(&possibles[..]); assert_eq!(got, ciphertext); } diff --git a/tests/set2.rs b/tests/set2.rs index 84f55b5..d5cc5d5 100644 --- a/tests/set2.rs +++ b/tests/set2.rs @@ -1,6 +1,6 @@ extern crate matasano; -extern crate rustc_serialize as serialize; extern crate rand; +extern crate rustc_serialize as serialize; use std::borrow::ToOwned; use std::collections::HashMap; @@ -11,14 +11,14 @@ use serialize::base64::FromBase64; mod util; #[test] -fn problem_9 () { +fn problem_9() { let block = b"YELLOW SUBMARINE"; let got = matasano::pad_pkcs7(block, 20); assert_eq!(got, b"YELLOW SUBMARINE\x04\x04\x04\x04"); } #[test] -fn problem_10 () { +fn problem_10() { let ciphertext = util::read_as_base64("data/10.txt"); let key = b"YELLOW SUBMARINE"; let plaintext = util::read("data/10.out.txt"); @@ -27,16 +27,17 @@ fn problem_10 () { } #[test] -fn problem_11 () { - static mut last_mode: matasano::BlockCipherMode = matasano::BlockCipherMode::ECB; +fn problem_11() { + static mut LAST_MODE: matasano::BlockCipherMode = + matasano::BlockCipherMode::ECB; - fn random_padding (input: &[u8]) -> Vec { + fn random_padding(input: &[u8]) -> Vec { let front_padding: Vec = rand::thread_rng() - .gen_iter() + .sample_iter(&rand::distributions::Standard) .take(rand::thread_rng().gen_range(5, 10)) .collect(); let back_padding: Vec = rand::thread_rng() - .gen_iter() + .sample_iter(&rand::distributions::Standard) .take(rand::thread_rng().gen_range(5, 10)) .collect(); return front_padding @@ -44,47 +45,48 @@ fn problem_11 () { .chain(input.iter()) .chain(back_padding.iter()) .map(|x| *x) - .collect() + .collect(); } - fn random_encrypter (input: &[u8]) -> Vec { + fn random_encrypter(input: &[u8]) -> Vec { let key = util::random_aes_128_key(); let padded_input = random_padding(input); if util::coinflip() { unsafe { - last_mode = matasano::BlockCipherMode::ECB; + LAST_MODE = matasano::BlockCipherMode::ECB; } return matasano::encrypt_aes_128_ecb(&padded_input[..], &key[..]); - } - else { + } else { unsafe { - last_mode = matasano::BlockCipherMode::CBC; + LAST_MODE = matasano::BlockCipherMode::CBC; } let iv = util::random_aes_128_key(); - return matasano::encrypt_aes_128_cbc(&padded_input[..], &key[..], &iv[..]); + return matasano::encrypt_aes_128_cbc( + &padded_input[..], + &key[..], + &iv[..], + ); } } for _ in 0..100 { let got = matasano::detect_ecb_cbc(&random_encrypter, 16); - let expected = unsafe { &last_mode }; + let expected = unsafe { &LAST_MODE }; assert_eq!(&got, expected); } } #[test] -fn problem_12 () { +fn problem_12() { let padding = b"Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWct\ dG9wIGRvd24gc28gbXkgaGFpciBjYW4gYmxvdwpU\ aGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBq\ dXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5v\ - LCBJIGp1c3QgZHJvdmUgYnkK".from_base64().unwrap(); + LCBJIGp1c3QgZHJvdmUgYnkK" + .from_base64() + .unwrap(); let fixed_padding = |input: &[u8]| -> Vec { - return input - .iter() - .chain(padding.iter()) - .map(|x| *x) - .collect() + return input.iter().chain(padding.iter()).map(|x| *x).collect(); }; let key = util::random_aes_128_key(); @@ -98,8 +100,8 @@ fn problem_12 () { } #[test] -fn problem_13 () { - fn profile_for (email: &str) -> String { +fn problem_13() { + fn profile_for(email: &str) -> String { let mut params = HashMap::new(); params.insert("email", email); params.insert("uid", "10"); @@ -112,40 +114,42 @@ fn problem_13 () { matasano::encrypt_aes_128_ecb(profile_for(email).as_bytes(), &key[..]) }; let decrypter = |ciphertext: &[u8]| -> Option> { - let plaintext = matasano::decrypt_aes_128_ecb(ciphertext, &key[..]).unwrap(); + let plaintext = matasano::decrypt_aes_128_ecb(ciphertext, &key[..]); let plaintext_str = std::str::from_utf8(&plaintext[..]).unwrap(); if let Some(params) = matasano::parse_query_string(plaintext_str) { return Some( params - .into_iter() - .map(|(k, v)| (k.to_owned(), v.to_owned())) - .collect() + .into_iter() + .map(|(k, v)| (k.to_owned(), v.to_owned())) + .collect(), ); - } - else { + } else { return None; } }; - let (email, ciphertexts) = matasano::crack_querystring_aes_128_ecb(&encrypter); + let (email, ciphertexts) = + matasano::crack_querystring_aes_128_ecb(&encrypter); let mut expected = HashMap::new(); expected.insert("email".to_owned(), email); expected.insert("uid".to_owned(), "10".to_owned()); expected.insert("role".to_owned(), "admin".to_owned()); - assert!(ciphertexts.iter().any(|ciphertext| { - decrypter(ciphertext).map(|params| params == expected).unwrap_or(false) - })); + assert!(ciphertexts.iter().any(|ciphertext| decrypter(ciphertext) + .map(|params| params == expected) + .unwrap_or(false))); } #[test] -fn problem_14 () { +fn problem_14() { let padding = b"Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWct\ dG9wIGRvd24gc28gbXkgaGFpciBjYW4gYmxvdwpU\ aGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBq\ dXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5v\ - LCBJIGp1c3QgZHJvdmUgYnkK".from_base64().unwrap(); + LCBJIGp1c3QgZHJvdmUgYnkK" + .from_base64() + .unwrap(); let front_padding: Vec = rand::thread_rng() - .gen_iter() + .sample_iter(&rand::distributions::Standard) .take(rand::thread_rng().gen_range(1, 100)) .collect(); let fixed_padding = |input: &[u8]| -> Vec { @@ -154,7 +158,7 @@ fn problem_14 () { .chain(input.iter()) .chain(padding.iter()) .map(|x| *x) - .collect() + .collect(); }; let key = util::random_aes_128_key(); @@ -163,36 +167,25 @@ fn problem_14 () { return matasano::encrypt_aes_128_ecb(&padded_input[..], &key[..]); }; - let got = matasano::crack_padded_aes_128_ecb_with_prefix(&random_encrypter); + let got = + matasano::crack_padded_aes_128_ecb_with_prefix(&random_encrypter); assert_eq!(got, padding); } #[test] -fn problem_15 () { +fn problem_15() { assert_eq!( matasano::unpad_pkcs7(b"ICE ICE BABY\x04\x04\x04\x04"), Some(&b"ICE ICE BABY"[..]) ); - assert_eq!( - matasano::unpad_pkcs7(b"ICE ICE BABY\x05\x05\x05\x05"), - None - ); - assert_eq!( - matasano::unpad_pkcs7(b"ICE ICE BABY\x01\x02\x03\x04"), - None - ); - assert_eq!( - matasano::unpad_pkcs7(b"ICE ICE BABY\x00"), - None - ); - assert_eq!( - matasano::unpad_pkcs7(b"\x04\x04\x04\x04"), - Some(&b""[..]) - ); + assert_eq!(matasano::unpad_pkcs7(b"ICE ICE BABY\x05\x05\x05\x05"), None); + assert_eq!(matasano::unpad_pkcs7(b"ICE ICE BABY\x01\x02\x03\x04"), None); + assert_eq!(matasano::unpad_pkcs7(b"ICE ICE BABY\x00"), None); + assert_eq!(matasano::unpad_pkcs7(b"\x04\x04\x04\x04"), Some(&b""[..])); } #[test] -fn problem_16 () { +fn problem_16() { let key = util::random_aes_128_key(); let iv = util::random_aes_128_key(); let prefix = "comment1=cooking%20MCs;userdata="; @@ -200,7 +193,10 @@ fn problem_16 () { let admin = ";admin=true;"; let escape = |input: &str| { - input.replace("%", "%25").replace(";", "%3B").replace("=", "%3D") + input + .replace("%", "%25") + .replace(";", "%3B") + .replace("=", "%3D") }; let encode = |input: &str| -> Vec { @@ -211,11 +207,17 @@ fn problem_16 () { .chain(suffix.as_bytes().iter()) .map(|x| *x) .collect(); - return matasano::encrypt_aes_128_cbc(&plaintext[..], &key[..], &iv[..]); + return matasano::encrypt_aes_128_cbc( + &plaintext[..], + &key[..], + &iv[..], + ); }; let verify = |ciphertext: &[u8]| -> bool { - let plaintext = matasano::decrypt_aes_128_cbc(ciphertext, &key[..], &iv[..]).unwrap(); + let plaintext = + matasano::decrypt_aes_128_cbc(ciphertext, &key[..], &iv[..]) + .unwrap(); return (0..(plaintext.len() - admin.len())).any(|i| { plaintext .iter() diff --git a/tests/set3.rs b/tests/set3.rs index 77b3371..4cbd9e2 100644 --- a/tests/set3.rs +++ b/tests/set3.rs @@ -1,16 +1,14 @@ extern crate matasano; -extern crate rustc_serialize as serialize; extern crate rand; +extern crate rustc_serialize as serialize; -use std::ascii::AsciiExt; - -use rand::{Rng, SeedableRng}; +use rand::{FromEntropy, Rng}; use serialize::base64::FromBase64; mod util; #[test] -fn problem_17 () { +fn problem_17() { let strings = [ &b"MDAwMDAwTm93IHRoYXQgdGhlIHBhcnR5IGlzIGp1bXBpbmc="[..], &b"MDAwMDAxV2l0aCB0aGUgYmFzcyBraWNrZWQgaW4gYW5kIHRoZSBWZWdhJ3MgYXJlIHB1bXBpbic="[..], @@ -25,24 +23,21 @@ fn problem_17 () { ]; let key = util::random_aes_128_key(); - static mut chosen_plaintext_idx: usize = 0; + static mut CHOSEN_PLAINTEXT_IDX: usize = 0; let encrypter = || { let idx = rand::thread_rng().gen_range(0, strings.len()); let plaintext = strings[idx].from_base64().unwrap(); - unsafe { chosen_plaintext_idx = idx }; + unsafe { CHOSEN_PLAINTEXT_IDX = idx }; let iv = util::random_aes_128_key(); return ( iv, - matasano::encrypt_aes_128_cbc(&plaintext[..], &key[..], &iv[..]) + matasano::encrypt_aes_128_cbc(&plaintext[..], &key[..], &iv[..]), ); }; let validator = |iv: &[u8], ciphertext: &[u8]| { - let plaintext = matasano::decrypt_aes_128_cbc( - ciphertext, - &key[..], - &iv[..] - ); + let plaintext = + matasano::decrypt_aes_128_cbc(ciphertext, &key[..], &iv[..]); return plaintext.is_some(); }; @@ -51,24 +46,23 @@ fn problem_17 () { let plaintext = matasano::crack_cbc_padding_oracle( &iv[..], &ciphertext[..], - &validator + &validator, ); - let idx = unsafe { chosen_plaintext_idx.clone() }; + let idx = unsafe { CHOSEN_PLAINTEXT_IDX.clone() }; let expected = strings[idx].from_base64().unwrap(); assert_eq!(plaintext, expected); } } #[test] -fn problem_18 () { +fn problem_18() { let ciphertext = b"L77na/nrFsKvynd6HzOoG7GHTLXsTVu9qvY/2syL\ - XzhPweyyMTJULu/6/kXX0KSvoOLSFQ==".from_base64().unwrap(); - let plaintext = &b"Yo, VIP Let's kick it Ice, Ice, baby Ice, Ice, baby "[..]; - let got = matasano::aes_128_ctr( - &ciphertext[..], - b"YELLOW SUBMARINE", - 0 - ); + XzhPweyyMTJULu/6/kXX0KSvoOLSFQ==" + .from_base64() + .unwrap(); + let plaintext = + &b"Yo, VIP Let's kick it Ice, Ice, baby Ice, Ice, baby "[..]; + let got = matasano::aes_128_ctr(&ciphertext[..], b"YELLOW SUBMARINE", 0); assert_eq!(got, plaintext); } @@ -83,8 +77,8 @@ fn problem_18 () { // } #[test] -fn problem_20 () { - fn normalize (line_list: Vec>, len: usize) -> Vec> { +fn problem_20() { + fn normalize(line_list: Vec>, len: usize) -> Vec> { line_list .iter() .map(|line| line.to_ascii_lowercase()) @@ -99,20 +93,19 @@ fn problem_20 () { .collect(); let expected = util::read_as_lines("data/20.out.txt"); - let plaintexts = matasano::crack_fixed_nonce_ctr_statistically( - ciphertexts - ); + let plaintexts = + matasano::crack_fixed_nonce_ctr_statistically(ciphertexts); - assert_eq!( - normalize(plaintexts, 27), - normalize(expected, 27) - ); + assert_eq!(normalize(plaintexts, 27), normalize(expected, 27)); } #[test] -fn problem_21 () { - let mut mt = matasano::MersenneTwister::from_seed(0x12345678); - let got: Vec = mt.gen_iter().take(10).collect(); +fn problem_21() { + let mut mt = matasano::MersenneTwister::from_u32(0x12345678); + let got: Vec = mt + .sample_iter(&rand::distributions::Standard) + .take(10) + .collect(); let expected: Vec = vec![ 0xC6979343, 0x0962D2FA, 0xA73A24A4, 0xE118A180, 0xB5475ABB, 0x64613C7C, 0x6F32F4DB, 0xF27BF199, 0x464DD8DC, 0x95C1FED6, @@ -121,20 +114,24 @@ fn problem_21 () { } #[test] -fn problem_22 () { +fn problem_22() { // std::thread::sleep_ms(rand::thread_rng().gen_range(40, 1000) * 1000); let seed = util::now(); - let mut mt = matasano::MersenneTwister::from_seed(seed); + let mut mt = matasano::MersenneTwister::from_u32(seed); // std::thread::sleep_ms(rand::thread_rng().gen_range(40, 1000) * 1000); let output: u32 = mt.gen(); - let got = matasano::recover_mersenne_twister_seed_from_time(output).unwrap(); + let got = + matasano::recover_mersenne_twister_seed_from_time(output).unwrap(); assert_eq!(got, seed); } #[test] -fn problem_23 () { - let mut mt: matasano::MersenneTwister = rand::thread_rng().gen(); - let outputs: Vec = mt.gen_iter().take(624).collect(); +fn problem_23() { + let mut mt = matasano::MersenneTwister::from_entropy(); + let outputs: Vec = mt + .sample_iter(&rand::distributions::Standard) + .take(624) + .collect(); let mut mt2 = matasano::clone_mersenne_twister_from_output(&outputs[..]); for _ in 1..1000 { assert_eq!(mt.gen::(), mt2.gen::()); @@ -142,27 +139,32 @@ fn problem_23 () { } #[test] -fn problem_24 () { +fn problem_24() { let key: u16 = rand::thread_rng().gen(); let fixed_suffix = b"AAAAAAAAAAAAAA"; let plaintext: Vec = rand::thread_rng() - .gen_iter() + .sample_iter(&rand::distributions::Standard) .take(rand::thread_rng().gen_range(0, 32)) .chain(fixed_suffix.iter().map(|x| *x)) .collect(); - let ciphertext = matasano::mt19937_stream_cipher(&plaintext[..], key as u32); + let ciphertext = + matasano::mt19937_stream_cipher(&plaintext[..], key as u32); let got = matasano::recover_16_bit_mt19937_key( &ciphertext[..], &fixed_suffix[..], - ).unwrap(); + ) + .unwrap(); assert_eq!(got, key); } #[test] -fn problem_24_part_2 () { +fn problem_24_part_2() { let seed = util::now(); - let mut mt = matasano::MersenneTwister::from_seed(seed); - let token: Vec = mt.gen_iter().take(16).collect(); + let mut mt = matasano::MersenneTwister::from_u32(seed); + let token: Vec = mt + .sample_iter(&rand::distributions::Standard) + .take(16) + .collect(); let got = matasano::recover_mt19937_key_from_time(&token[..]).unwrap(); assert_eq!(got, seed); } diff --git a/tests/set4.rs b/tests/set4.rs index d6fbeb5..5f5916d 100644 --- a/tests/set4.rs +++ b/tests/set4.rs @@ -6,7 +6,7 @@ use rand::Rng; mod util; #[test] -fn problem_25 () { +fn problem_25() { let key = util::random_aes_128_key(); let nonce: u64 = rand::thread_rng().gen(); let plaintext = util::read("data/25.txt"); @@ -16,15 +16,13 @@ fn problem_25 () { let block_start_number = offset / 16; let block_start = block_start_number * 16; let block_end_number = (offset + newtext.len() - 1) / 16; - let block_end = std::cmp::min( - (block_end_number + 1) * 16, - ciphertext.len() - ); + let block_end = + std::cmp::min((block_end_number + 1) * 16, ciphertext.len()); let mut plaintext = matasano::aes_128_ctr_with_counter( &ciphertext[block_start..block_end], &key[..], nonce, - (offset / 16) as u64 + (offset / 16) as u64, ); for i in 0..newtext.len() { plaintext[offset - block_start + i] = newtext[i]; @@ -33,7 +31,7 @@ fn problem_25 () { &plaintext[..], &key[..], nonce, - (offset / 16) as u64 + (offset / 16) as u64, ); return ciphertext @@ -45,12 +43,13 @@ fn problem_25 () { .collect(); }; - let got = matasano::crack_aes_128_ctr_random_access(&ciphertext[..], edit); + let got = + matasano::crack_aes_128_ctr_random_access(&ciphertext[..], edit); assert_eq!(&got[..], &plaintext[..]); } #[test] -fn problem_26 () { +fn problem_26() { let key = util::random_aes_128_key(); let nonce = rand::thread_rng().gen(); let prefix = "comment1=cooking%20MCs;userdata="; @@ -58,7 +57,10 @@ fn problem_26 () { let admin = ";admin=true;"; let escape = |input: &str| { - input.replace("%", "%25").replace(";", "%3B").replace("=", "%3D") + input + .replace("%", "%25") + .replace(";", "%3B") + .replace("=", "%3D") }; let encode = |input: &str| -> Vec { @@ -88,7 +90,7 @@ fn problem_26 () { } #[test] -fn problem_27 () { +fn problem_27() { let key = util::random_aes_128_key(); let iv = key; let prefix = "comment1=cooking%20MCs;userdata="; @@ -96,7 +98,10 @@ fn problem_27 () { let admin = ";admin=true;"; let escape = |input: &str| { - input.replace("%", "%25").replace(";", "%3B").replace("=", "%3D") + input + .replace("%", "%25") + .replace(";", "%3B") + .replace("=", "%3D") }; let encode = |input: &str| -> Vec { @@ -107,24 +112,27 @@ fn problem_27 () { .chain(suffix.as_bytes().iter()) .map(|x| *x) .collect(); - return matasano::encrypt_aes_128_cbc(&plaintext[..], &key[..], &iv[..]); + return matasano::encrypt_aes_128_cbc( + &plaintext[..], + &key[..], + &iv[..], + ); }; let verify = |ciphertext: &[u8]| -> Result> { - let plaintext = matasano::decrypt_aes_128_cbc(ciphertext, &key[..], &iv[..]).unwrap(); + let plaintext = + matasano::decrypt_aes_128_cbc(ciphertext, &key[..], &iv[..]) + .unwrap(); if plaintext.iter().any(|&c| c < 32 || c > 126) { return Err(plaintext); - } - else { - return Ok( - (0..(plaintext.len() - admin.len())).any(|i| { - plaintext - .iter() - .skip(i) - .zip(admin.as_bytes().iter()) - .all(|(&c1, &c2)| c1 == c2) - }) - ); + } else { + return Ok((0..(plaintext.len() - admin.len())).any(|i| { + plaintext + .iter() + .skip(i) + .zip(admin.as_bytes().iter()) + .all(|(&c1, &c2)| c1 == c2) + })); } }; @@ -135,45 +143,47 @@ fn problem_27 () { // problem 28 is just matasano::sha1_mac #[test] -fn problem_29 () { - let key: Vec = ::rand::thread_rng() - .gen_iter() +fn problem_29() { + let key: Vec = rand::thread_rng() + .sample_iter(&rand::distributions::Standard) .take(::rand::thread_rng().gen_range(5, 25)) .collect(); let valid_input = b"comment1=cooking%20MCs;userdata=foo;comment2=%20like%20a%20pound%20of%20bacon"; let valid_mac = matasano::sha1_mac(valid_input, &key[..]); - let possibles = matasano::crack_sha1_mac_length_extension(valid_input, valid_mac, b";admin=true"); - assert!( - possibles.iter().all(|&(ref input, _)| { - input.ends_with(b";admin=true") - }) - ); - assert!( - possibles.iter().any(|&(ref input, ref mac)| { - &matasano::sha1_mac(&input[..], &key[..])[..] == &mac[..] - }) + let possibles = matasano::crack_sha1_mac_length_extension( + valid_input, + valid_mac, + b";admin=true", ); + assert!(possibles + .iter() + .all(|&(ref input, _)| input.ends_with(b";admin=true"))); + assert!(possibles.iter().any( + |&(ref input, ref mac)| &matasano::sha1_mac(&input[..], &key[..])[..] + == &mac[..] + )); } #[test] -fn problem_30 () { - let key: Vec = ::rand::thread_rng() - .gen_iter() +fn problem_30() { + let key: Vec = rand::thread_rng() + .sample_iter(&rand::distributions::Standard) .take(::rand::thread_rng().gen_range(5, 25)) .collect(); let valid_input = b"comment1=cooking%20MCs;userdata=foo;comment2=%20like%20a%20pound%20of%20bacon"; let valid_mac = matasano::md4_mac(valid_input, &key[..]); - let possibles = matasano::crack_md4_mac_length_extension(valid_input, valid_mac, b";admin=true"); - assert!( - possibles.iter().all(|&(ref input, _)| { - input.ends_with(b";admin=true") - }) - ); - assert!( - possibles.iter().any(|&(ref input, ref mac)| { - &matasano::md4_mac(&input[..], &key[..])[..] == &mac[..] - }) + let possibles = matasano::crack_md4_mac_length_extension( + valid_input, + valid_mac, + b";admin=true", ); + assert!(possibles + .iter() + .all(|&(ref input, _)| input.ends_with(b";admin=true"))); + assert!(possibles.iter().any( + |&(ref input, ref mac)| &matasano::md4_mac(&input[..], &key[..])[..] + == &mac[..] + )); } diff --git a/tests/util.rs b/tests/util.rs index 6921eea..390559e 100644 --- a/tests/util.rs +++ b/tests/util.rs @@ -4,66 +4,66 @@ extern crate rand; extern crate rustc_serialize as serialize; extern crate time; -use std::io::prelude::*; use std::fs::File; +use std::io::prelude::*; -use self::rand::Rng; +use self::rand::{Rng, RngCore}; use self::serialize::base64::FromBase64; use self::serialize::hex::FromHex; -pub fn read_as_hex_lines (filename: &str) -> Vec> { +pub fn read_as_hex_lines(filename: &str) -> Vec> { let fh = File::open(filename).unwrap(); - return ::std::io::BufReader::new(fh) + return std::io::BufReader::new(fh) .lines() .map(|line| line.unwrap().from_hex().unwrap()) .collect(); } -pub fn read_as_base64_lines (filename: &str) -> Vec> { +pub fn read_as_base64_lines(filename: &str) -> Vec> { let fh = File::open(filename).unwrap(); - return ::std::io::BufReader::new(fh) + return std::io::BufReader::new(fh) .lines() .map(|line| line.unwrap().from_base64().unwrap()) .collect(); } -pub fn read_as_lines (filename: &str) -> Vec> { +pub fn read_as_lines(filename: &str) -> Vec> { let fh = File::open(filename).unwrap(); - return ::std::io::BufReader::new(fh) + return std::io::BufReader::new(fh) .lines() .map(|line| line.unwrap().as_bytes().to_vec()) .collect(); } -pub fn read_as_base64 (filename: &str) -> Vec { +pub fn read_as_base64(filename: &str) -> Vec { let fh = File::open(filename).unwrap(); - return ::std::io::BufReader::new(fh) + return std::io::BufReader::new(fh) .lines() .map(|line| line.unwrap().from_base64().unwrap()) .collect::>>() .concat(); } -pub fn read (filename: &str) -> Vec { +pub fn read(filename: &str) -> Vec { let outfh = File::open(filename).unwrap(); return outfh.bytes().map(|c| c.unwrap()).collect(); } -pub fn write (filename: &str, data: &[u8]) { +pub fn write(filename: &str, data: &[u8]) { let mut outfh = File::create(filename).unwrap(); outfh.write(data).unwrap(); } -pub fn random_aes_128_key () -> [u8; 16] { +pub fn random_aes_128_key() -> [u8; 16] { let mut key = [0; 16]; self::rand::thread_rng().fill_bytes(&mut key); return key; } -pub fn coinflip () -> bool { +pub fn coinflip() -> bool { self::rand::thread_rng().gen() } -pub fn now () -> u32 { +pub fn now() -> u32 { return self::time::now().to_timespec().sec as u32; } -- cgit v1.2.3-54-g00ecf