added md2 and md4, updated API to v2

This commit is contained in:
Frederik Palmø 2022-09-16 14:07:57 +02:00
parent 1c43531f3f
commit 167a6cb25a
12 changed files with 656 additions and 825 deletions

592
Cargo.lock generated
View File

@ -2,598 +2,6 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bstr"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
dependencies = [
"lazy_static",
"memchr",
"regex-automata",
"serde",
]
[[package]]
name = "bumpalo"
version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
[[package]]
name = "cast"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a"
dependencies = [
"rustc_version",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [
"bitflags",
"textwrap",
"unicode-width",
]
[[package]]
name = "criterion"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10"
dependencies = [
"atty",
"cast",
"clap",
"criterion-plot",
"csv",
"itertools",
"lazy_static",
"num-traits",
"oorandom",
"plotters",
"rayon",
"regex",
"serde",
"serde_cbor",
"serde_derive",
"serde_json",
"tinytemplate",
"walkdir",
]
[[package]]
name = "criterion-plot"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57"
dependencies = [
"cast",
"itertools",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
dependencies = [
"cfg-if",
"crossbeam-utils",
"lazy_static",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
dependencies = [
"cfg-if",
"lazy_static",
]
[[package]]
name = "csv"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
dependencies = [
"bstr",
"csv-core",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "csv-core"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
dependencies = [
"memchr",
]
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "half"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "itertools"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "js-sys"
version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
[[package]]
name = "lore"
version = "2.0.0"
dependencies = [
"criterion",
]
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "memoffset"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
dependencies = [
"autocfg",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "oorandom"
version = "11.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
name = "plotters"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a"
dependencies = [
"num-traits",
"plotters-backend",
"plotters-svg",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "plotters-backend"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c"
[[package]]
name = "plotters-svg"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9"
dependencies = [
"plotters-backend",
]
[[package]]
name = "proc-macro2"
version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rayon"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
dependencies = [
"autocfg",
"crossbeam-deque",
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"lazy_static",
"num_cpus",
]
[[package]]
name = "regex"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
dependencies = [
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver",
]
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "semver"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
[[package]]
name = "serde"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
[[package]]
name = "serde_cbor"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
dependencies = [
"half",
"serde",
]
[[package]]
name = "serde_derive"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "syn"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]]
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "unicode-width"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "walkdir"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
dependencies = [
"same-file",
"winapi",
"winapi-util",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
[[package]]
name = "web-sys"
version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -12,8 +12,3 @@ categories = ["algorithms", "compression", "cryptography"]
exclude = []
[dev-dependencies]
criterion = { version = "^0.3", features = ["html_reports"] }
[[bench]]
name = "md5"
harness = false

View File

@ -1,14 +0,0 @@
use criterion::*;
use lore::md5;
fn md5(c: &mut Criterion) {
c.bench_function("md5", |b| {
b.iter(|| {
let hash = md5::hash(black_box("tihi xd"));
hash.to_hex_string();
})
});
}
criterion_group!(benches, md5);
criterion_main!(benches);

1
rust-toolchain Normal file
View File

@ -0,0 +1 @@
nightly

View File

@ -1,10 +1,3 @@
use lore::md5;
fn main() {
let input = "lol xd";
assert_eq!(
md5::hash(input).to_hex_string(),
"982d7f24f8985a6baa5cf129acc73561"
);
println!("{}", lore::md2("abc"));
}

64
src/hash.rs Normal file
View File

@ -0,0 +1,64 @@
use std::fmt::Display;
pub mod md2;
pub mod md4;
pub mod md5;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Digest<const S: usize>([u8; S]);
impl<const S: usize> Display for Digest<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(
&self
.0
.iter()
.map(|u| format!("{:02x}", u))
.collect::<Vec<_>>()
.join(""),
)
}
}
pub(crate) fn bytes_to_words_le(bytes: impl AsRef<[u8]>) -> Vec<u32> {
bytes
.as_ref()
.array_chunks::<4>()
.map(|chunk| u32::from_le_bytes(*chunk))
.collect()
}
pub(crate) fn words_to_bytes_le(words: impl AsRef<[u32]>) -> Vec<u8> {
words
.as_ref()
.iter()
.flat_map(|w| w.to_le_bytes())
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bytes_to_words_le_works() {
assert_eq!(
vec![0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476],
bytes_to_words_le([
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
0x32, 0x10
])
)
}
#[test]
fn words_to_bytes_le_works() {
assert_eq!(
vec![
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
0x32, 0x10
],
words_to_bytes_le([0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476])
)
}
}

140
src/hash/md2.rs Normal file
View File

@ -0,0 +1,140 @@
use crate::hash::Digest;
/// see RFC1319
const S: [u8; 256] = [
0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13,
0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA,
0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12,
0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A,
0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03,
0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6,
0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1,
0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02,
0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26,
0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52,
0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A,
0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39,
0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14,
];
fn pad(message: impl AsRef<[u8]>) -> Vec<u8> {
let mut message = message.as_ref().to_vec();
let padding_length = 16 - (message.len() % 16);
message.append(&mut vec![padding_length as u8; padding_length]);
message
}
fn checksum(message: impl AsRef<[u8]>) -> Vec<u8> {
let mut message = message.as_ref().to_vec();
let mut checksum = vec![0u8; 16];
let mut last = 0;
for block in message.array_chunks::<16>() {
for i in 0..16 {
checksum[i] ^= S[(block[i] ^ last) as usize];
last = checksum[i];
}
}
message.append(&mut checksum);
message
}
/// Compute the MD2 hash of the input bytes
/// # Examples
/// ```
/// let input = "abc";
/// let digest = lore::md2(input);
///
/// assert_eq!(digest.to_string(), "da853b0d3f88d99b30283a69e6ded6bb");
/// ```
pub fn hash(msg: impl AsRef<[u8]>) -> Digest<16> {
let padded = checksum(pad(msg));
let buffer = padded
.array_chunks::<16>()
.fold([0u8; 48], |mut buffer, chunk| {
// copy chunk into buffer
for i in 0..16 {
buffer[16 + i] = chunk[i];
buffer[32 + i] = buffer[16 + i] ^ buffer[i];
}
// do 18 rounds
let mut t = 0;
for i in 0..18 {
for b in buffer.iter_mut() {
*b ^= S[t as usize];
t = *b;
}
t = t.wrapping_add(i);
}
buffer
});
let digest = *buffer.array_chunks::<16>().next().unwrap();
Digest(digest)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn md2_pad() {
// assert that padding length is always correct
assert!(pad([]).len() % 16 == 0);
assert!(pad([0u8]).len() % 16 == 0);
assert!(pad([0u8; 15]).len() % 16 == 0);
assert!(pad([0u8; 16]).len() % 16 == 0);
assert!(pad([0u8; 476]).len() % 16 == 0);
// check some simple cases
assert_eq!(vec![16u8; 16], pad([]));
assert_eq!(
vec![0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15],
pad([0u8])
);
}
#[test]
fn md2_checksum() {
assert_eq!(
vec![
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 98, 56, 103, 182,
175, 82, 121, 94, 95, 33, 78, 151, 32, 190, 234, 141
],
checksum(vec![16u8; 16])
);
assert_eq!(
vec![
0u8, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 41, 224, 10, 216,
109, 48, 122, 164, 206, 220, 139, 100, 42, 212, 254, 68
],
checksum(vec![
0u8, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15
])
);
}
#[test]
fn md2_hash() {
assert_eq!(
"a9046c73e00331af68917d3804f70655",
hash(b"hello").to_string()
);
assert_eq!("8350e5a3e24c153df2275c9f80692773", hash(b"").to_string());
assert_eq!("32ec01ec4a6dac72c0ab96fb34c0b5d1", hash(b"a").to_string());
assert_eq!("da853b0d3f88d99b30283a69e6ded6bb", hash(b"abc").to_string());
assert_eq!(
"03d85a0d629d2c442e987525319fc471",
hash(b"The quick brown fox jumps over the lazy dog").to_string()
);
}
}

239
src/hash/md4.rs Normal file
View File

@ -0,0 +1,239 @@
use crate::hash::{bytes_to_words_le, words_to_bytes_le, Digest};
// based on RFC1320
const A: u32 = 0x67452301;
const B: u32 = 0xefcdab89;
const C: u32 = 0x98badcfe;
const D: u32 = 0x10325476;
// additional constants for round 1, 2 & 3
const C1: u32 = 0;
const C2: u32 = 0x5a827999;
const C3: u32 = 0x6ed9eba1;
// shifts & indices for each step
const S: [u32; 48] = [
3, 7, 11, 19, 3, 7, 11, 19, 3, 7, 11, 19, 3, 7, 11, 19, 3, 5, 9, 13, 3, 5, 9, 13, 3, 5, 9, 13,
3, 5, 9, 13, 3, 9, 11, 15, 3, 9, 11, 15, 3, 9, 11, 15, 3, 9, 11, 15,
];
const W: [usize; 48] = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14,
3, 7, 11, 15, 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15,
];
// round functions
const F: fn(u32, u32, u32) -> u32 = |x, y, z| (x & y) | (!x & z);
const G: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| (x & y) | (x & z) | (y & z);
const H: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| x ^ y ^ z;
// pad the message to next 512-bit interval
pub(crate) fn pad(message: impl AsRef<[u8]>) -> Vec<u8> {
let mut message = message.as_ref().to_vec();
let message_length = message.len().wrapping_mul(8) as u64;
// add 1 bit (le)
message.push(0x80);
// add 0 bits until length in bits is congruent to 448 mod 512
while (message.len()) % 64 != 56 {
message.push(0u8)
}
// append message length (64 bits)
message.extend(message_length.to_le_bytes());
message
}
// compute an invidiual step in the md4 algorithm
fn step([mut a, b, c, d]: [u32; 4], words: &[u32], index: usize) -> [u32; 4] {
// choose function and constant based on which round is currently active
let (rc, f) = match index {
0..=15 => (C1, F),
16..=31 => (C2, G),
32..=47 => (C3, H),
_ => panic!("This function shouldn't be called using an index outside 0..48"),
};
// main operation
a = f(b, c, d)
.wrapping_add(a)
.wrapping_add(words[W[index]])
.wrapping_add(rc)
.rotate_left(S[index]);
[a, b, c, d]
}
/// Compute the MD4 hash of the input bytes
/// # Examples
/// ```
/// let input = "abc";
/// let digest = lore::md4(input);
///
/// assert_eq!(digest.to_string(), "a448017aaf21d8525fc10ae87aa6729d");
/// ```
pub fn hash(message: impl AsRef<[u8]>) -> Digest<16> {
let padded = pad(message);
let buffer = padded.array_chunks::<64>().map(bytes_to_words_le).fold(
[A, B, C, D],
|[a, b, c, d], words| {
// perform rounds on this chunk of data
let mut state = [a, b, c, d];
for i in 0..48 {
state = step(state, &words, i);
state.rotate_right(1);
}
[
a.wrapping_add(state[0]),
b.wrapping_add(state[1]),
c.wrapping_add(state[2]),
d.wrapping_add(state[3]),
]
},
);
let digest = *words_to_bytes_le(buffer)
.array_chunks::<16>()
.next()
.unwrap();
Digest(digest)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn md4_pad() {
assert_eq!(pad([1u8]).len() % 64, 0);
assert_eq!(pad([1u8; 63]).len() % 64, 0);
assert_eq!(pad([1u8; 65]).len() % 64, 0);
assert_eq!(pad([1u8; 511]).len() % 64, 0);
assert_eq!(pad([1u8; 512]).len() % 64, 0);
assert_eq!(pad([1u8; 513]).len() % 64, 0);
assert_eq!(pad([1u8; 4472]).len() % 64, 0);
assert_eq!(
vec![
0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
],
pad([1u8])
);
}
#[test]
fn md4_hash() {
assert_eq!(
"1bee69a46ba811185c194762abaeae90",
hash("The quick brown fox jumps over the lazy dog").to_string()
);
assert_eq!(
"b86e130ce7028da59e672d56ad0113df",
hash("The quick brown fox jumps over the lazy cog").to_string()
);
assert_eq!("31d6cfe0d16ae931b73c59d7e0c089c0", hash("").to_string());
// RFC 1320 test suite
assert_eq!(hash("").to_string(), "31d6cfe0d16ae931b73c59d7e0c089c0");
assert_eq!(hash("a").to_string(), "bde52cb31de33e46245e05fbdbd6fb24");
assert_eq!(hash("abc").to_string(), "a448017aaf21d8525fc10ae87aa6729d");
assert_eq!(
hash("message digest").to_string(),
"d9130a8164549fe818874806e1c7014b"
);
assert_eq!(
hash("abcdefghijklmnopqrstuvwxyz").to_string(),
"d79e1c308aa5bbcdeea8ed63df412da9"
);
assert_eq!(
hash("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789").to_string(),
"043f8582f241db351ce627e153e7f0e4"
);
assert_eq!(
hash(
"12345678901234567890123456789012345678901234567890123456789012345678901234567890"
)
.to_string(),
"e33b4ddc9c38f2199c3e7b164fcc0536"
);
assert_eq!(
hash("Rosetta Code").to_string(),
"a52bcfc6a0d0d300cdc5ddbfbefe478b"
)
}
#[test]
fn md4_steps() {
let expected: [[u32; 4]; 48] = [
[0x2b9b7a8b, 0xefcdab89, 0x98badcfe, 0x10325476],
[0x1ebbf3f6, 0x2b9b7a8b, 0xefcdab89, 0x98badcfe],
[0xf636674f, 0x1ebbf3f6, 0x2b9b7a8b, 0xefcdab89],
[0x3e787c49, 0xf636674f, 0x1ebbf3f6, 0x2b9b7a8b],
[0x127b1453, 0x3e787c49, 0xf636674f, 0x1ebbf3f6],
[0x9c35a18a, 0x127b1453, 0x3e787c49, 0xf636674f],
[0x7e1c9145, 0x9c35a18a, 0x127b1453, 0x3e787c49],
[0x0adad780, 0x7e1c9145, 0x9c35a18a, 0x127b1453],
[0x85c62aed, 0x0adad780, 0x7e1c9145, 0x9c35a18a],
[0x881a850b, 0x85c62aed, 0x0adad780, 0x7e1c9145],
[0xf71e7006, 0x881a850b, 0x85c62aed, 0x0adad780],
[0x135c5da7, 0xf71e7006, 0x881a850b, 0x85c62aed],
[0x0727d7d9, 0x135c5da7, 0xf71e7006, 0x881a850b],
[0x9b7d493d, 0x0727d7d9, 0x135c5da7, 0xf71e7006],
[0x1e300fd2, 0x9b7d493d, 0x0727d7d9, 0x135c5da7],
[0xb60174a1, 0x1e300fd2, 0x9b7d493d, 0x0727d7d9],
[0x2a7873ab, 0xb60174a1, 0x1e300fd2, 0x9b7d493d],
[0x86074f26, 0x2a7873ab, 0xb60174a1, 0x1e300fd2],
[0x68021c3d, 0x86074f26, 0x2a7873ab, 0xb60174a1],
[0xc9ad2750, 0x68021c3d, 0x86074f26, 0x2a7873ab],
[0x6b1b8763, 0xc9ad2750, 0x68021c3d, 0x86074f26],
[0x329a0609, 0x6b1b8763, 0xc9ad2750, 0x68021c3d],
[0x3f3a2e5c, 0x329a0609, 0x6b1b8763, 0xc9ad2750],
[0x34e64be9, 0x3f3a2e5c, 0x329a0609, 0x6b1b8763],
[0x0de3f443, 0x34e64be9, 0x3f3a2e5c, 0x329a0609],
[0x5fddbd79, 0x0de3f443, 0x34e64be9, 0x3f3a2e5c],
[0x494abd6f, 0x5fddbd79, 0x0de3f443, 0x34e64be9],
[0x9069bba6, 0x494abd6f, 0x5fddbd79, 0x0de3f443],
[0x0d815e5e, 0x9069bba6, 0x494abd6f, 0x5fddbd79],
[0x753ed018, 0x0d815e5e, 0x9069bba6, 0x494abd6f],
[0xee224d71, 0x753ed018, 0x0d815e5e, 0x9069bba6],
[0xd232eb01, 0xee224d71, 0x753ed018, 0x0d815e5e],
[0x57e97dc9, 0xd232eb01, 0xee224d71, 0x753ed018],
[0x252ee4a0, 0x57e97dc9, 0xd232eb01, 0xee224d71],
[0x8d5bd7ef, 0x252ee4a0, 0x57e97dc9, 0xd232eb01],
[0x92942054, 0x8d5bd7ef, 0x252ee4a0, 0x57e97dc9],
[0x38475e43, 0x92942054, 0x8d5bd7ef, 0x252ee4a0],
[0x22f47377, 0x38475e43, 0x92942054, 0x8d5bd7ef],
[0xe6878422, 0x22f47377, 0x38475e43, 0x92942054],
[0x5ab5fed1, 0xe6878422, 0x22f47377, 0x38475e43],
[0x32463ee3, 0x5ab5fed1, 0xe6878422, 0x22f47377],
[0x85465040, 0x32463ee3, 0x5ab5fed1, 0xe6878422],
[0xb801aa18, 0x85465040, 0x32463ee3, 0x5ab5fed1],
[0xd796ec48, 0xb801aa18, 0x85465040, 0x32463ee3],
[0x5f8a08a4, 0xd796ec48, 0xb801aa18, 0x85465040],
[0x7b15aa48, 0x5f8a08a4, 0xd796ec48, 0xb801aa18],
[0x2722e8cf, 0x7b15aa48, 0x5f8a08a4, 0xd796ec48],
[0x11062517, 0x2722e8cf, 0x7b15aa48, 0x5f8a08a4],
];
// perform first step of md4 round 1
let words: [u32; 16] = [
0x65736f52, 0x20617474, 0x65646f43, 0x00000080, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000060, 0x00000000,
];
let mut state: [u32; 4] = [A, B, C, D];
#[allow(clippy::needless_range_loop)]
for i in 0..48 {
state = step(state, &words, i);
assert_eq!(expected[i], state);
state.rotate_right(1);
}
}
}

197
src/hash/md5.rs Normal file
View File

@ -0,0 +1,197 @@
use crate::hash::{bytes_to_words_le, md4::pad, words_to_bytes_le, Digest};
// based on RFC1321
const A: u32 = 0x67452301;
const B: u32 = 0xefcdab89;
const C: u32 = 0x98badcfe;
const D: u32 = 0x10325476;
const K: [u32; 64] = [
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
];
// shifts & indices for each step
const S: [u32; 64] = [
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9,
14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15,
21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
];
const W: [usize; 64] = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8,
13, 2, 7, 12, 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, 0, 7, 14, 5, 12, 3, 10, 1,
8, 15, 6, 13, 4, 11, 2, 9,
];
// round functions
const F: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| (x & y) | (!x & z);
const G: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| (x & z) | (y & !z);
const H: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| x ^ y ^ z;
const I: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| y ^ (x | !z);
fn step([mut a, b, c, d]: [u32; 4], words: &[u32], index: usize) -> [u32; 4] {
let f = match index {
0..=15 => F,
16..=31 => G,
32..=47 => H,
48..=63 => I,
_ => panic!("This function shouldn't be called using an index outside 0..48"),
};
a = f(b, c, d)
.wrapping_add(a)
.wrapping_add(words[W[index]])
.wrapping_add(K[index])
.rotate_left(S[index])
.wrapping_add(b);
[a, b, c, d]
}
/// Compute the MD5 hash of the input bytes
/// # Examples
/// ```
/// let input = "lol";
/// let digest = lore::md5(input);
///
/// assert_eq!(digest.to_string(), "9cdfb439c7876e703e307864c9167a15");
/// ```
pub fn hash(message: impl AsRef<[u8]>) -> Digest<16> {
let padded = pad(message);
let buffer = padded.array_chunks::<64>().map(bytes_to_words_le).fold(
[A, B, C, D],
|[a, b, c, d], words| {
println!("{words:08x?}");
let mut state = [a, b, c, d];
for i in 0..64 {
state = step(state, &words, i);
println!("{state:08x?}");
state.rotate_right(1);
}
[
a.wrapping_add(state[0]),
b.wrapping_add(state[1]),
c.wrapping_add(state[2]),
d.wrapping_add(state[3]),
]
},
);
let digest = *words_to_bytes_le(buffer)
.array_chunks::<16>()
.next()
.unwrap();
Digest(digest)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn md5_hash() {
assert_eq!("d41d8cd98f00b204e9800998ecf8427e", hash("").to_string());
assert_eq!(
"73e51861b65c1e83d6136fb6a002585e",
hash("tihi xd").to_string()
);
assert_eq!("9cdfb439c7876e703e307864c9167a15", hash("lol").to_string());
assert_eq!(
"fd6f92edff2b7db7cd92b494c4926ef0",
hash("Lorem ipsum dolor sit amet. Nam placeat iste aut dolorem necessitatibus sit unde magni. Nam cumque quia nam fugit quibusdam ut incidunt minima nam dignissimos iusto et voluptatum magnam. Et pariatur eius vel excepturi odit libero sit molestiae consequatur vel nostrum ullam. Sit sint beatae eos doloribus sapiente aut aperiam ullam ut laboriosam debitis! Qui reiciendis rerum est omnis galisum aut similique iure est dolores fuga sit rerum dicta. Aut excepturi fuga et enim ipsum a quia ut velit atque id iste nobis. Non molestiae vero et veritatis aliquam sed enim ducimus. At sunt tempora quo quisquam unde aut ipsum nulla et fugit eius in nulla fugit qui magnam excepturi aut rerum officia. Et officia magnam eos reiciendis voluptatum ea voluptas recusandae in similique enim. Ut provident laudantium ut temporibus eius ut laudantium voluptate aut ducimus impedit. Et asperiores aperiam sit deleniti voluptas ex porro omnis ut voluptas assumenda aut necessitatibus aliquid.").to_string()
);
}
#[test]
fn md5_steps() {
let expected: [[u32; 4]; 64] = [
[0x5954a129, 0xefcdab89, 0x98badcfe, 0x10325476],
[0x3171555d, 0x5954a129, 0xefcdab89, 0x98badcfe],
[0x24368ecc, 0x3171555d, 0x5954a129, 0xefcdab89],
[0x1d414db3, 0x24368ecc, 0x3171555d, 0x5954a129],
[0x9da81fec, 0x1d414db3, 0x24368ecc, 0x3171555d],
[0x983a9b4c, 0x9da81fec, 0x1d414db3, 0x24368ecc],
[0x01f76eec, 0x983a9b4c, 0x9da81fec, 0x1d414db3],
[0x82251f6b, 0x01f76eec, 0x983a9b4c, 0x9da81fec],
[0x3648b77a, 0x82251f6b, 0x01f76eec, 0x983a9b4c],
[0xa57749ed, 0x3648b77a, 0x82251f6b, 0x01f76eec],
[0x69859a5a, 0xa57749ed, 0x3648b77a, 0x82251f6b],
[0x8dd64e23, 0x69859a5a, 0xa57749ed, 0x3648b77a],
[0x4cc08388, 0x8dd64e23, 0x69859a5a, 0xa57749ed],
[0x9a1db095, 0x4cc08388, 0x8dd64e23, 0x69859a5a],
[0xf3a1ec18, 0x9a1db095, 0x4cc08388, 0x8dd64e23],
[0x68bf5f16, 0xf3a1ec18, 0x9a1db095, 0x4cc08388],
[0x08cf03db, 0x68bf5f16, 0xf3a1ec18, 0x9a1db095],
[0x03bceaa0, 0x08cf03db, 0x68bf5f16, 0xf3a1ec18],
[0x2809715f, 0x03bceaa0, 0x08cf03db, 0x68bf5f16],
[0xc305e2e6, 0x2809715f, 0x03bceaa0, 0x08cf03db],
[0x0386e9c7, 0xc305e2e6, 0x2809715f, 0x03bceaa0],
[0x0f4c9f59, 0x0386e9c7, 0xc305e2e6, 0x2809715f],
[0x8814e065, 0x0f4c9f59, 0x0386e9c7, 0xc305e2e6],
[0xd8d052d2, 0x8814e065, 0x0f4c9f59, 0x0386e9c7],
[0x8ff59707, 0xd8d052d2, 0x8814e065, 0x0f4c9f59],
[0x4069945d, 0x8ff59707, 0xd8d052d2, 0x8814e065],
[0x213a0570, 0x4069945d, 0x8ff59707, 0xd8d052d2],
[0xf2affb96, 0x213a0570, 0x4069945d, 0x8ff59707],
[0x555223a9, 0xf2affb96, 0x213a0570, 0x4069945d],
[0x37ba19ca, 0x555223a9, 0xf2affb96, 0x213a0570],
[0x003749f2, 0x37ba19ca, 0x555223a9, 0xf2affb96],
[0x20617338, 0x003749f2, 0x37ba19ca, 0x555223a9],
[0xf3e971ee, 0x20617338, 0x003749f2, 0x37ba19ca],
[0x4ec4ee85, 0xf3e971ee, 0x20617338, 0x003749f2],
[0xe62bf9a6, 0x4ec4ee85, 0xf3e971ee, 0x20617338],
[0x0ae8a02f, 0xe62bf9a6, 0x4ec4ee85, 0xf3e971ee],
[0xbc31561a, 0x0ae8a02f, 0xe62bf9a6, 0x4ec4ee85],
[0x6a9f6576, 0xbc31561a, 0x0ae8a02f, 0xe62bf9a6],
[0x42e91ea3, 0x6a9f6576, 0xbc31561a, 0x0ae8a02f],
[0x7a181668, 0x42e91ea3, 0x6a9f6576, 0xbc31561a],
[0xedcc403b, 0x7a181668, 0x42e91ea3, 0x6a9f6576],
[0x1fcae4da, 0xedcc403b, 0x7a181668, 0x42e91ea3],
[0x217c84d1, 0x1fcae4da, 0xedcc403b, 0x7a181668],
[0xf02591fa, 0x217c84d1, 0x1fcae4da, 0xedcc403b],
[0x5375b853, 0xf02591fa, 0x217c84d1, 0x1fcae4da],
[0xecd77499, 0x5375b853, 0xf02591fa, 0x217c84d1],
[0x4bd1053f, 0xecd77499, 0x5375b853, 0xf02591fa],
[0x7625a818, 0x4bd1053f, 0xecd77499, 0x5375b853],
[0xf7223b53, 0x7625a818, 0x4bd1053f, 0xecd77499],
[0x2e422a17, 0xf7223b53, 0x7625a818, 0x4bd1053f],
[0xe5235245, 0x2e422a17, 0xf7223b53, 0x7625a818],
[0x8e8a212d, 0xe5235245, 0x2e422a17, 0xf7223b53],
[0x551950d2, 0x8e8a212d, 0xe5235245, 0x2e422a17],
[0xf067530c, 0x551950d2, 0x8e8a212d, 0xe5235245],
[0xdb4e97cc, 0xf067530c, 0x551950d2, 0x8e8a212d],
[0x5b429768, 0xdb4e97cc, 0xf067530c, 0x551950d2],
[0xb0c06d7a, 0x5b429768, 0xdb4e97cc, 0xf067530c],
[0xd1906cf3, 0xb0c06d7a, 0x5b429768, 0xdb4e97cc],
[0x3fc74ed9, 0xd1906cf3, 0xb0c06d7a, 0x5b429768],
[0xa6b24624, 0x3fc74ed9, 0xd1906cf3, 0xb0c06d7a],
[0xf9d3c272, 0xa6b24624, 0x3fc74ed9, 0xd1906cf3],
[0x4e25ae2a, 0xf9d3c272, 0xa6b24624, 0x3fc74ed9],
[0x1db436d8, 0x4e25ae2a, 0xf9d3c272, 0xa6b24624],
[0x9350b12d, 0x1db436d8, 0x4e25ae2a, 0xf9d3c272],
];
let words: [u32; 16] = [
0x69686974, 0x80647820, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000038, 0x00000000,
];
let mut state = [A, B, C, D];
#[allow(clippy::needless_range_loop)]
for i in 0..64 {
state = step(state, &words, i);
assert_eq!(expected[i], state);
state.rotate_right(1);
}
}
}

7
src/hash/sha1.rs Normal file
View File

@ -0,0 +1,7 @@
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sha1() {}
}

