diff --git a/Cargo.lock b/Cargo.lock index c9214d8..a7c14c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "anstream" version = "0.6.14" @@ -51,12 +60,58 @@ dependencies = [ "windows-sys", ] +[[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.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[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.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "bitflags", + "textwrap", + "unicode-width", +] + [[package]] name = "clap" version = "4.5.9" @@ -112,19 +167,145 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +[[package]] +name = "criterion" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +dependencies = [ + "atty", + "cast", + "clap 2.34.0", + "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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "csv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "env_logger" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "half" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" + [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "idea" -version = "0.2.0" +version = "1.0.0" dependencies = [ - "clap", + "clap 4.5.9", "clap-num", + "criterion", "modinverse", + "quickcheck", ] [[package]] @@ -133,6 +314,54 @@ version = "1.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + [[package]] name = "modinverse" version = "0.1.1" @@ -160,6 +389,46 @@ dependencies = [ "autocfg", ] +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "oorandom" +version = "11.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" + +[[package]] +name = "plotters" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" + +[[package]] +name = "plotters-svg" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" +dependencies = [ + "plotters-backend", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -169,6 +438,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quickcheck" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" +dependencies = [ + "env_logger", + "log", + "rand", +] + [[package]] name = "quote" version = "1.0.36" @@ -178,6 +458,129 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[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 = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", +] + +[[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.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "strsim" version = "0.11.1" @@ -195,18 +598,154 @@ dependencies = [ "unicode-ident", ] +[[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-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +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.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-sys" version = "0.52.0" diff --git a/Cargo.toml b/Cargo.toml index 51de580..0c46f39 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,11 @@ edition = "2021" clap = { version = "4.0", features = ["derive"] } clap-num = { version = "1.1" } modinverse = { version = "0.1" } + +[dev-dependencies] +criterion = "0.3" +quickcheck = "1.0.3" + +[[bench]] +name = "idea_timing_benchmark" +harness = false diff --git a/benches/idea_timing_benchmark.rs b/benches/idea_timing_benchmark.rs new file mode 100644 index 0000000..cd60301 --- /dev/null +++ b/benches/idea_timing_benchmark.rs @@ -0,0 +1,16 @@ +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use idea::{decrypt, encrypt}; + +pub fn criterion_benchmark(c: &mut Criterion) { + c.bench_function("encrypt ", |b| { + b.iter(|| { + encrypt( + black_box(0x9d31ccc9ce639084e2f1f70541285b8d), + black_box(0xba431a8cfda88c8f), + ) + }) + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..c3ece9f --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,218 @@ +use modinverse::modinverse; + +struct Vr { + v1: u16, + v2: u16, + v3: u16, + v4: u16, +} + +impl Vr { + fn split(v: u64) -> Self { + let v4 = (v & 0xFFFF) as u16; + let v3 = ((v >> 16) & 0xFFFF) as u16; + let v2 = ((v >> 32) & 0xFFFF) as u16; + let v1 = ((v >> 48) & 0xFFFF) as u16; + Self { + v1: v1, + v2: v2, + v3: v3, + v4: v4, + } + } + + fn expand(&self) -> u64 { + (self.v1 as u64 * 2_u64.pow(48)) + + (self.v2 as u64 * 2_u64.pow(32)) + + (self.v3 as u64 * 2_u64.pow(16)) + + self.v4 as u64 + } +} + +struct Keys { + z1: u16, + z2: u16, + z3: u16, + z4: u16, + z5: u16, + z6: u16, +} + +fn derive_keys(mut k: u128) -> Vec { + let mut keys: Vec = Vec::new(); + + let mut subkeys = Vec::new(); + while subkeys.len() < 52 { + subkeys.push((k & 0xFFFF) as u16); + subkeys.push(((k >> 16) & 0xFFFF) as u16); + subkeys.push(((k >> 32) & 0xFFFF) as u16); + subkeys.push(((k >> 48) & 0xFFFF) as u16); + subkeys.push(((k >> 64) & 0xFFFF) as u16); + subkeys.push(((k >> 80) & 0xFFFF) as u16); + subkeys.push(((k >> 96) & 0xFFFF) as u16); + subkeys.push(((k >> 112) & 0xFFFF) as u16); + k = k.rotate_left(25); + } + let mut i = 0; + while keys.len() < 8 { + keys.push(Keys { + z1: subkeys[0 + i], + z2: subkeys[1 + i], + z3: subkeys[2 + i], + z4: subkeys[3 + i], + z5: subkeys[4 + i], + z6: subkeys[5 + i], + }); + i = i + 1; + } + keys.push(Keys { + z1: subkeys[0 + i], + z2: subkeys[1 + i], + z3: subkeys[2 + i], + z4: subkeys[3 + i], + z5: 0, + z6: 0, + }); + keys +} + +fn add(a: u16, b: u16) -> u16 { + let (a, b, m) = (a as i32, b as i32, 0x10000 as i32); + ((a + b) % m) as u16 +} + +// 0010 0110 % 10001 -> 0010 * (-0001) + 0110 -> 0110 +fn slow_mul(a: u16, b: u16) -> u16 { + let (a, b, m) = (a as u32, b as u32, 0x10001 as u32); + let a = if a == 0 {0x10000} else {a}; + let b = if b == 0 {0x10000} else {b}; + ((a * b) % m) as u16 +} + +fn mul(a: u16, b: u16) -> u16 { + let (a, b) = (a as u32, b as u32); + if a == 0 && b == 0 { return 1 } + let a = if a == 0 { 0x10000 } else { a }; + let b = if b == 0 { 0x10000 } else { b }; + let ab = a * b; + let ab_high = ab >> 16; + let ab_low = ab & 0xffff; + let m = if ab_high > ab_low { 0x10001 } else { 0 }; + (ab_low + m - ab_high) as u16 +} + +fn idea_round(ks: &Keys, xs: Vr) -> Vr { + let u1 = mul(ks.z1, xs.v1); + let u2 = mul(ks.z2, xs.v2); + let u3 = add(ks.z3, xs.v3); + let u4 = add(ks.z4, xs.v4); + let u13 = u1 ^ u3; + let u24 = u2 ^ u4; + let u5 = mul(ks.z5, u13); + let c1 = mul(ks.z6, add(u24, u5)); + let c2 = add(u5, c1); + Vr { + v1: c1 ^ u3, + v2: c2 ^ u4, + v3: c1 ^ u1, + v4: c2 ^ u2, + } +} + +fn idea_finish(ks: &Keys, xs: Vr) -> Vr { + let u1 = mul(ks.z1, xs.v1); + let u2 = mul(ks.z2, xs.v2); + let u3 = add(ks.z3, xs.v3); + let u4 = add(ks.z4, xs.v4); + Vr { + v1: u1, + v2: u2, + v3: u3, + v4: u4, + } +} + +fn invert_keys(ks: &Keys, z5: u16, z6: u16) -> Keys { + let mut z1 = ks.z1 as i32; + let mut z2 = ks.z2 as i32; + if ks.z1 == 0 { + z1 = 0x010000 as i32; + } + if ks.z2 == 0 { + z2 = 0x010000 as i32; + } + Keys { + z1: modinverse(z1 as i32, 0x0010001 as i32).expect("Modular inverse of z1 doesn't exist!") + as u16, + z2: modinverse(z2 as i32, 0x0010001 as i32).expect("Modular inverse of z2 doesn't exist!") + as u16, + z3: (0x10000 as u32 - ks.z3 as u32) as u16, + z4: (0x10000 as u32 - ks.z4 as u32) as u16, + z5: z5, + z6: z6, + } +} + +pub fn encrypt(k: u128, m: u64) -> u64 { + let xr = Vr::split(m); + assert_eq!(m, xr.expand()); + // Derive keys + let kr = derive_keys(k); + + let mut bs = xr; + let mut i = 0; + while i < 8 { + // println!("Round {i}:"); + bs = idea_round(&kr[i], bs); + // println!("intermediate result: {:?}\n", bs.expand()); + i = i + 1; + } + let ys = idea_finish(&kr[8], bs); + ys.expand() +} + +pub fn decrypt(k: u128, m: u64) -> u64 { + let xr = Vr::split(m); + assert_eq!(m, xr.expand()); + // Derive and invert keys + let kr = derive_keys(k); + let mut dr: Vec = Vec::new(); + let mut i = 8; + while i > 0 { + let ds = invert_keys(&kr[i], kr[i - 1].z5, kr[i - 1].z6); + i = i - 1; + dr.push(ds); + } + let ds = invert_keys(&kr[0], 0, 0); + dr.push(ds); + + let mut bs = xr; + while i < 8 { + // println!("Round {i}:"); + bs = idea_round(&dr[i], bs); + // println!("intermediate result: {:?}\n", bs.expand()); + i = i + 1; + } + let ys = idea_finish(&dr[8], bs); + ys.expand() +} + +#[cfg(test)] +#[macro_use] +extern crate quickcheck; +#[cfg(test)] +mod tests { + use super::{decrypt, encrypt}; + quickcheck! { + fn decrypt_encrypt(ks: u128, mes: u64) -> bool { + mes == decrypt(ks, encrypt(ks, mes)) + } + } + + use super::{slow_mul, mul}; + quickcheck! { + fn correct_mul(a: u16, b: u16) -> bool { + mul(a, b) == slow_mul(a, b) + } + } +} diff --git a/src/main.rs b/src/main.rs index 4f36a88..fa9acc8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,12 @@ -// ca 5h +// ca 5h initial coding use clap::Parser; +use clap::ArgAction; use clap_num::maybe_hex; -use modinverse::modinverse; +use idea::{decrypt, encrypt}; +use std::cmp::min; +use std::io::BufRead; +use std::io::Write; #[derive(Parser)] struct Cli { @@ -12,177 +16,57 @@ struct Cli { // the key used for encryption/decryption #[arg(short = 'k', long = "key", value_parser=maybe_hex::, default_value_t = 123456789012345678901234567890)] key: u128, + #[clap(long = "decrypt", short = 'd', action=ArgAction::SetFalse)] + decrypt: bool, } -struct Vr { - v1: u16, - v2: u16, - v3: u16, - v4: u16, -} - -impl Vr { - fn split(v: u64) -> Self { - let v4 = (v & 0xFFFF) as u16; - let v3 = ((v >> 16) & 0xFFFF) as u16; - let v2 = ((v >> 32) & 0xFFFF) as u16; - let v1 = ((v >> 48) & 0xFFFF) as u16; - Self{ v1: v1, v2: v2, v3: v3, v4: v4 } - } - - fn expand(&self) -> u64 { - (self.v1 as u64 * 2_u64.pow(48)) + (self.v2 as u64 * 2_u64.pow(32)) + (self.v3 as u64 * 2_u64.pow(16)) + self.v4 as u64 - } -} - -struct Keys { - z1: u16, z2: u16, z3: u16, z4: u16, z5: u16, z6: u16, -} - - -fn derive_keys(mut k: u128) -> Vec { - let mut keys: Vec = Vec::new(); - - let mut subkeys = Vec::new(); - while subkeys.len() < 52 { - subkeys.push((k & 0xFFFF) as u16); - subkeys.push(((k >> 16) & 0xFFFF) as u16); - subkeys.push(((k >> 32) & 0xFFFF) as u16); - subkeys.push(((k >> 48) & 0xFFFF) as u16); - subkeys.push(((k >> 64) & 0xFFFF) as u16); - subkeys.push(((k >> 80) & 0xFFFF) as u16); - subkeys.push(((k >> 96) & 0xFFFF) as u16); - subkeys.push(((k >> 112) & 0xFFFF) as u16); - k = k.rotate_left(25); - } - let mut i = 0; - while keys.len() < 8 { - keys.push( - Keys{ z1: subkeys[0+i], z2: subkeys[1+i], z3: subkeys[2+i], z4: subkeys[3+i], z5: subkeys[4+i], z6: subkeys[5+i] } - ); - i = i+1; - } - keys.push( - Keys{ z1: subkeys[0+i], z2: subkeys[1+i], z3: subkeys[2+i], z4: subkeys[3+i], z5: 0, z6: 0 } - ); - keys -} - -fn add(a: u16, b: u16) -> u16 { - let (a, b, m) = (a as i32, b as i32, 0x10000 as i32); - ((a + b) % m) as u16 -} - -fn mul(a: u16, b: u16) -> u16 { - let (a, b, m) = (a as u32, b as u32, 0x10001 as u32); - if a == 0 { - let a = 0x10000; - ((a * b) % m) as u16 - } - else if b == 0 { - let b = 0x10000; - ((a * b) % m) as u16 - } - else{ - ((a * b) % m) as u16 - } -} - -fn idea_round(ks: &Keys, xs: Vr) -> Vr { - let u1 = mul(ks.z1, xs.v1); - let u2 = mul(ks.z2, xs.v2); - let u3 = add(ks.z3, xs.v3); - let u4 = add(ks.z4, xs.v4); - let u13 = u1 ^ u3; - let u24 = u2 ^ u4; - let u5 = mul(ks.z5, u13); - let c1 = mul(ks.z6, add(u24, u5)); - let c2 = add(u5, c1); - Vr { v1: c1 ^ u3, v2: c2 ^ u4, v3: c1 ^ u1, v4: c2 ^ u2 } -} - -fn idea_finish(ks: &Keys, xs: Vr) -> Vr { - let u1 = mul(ks.z1, xs.v1); - let u2 = mul(ks.z2, xs.v2); - let u3 = add(ks.z3, xs.v3); - let u4 = add(ks.z4, xs.v4); - Vr { v1: u1, v2: u2, v3: u3, v4: u4 } -} - -fn invert_keys(ks: &Keys, z5: u16, z6: u16) -> Keys { - let mut z1 = ks.z1 as i32; - let mut z2 = ks.z2 as i32; - if ks.z1 == 0 { - z1 = 0x010000 as i32; - } - if ks.z2 == 0 { - z2 = 0x010000 as i32; - } - Keys { - z1: modinverse(z1 as i32, 0x0010001 as i32).expect("Modular inverse of z1 doesn't exist!") as u16, - z2: modinverse(z2 as i32, 0x0010001 as i32).expect("Modular inverse of z2 doesn't exist!") as u16, - z3: (0x10000 as u32 - ks.z3 as u32) as u16, - z4: (0x10000 as u32 - ks.z4 as u32) as u16, - z5: z5, - z6: z6 } -} - -fn encrypt(k: u128, m: u64) -> u64 { - let xr = Vr::split(m); - assert_eq!(m, xr.expand()); - // Derive keys - let kr = derive_keys(k); - - let mut bs = xr; - let mut i = 0; - while i < 8 { - println!("Round {i}:"); - bs = idea_round(&kr[i], bs); - println!("intermediate result: {:?}\n", bs.expand()); - i = i+1; - } - let ys = idea_finish(&kr[8], bs); - ys.expand() -} - -fn decrypt(k: u128, m: u64) -> u64 { - let xr = Vr::split(m); - assert_eq!(m, xr.expand()); - // Derive and invert keys - let kr = derive_keys(k); - let mut dr: Vec = Vec::new(); - let mut i = 8; - while i > 0 { - let ds = invert_keys(&kr[i], kr[i-1].z5, kr[i-1].z6); - i = i-1; - dr.push(ds); - } - let ds = invert_keys(&kr[0], 0, 0); - dr.push(ds); - - let mut bs = xr; - while i < 8 { - println!("Round {i}:"); - bs = idea_round(&dr[i], bs); - println!("intermediate result: {:?}\n", bs.expand()); - i = i+1; - } - let ys = idea_finish(&dr[8], bs); - ys.expand() -} - -fn main() { - println!("Welcome to your IDEA encryption tool!\n"); - +fn main() -> Result<(), Box> { let args = Cli::parse(); let key: u128 = args.key; - let key2: u128 = args.key; - let message: u64 = args.message; - - println!("message: {:?}, key: {:?}\n", message, key); - - let cipher: u64 = encrypt(key, message); - println!("Ciphertext: {:?}\n", cipher); - let plain: u64 = decrypt(key2, cipher); - println!("Computed plaintext: {:?}", plain); + // let message: u64 = args.message; + // println!("message: {:?}, key: {:?}\n", message, key); + + let zeros = [0,0,0,0,0,0,0,0]; + let mut inp = std::io::stdin().lock(); + let mut out = std::io::stdout(); + let mut buf: Vec = vec![0u8; 4096]; + let mut amt = 0; + loop { + while amt < 8 { + let buff = inp.fill_buf()?; + if buff.is_empty() { + break; + } + let to_copy = min(buf.len() - amt, buff.len()); + buf[amt..(amt + to_copy)].copy_from_slice(&buff[0..to_copy]); + amt += to_copy; + inp.consume(to_copy); + } + if amt < 8 { + let pad = 8 - amt; + buf[amt..8].copy_from_slice(&zeros[0..pad]); + amt += pad; + } + let mut offset = 0; + while amt >= offset + 8 { + let array: [u8; 8] = buf[offset..offset + 8].try_into().unwrap(); + let plain = u64::from_le_bytes(array); + let cipher: u64; + if args.decrypt { + cipher = decrypt(key, plain); + } + else { + cipher = encrypt(key, plain); + } + out.write_all(&cipher.to_le_bytes())?; + offset += 8; + } + buf.copy_within(offset..amt, 0); + amt = amt - offset; + if amt == 0 { + return Ok(()); + } + } } + +// diff --git a/test0 b/test0 new file mode 100644 index 0000000..405b033 Binary files /dev/null and b/test0 differ