View File

@ -1 +1,7 @@
pub mod md5;
#![feature(array_chunks)]
mod hash;
pub use hash::md2::hash as md2;
pub use hash::md4::hash as md4;
pub use hash::md5::hash as md5;

View File

@ -1,205 +0,0 @@
use std::convert::TryInto;
// round functions as defined in RFC1321
const F: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| (x & y) | (!x & z);
const G: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| (x & z) | (y & !z);
const H: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| x ^ y ^ z;
const I: fn(u32, u32, u32) -> u32 = |x: u32, y: u32, z: u32| y ^ (x | !z);
// constants used in RFC132
const K: [u32; 64] = [
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
];
// shifts per round
const S: [u32; 64] = [
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9,
14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15,
21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21,
];
pub struct Hash([u32; 4]);
impl Hash {
pub fn to_hex_string(&self) -> String {
format!(
"{:08x}{:08x}{:08x}{:08x}",
self.0[0], self.0[1], self.0[2], self.0[3]
)
}
}
fn preprocess(msg: impl AsRef<[u8]>) -> Vec<u8> {
let mut message = msg.as_ref().to_vec();
let len_in_bits = message.len().wrapping_mul(8) as u64;
// padding
// add one bit first (le), then pad with zeroes
message.push(0b10000000);
while (message.len() * 8) % 512 != 448 {
message.push(0u8);
}
// append length
message.extend(len_in_bits.to_le_bytes());
message
}
#[inline(always)]
fn op(
function: impl Fn(u32, u32, u32) -> u32,
state: (u32, u32, u32, u32),
word: u32,
index: usize,
) -> u32 {
function(state.1, state.2, state.3)
.wrapping_add(state.0)
.wrapping_add(word)
.wrapping_add(K[index])
.rotate_left(S[index])
.wrapping_add(state.1)
}
pub fn hash(input: impl AsRef<[u8]>) -> Hash {
let (a, b, c, d) = preprocess(input).chunks_exact(64).fold(
(0x67452301u32, 0xefcdab89u32, 0x98badcfeu32, 0x10325476u32),
|(mut a0, mut b0, mut c0, mut d0), chunk| {
let mut words = [0u32; 16];
for (word, c) in words.iter_mut().zip(chunk.chunks_exact(4)) {
*word = u32::from_le_bytes(c.try_into().unwrap());
}
let (mut a, mut b, mut c, mut d) = (a0, b0, c0, d0);
// round 1
a = op(F, (a, b, c, d), words[0], 0);
d = op(F, (d, a, b, c), words[1], 1);
c = op(F, (c, d, a, b), words[2], 2);
b = op(F, (b, c, d, a), words[3], 3);
a = op(F, (a, b, c, d), words[4], 4);
d = op(F, (d, a, b, c), words[5], 5);
c = op(F, (c, d, a, b), words[6], 6);
b = op(F, (b, c, d, a), words[7], 7);
a = op(F, (a, b, c, d), words[8], 8);
d = op(F, (d, a, b, c), words[9], 9);
c = op(F, (c, d, a, b), words[10], 10);
b = op(F, (b, c, d, a), words[11], 11);
a = op(F, (a, b, c, d), words[12], 12);
d = op(F, (d, a, b, c), words[13], 13);
c = op(F, (c, d, a, b), words[14], 14);
b = op(F, (b, c, d, a), words[15], 15);
// round 2
a = op(G, (a, b, c, d), words[1], 16);
d = op(G, (d, a, b, c), words[6], 17);
c = op(G, (c, d, a, b), words[11], 18);
b = op(G, (b, c, d, a), words[0], 19);
a = op(G, (a, b, c, d), words[5], 20);
d = op(G, (d, a, b, c), words[10], 21);
c = op(G, (c, d, a, b), words[15], 22);
b = op(G, (b, c, d, a), words[4], 23);
a = op(G, (a, b, c, d), words[9], 24);
d = op(G, (d, a, b, c), words[14], 25);
c = op(G, (c, d, a, b), words[3], 26);
b = op(G, (b, c, d, a), words[8], 27);
a = op(G, (a, b, c, d), words[13], 28);
d = op(G, (d, a, b, c), words[2], 29);
c = op(G, (c, d, a, b), words[7], 30);
b = op(G, (b, c, d, a), words[12], 31);
// round 3
a = op(H, (a, b, c, d), words[5], 32);
d = op(H, (d, a, b, c), words[8], 33);
c = op(H, (c, d, a, b), words[11], 34);
b = op(H, (b, c, d, a), words[14], 35);
a = op(H, (a, b, c, d), words[1], 36);
d = op(H, (d, a, b, c), words[4], 37);
c = op(H, (c, d, a, b), words[7], 38);
b = op(H, (b, c, d, a), words[10], 39);
a = op(H, (a, b, c, d), words[13], 40);
d = op(H, (d, a, b, c), words[0], 41);
c = op(H, (c, d, a, b), words[3], 42);
b = op(H, (b, c, d, a), words[6], 43);
a = op(H, (a, b, c, d), words[9], 44);
d = op(H, (d, a, b, c), words[12], 45);
c = op(H, (c, d, a, b), words[15], 46);
b = op(H, (b, c, d, a), words[2], 47);
// round 4
a = op(I, (a, b, c, d), words[0], 48);
d = op(I, (d, a, b, c), words[7], 49);
c = op(I, (c, d, a, b), words[14], 50);
b = op(I, (b, c, d, a), words[5], 51);
a = op(I, (a, b, c, d), words[12], 52);
d = op(I, (d, a, b, c), words[3], 53);
c = op(I, (c, d, a, b), words[10], 54);
b = op(I, (b, c, d, a), words[1], 55);
a = op(I, (a, b, c, d), words[8], 56);
d = op(I, (d, a, b, c), words[15], 57);
c = op(I, (c, d, a, b), words[6], 58);
b = op(I, (b, c, d, a), words[13], 59);
a = op(I, (a, b, c, d), words[4], 60);
d = op(I, (d, a, b, c), words[11], 61);
c = op(I, (c, d, a, b), words[2], 62);
b = op(I, (b, c, d, a), words[9], 63);
a0 = a0.wrapping_add(a);
b0 = b0.wrapping_add(b);
c0 = c0.wrapping_add(c);
d0 = d0.wrapping_add(d);
(a0, b0, c0, d0)
},
);
Hash([
a.swap_bytes(),
b.swap_bytes(),
c.swap_bytes(),
d.swap_bytes(),
])
}
#[cfg(test)]
mod tests {
use crate::md5;
#[test]
fn md5() {
assert_eq!(
"73e51861b65c1e83d6136fb6a002585e",
md5::hash("tihi xd").to_hex_string()
);
assert_eq!(
"9cdfb439c7876e703e307864c9167a15",
md5::hash("lol").to_hex_string()
);
assert_eq!(
"d41d8cd98f00b204e9800998ecf8427e",
md5::hash("").to_hex_string()
);
assert_eq!("fd6f92edff2b7db7cd92b494c4926ef0", md5::hash("Lorem ipsum dolor sit amet. Nam placeat iste aut dolorem necessitatibus sit unde magni. Nam cumque quia nam fugit quibusdam ut incidunt minima nam dignissimos iusto et voluptatum magnam. Et pariatur eius vel excepturi odit libero sit molestiae consequatur vel nostrum ullam. Sit sint beatae eos doloribus sapiente aut aperiam ullam ut laboriosam debitis! Qui reiciendis rerum est omnis galisum aut similique iure est dolores fuga sit rerum dicta. Aut excepturi fuga et enim ipsum a quia ut velit atque id iste nobis. Non molestiae vero et veritatis aliquam sed enim ducimus. At sunt tempora quo quisquam unde aut ipsum nulla et fugit eius in nulla fugit qui magnam excepturi aut rerum officia. Et officia magnam eos reiciendis voluptatum ea voluptas recusandae in similique enim. Ut provident laudantium ut temporibus eius ut laudantium voluptate aut ducimus impedit. Et asperiores aperiam sit deleniti voluptas ex porro omnis ut voluptas assumenda aut necessitatibus aliquid.").to_hex_string());
}
}