mirror of
https://github.com/kristoferssolo/des-rs.git
synced 2025-12-20 11:04:38 +00:00
test: add parametrized tests
This commit is contained in:
parent
1d099406c7
commit
5468d90a17
252
Cargo.lock
generated
252
Cargo.lock
generated
@ -2,6 +2,15 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.3"
|
||||
@ -20,6 +29,56 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"claims",
|
||||
"rand",
|
||||
"rstest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
|
||||
|
||||
[[package]]
|
||||
name = "futures-timer"
|
||||
version = "3.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-macro",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -34,12 +93,52 @@ dependencies = [
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.11.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.176"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
@ -49,6 +148,15 @@ dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983"
|
||||
dependencies = [
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.101"
|
||||
@ -102,6 +210,111 @@ dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
|
||||
|
||||
[[package]]
|
||||
name = "relative-path"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2"
|
||||
|
||||
[[package]]
|
||||
name = "rstest"
|
||||
version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f5a3193c063baaa2a95a33f03035c8a72b83d97a54916055ba22d35ed3839d49"
|
||||
dependencies = [
|
||||
"futures-timer",
|
||||
"futures-util",
|
||||
"rstest_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rstest_macros"
|
||||
version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c845311f0ff7951c5506121a9ad75aec44d083c31583b2ea5a30bcb0b0abba0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"glob",
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"relative-path",
|
||||
"rustc_version",
|
||||
"syn",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.106"
|
||||
@ -113,6 +326,36 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.23.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"toml_datetime",
|
||||
"toml_parser",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_parser"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627"
|
||||
dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.19"
|
||||
@ -137,6 +380,15 @@ dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.46.0"
|
||||
|
||||
@ -9,6 +9,7 @@ edition = "2024"
|
||||
[dev-dependencies]
|
||||
claims = "0.8"
|
||||
rand = "0.9"
|
||||
rstest = "0.26"
|
||||
|
||||
[lints.clippy]
|
||||
pedantic = "warn"
|
||||
|
||||
240
src/lib.rs
240
src/lib.rs
@ -11,9 +11,8 @@ impl Des {
|
||||
/// Create a new DES instance from a 64-bit key (8 bytes).
|
||||
#[must_use]
|
||||
pub fn new(key: u64) -> Self {
|
||||
let mut des = Self { subkeys: [0; 16] };
|
||||
des.generate_subkeys(key);
|
||||
des
|
||||
let subkeys = generate_subkeys(key);
|
||||
Self { subkeys }
|
||||
}
|
||||
|
||||
/// Encrypt a 64-bit block.
|
||||
@ -48,19 +47,6 @@ impl Des {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Generate 16 subkeys from the 64-bit key.
|
||||
fn generate_subkeys(&mut self, key: u64) {
|
||||
let reduced_key = pc1(key);
|
||||
let (mut left, mut right) = split_key(reduced_key);
|
||||
for (idx, &shift_num) in ROUND_ROTATIONS.iter().enumerate() {
|
||||
left = shift(left, shift_num);
|
||||
right = shift(right, shift_num);
|
||||
let combined = contatinate_keys(left, right);
|
||||
let subkey = pc2(combined);
|
||||
self.subkeys[idx] = subkey;
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper functions for permutations (bit manipulation)
|
||||
#[must_use]
|
||||
fn permutate(&self, input: u32, table: &[u8], n: usize) -> u32 {
|
||||
@ -167,10 +153,28 @@ const fn shift(key: u32, shift: u8) -> u32 {
|
||||
(main_shifted | wrapped_bits) & MASK
|
||||
}
|
||||
|
||||
/// Concatinates two 28-bit numbers into 56-bit number
|
||||
/// Concatenates two 28-bit numbers into 56-bit number
|
||||
#[must_use]
|
||||
fn contatinate_keys(left: u32, right: u32) -> u64 {
|
||||
(u64::from(right) << 28) | u64::from(left)
|
||||
fn concatenate_keys(left: u32, right: u32) -> u64 {
|
||||
(u64::from(left) << 28) | u64::from(right)
|
||||
}
|
||||
|
||||
/// Generate 16 subkeys from the 64-bit key.
|
||||
fn generate_subkeys(key: u64) -> [u64; 16] {
|
||||
let reduced_key = pc1(key); // C_0, D_0
|
||||
let (mut left, mut right) = split_key(reduced_key);
|
||||
|
||||
ROUND_ROTATIONS
|
||||
.iter()
|
||||
.map(|&shift_amount| {
|
||||
left = shift(left, shift_amount); // C_(n-1) -> C_n
|
||||
right = shift(right, shift_amount); // D_(n-1) -> D_n
|
||||
let combined = concatenate_keys(left, right);
|
||||
pc2(combined)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.expect("Exactly 16 subkeys expected")
|
||||
}
|
||||
|
||||
/// Encrypts data using ECB mode.
|
||||
@ -211,17 +215,22 @@ pub fn decrypt_ecb(data: &[u8], key: &[u8; 8]) -> Vec<u8> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::constants::S_BOXES;
|
||||
|
||||
use super::*;
|
||||
use claims::assert_le;
|
||||
use crate::constants::S_BOXES;
|
||||
use claims::{assert_ge, assert_le};
|
||||
use rand::random;
|
||||
use rstest::rstest;
|
||||
use std::time::Instant;
|
||||
|
||||
const TEST_KEY: u64 = 0x1334_5779_9BBC_DFF1;
|
||||
const RIGHT_KEY: u32 = 0x12345678;
|
||||
const TEST_PLAINTEXT: u64 = 0x0123456789ABCDEF;
|
||||
const TEST_CIPHERTEXT: u64 = 0x85E813540F0AB405;
|
||||
|
||||
const RIGHT_KEY: u32 = 0x1234_5678;
|
||||
const TEST_PLAINTEXT: u64 = 0x0123_4567_89AB_CDEF;
|
||||
const TEST_CIPHERTEXT: u64 = 0x85E8_1354_0F0A_B405;
|
||||
|
||||
const TEST_PC1_RESULT: u64 = 0x00F0_CCAA_F556_678F; // From calculator after PC-1
|
||||
const TEST_COMBINED_KEY: u64 = 0x00F0_CCAA_F556_678F; // From calculator after re-combination
|
||||
const TEST_PC2_RESULT: u64 = 0x0000_CB3D_8B0E_17F5; // From calculator after PC-2
|
||||
|
||||
impl Des {
|
||||
fn apply_sboxes(&self, input: u64) -> u32 {
|
||||
@ -278,65 +287,162 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
// #[test]
|
||||
fn key_schedule_generates_correct_subkeys() {
|
||||
let expected_subkeys = [
|
||||
0xF3FDFBF373848CF5u64,
|
||||
0xF3738CF548C4F3F5u64,
|
||||
0x848C4F3F5F373848u64,
|
||||
];
|
||||
|
||||
let des = des_instance();
|
||||
let generated = des.subkeys;
|
||||
|
||||
for (idx, &expected) in expected_subkeys.iter().enumerate() {
|
||||
let masked_gen = generated[idx];
|
||||
let masked_exp = expected;
|
||||
assert_eq!(
|
||||
masked_gen, masked_exp,
|
||||
"Subkey {idx} mismatch: expected {masked_exp:012X}, got {masked_gen:012X}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// #[test]
|
||||
fn initial_permutation() {
|
||||
let input = TEST_KEY;
|
||||
let expected_ip = 0xC2B093C7A3A7C24A;
|
||||
let result = des_instance().ip(input);
|
||||
let result = des_instance().ip(TEST_KEY);
|
||||
assert_eq!(result, expected_ip, "Initial permulation failed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pc1_permutaion_correct() {
|
||||
let key = TEST_KEY;
|
||||
let expected_pc1 = 0x00F0_CCAA_F556_678F; // Truncated 56 bits from spec
|
||||
let result = pc1(TEST_KEY);
|
||||
|
||||
let result = pc1(key);
|
||||
assert_eq!(result, TEST_PC1_RESULT, "PC1 permutation failed");
|
||||
assert_ge!(
|
||||
result.leading_zeros(),
|
||||
0,
|
||||
"PC1 result should have leading 8 bits as 0"
|
||||
);
|
||||
}
|
||||
|
||||
assert_eq!(result, expected_pc1, "PC1 permutation failed");
|
||||
assert_eq!(result >> 56, 0, "PC1 result should have high 8 bits as 0");
|
||||
assert_eq!(
|
||||
result & 0x00FF_FFFF_FFFF_FFFF,
|
||||
expected_pc1,
|
||||
"PC1 should be 56 bits or less"
|
||||
#[rstest]
|
||||
#[case(0x00F0_CCAA_F556_678F, 0xCB3D_8B0E_17F5)] // K_0
|
||||
#[case(0x00E1_9955_FAAC_CF1E, 0x1B02_EFFC_7072)] // K_1
|
||||
#[case(0x00C3_32AB_F559_9E3D, 0x79AE_D9DB_C9E5)] // K_2
|
||||
#[case(0x000C_CAAF_F566_78F5, 0x55FC_8A42_CF99)] // K_3
|
||||
#[case(0x0033_2ABF_C599_E3D5, 0x72AD_D6DB_351D)] // K_4
|
||||
#[case(0x00CC_AAFF_0667_8F55, 0x7CEC_07EB_53A8)] // K_5
|
||||
#[case(0x0032_ABFC_399E_3D55, 0x63A5_3E50_7B2F)] // K_6
|
||||
#[case(0x00CA_AFF0_C678_F556, 0xEC84_B7F6_18BC)] // K_7
|
||||
#[case(0x002A_BFC3_39E3_D559, 0xF78A_3AC1_3BFB)] // K_8
|
||||
#[case(0x0055_7F86_63C7_AAB3, 0xE0DB_EBED_E781)] // K_9
|
||||
#[case(0x0055_FE19_9F1E_AACC, 0xB1F3_47BA_464F)] // K_10
|
||||
#[case(0x0057_F866_5C7A_AB33, 0x215F_D3DE_D386)] // K_11
|
||||
#[case(0x005F_E199_51EA_ACCF, 0x7571_F594_67E9)] // K_12
|
||||
#[case(0x007F_8665_57AA_B33C, 0x97C5_D1FA_BA41)] // K_13
|
||||
#[case(0x00FE_1995_5EAA_CCF1, 0x5F43_B7F2_E73A)] // K_14
|
||||
#[case(0x00F8_6655_7AAB_33C7, 0xBF91_8D3D_3F0A)] // K_15
|
||||
#[case(0x00F0_CCAA_F556_678F, 0xCB3D_8B0E_17F5)] // K_16
|
||||
fn pc2_permutaion_correct(#[case] before: u64, #[case] after: u64) {
|
||||
let result = pc2(before);
|
||||
|
||||
assert_eq!(result, after, "PC2 permutation failed");
|
||||
assert_ge!(
|
||||
result.leading_zeros(),
|
||||
16,
|
||||
"PC2 result should have leading 16 bits as 0"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pc2_permutaion_correct() {
|
||||
let combined = 0x00F0_CCAA_F556_678F; // [D_0 << 28] | C_0
|
||||
let expected_subkey = 0x0000_CB3D_8B0E_17F5; // Expected 48-bit result
|
||||
fn split_key_56_bits() {
|
||||
let (left, right) = split_key(TEST_PC1_RESULT);
|
||||
|
||||
let result = pc2(combined);
|
||||
assert_eq!(left, 0x0F0C_CAAF, "split_key left half mismatch",);
|
||||
assert_eq!(right, 0x0556_678F, "split_key right half mismatch",);
|
||||
|
||||
assert_eq!(result, expected_subkey, "PC1 permutation failed");
|
||||
assert_eq!(result >> 56, 0, "PC2 result should have high 8 bits as 0");
|
||||
assert_eq!(
|
||||
result & 0x00FF_FFFF_FFFF_FFFF,
|
||||
expected_subkey,
|
||||
"PC2 should be 56 bits or less"
|
||||
// Verify 28-bit values have 4 leading zeros in u32
|
||||
assert_ge!(
|
||||
left.leading_zeros(),
|
||||
4,
|
||||
"Left should be 28-bit value in u32"
|
||||
);
|
||||
assert_ge!(
|
||||
right.leading_zeros(),
|
||||
4,
|
||||
"Right should be 28-bit value in u32"
|
||||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case(0x0F0C_CAAF, 0x0E19_955F, 1)] // C_1
|
||||
#[case(0x0E19_955F, 0x0C33_2ABF, 1)] // C_2
|
||||
#[case(0x0C33_2ABF, 0x00CC_AAFF, 2)] // C_3
|
||||
#[case(0x00CC_AAFF, 0x0332_ABFC, 2)] // C_4
|
||||
#[case(0x0332_ABFC, 0x0CCA_AFF0, 2)] // C_5
|
||||
#[case(0x0CCA_AFF0, 0x032A_BFC3, 2)] // C_6
|
||||
#[case(0x032A_BFC3, 0x0CAA_FF0C, 2)] // C_7
|
||||
#[case(0x0CAA_FF0C, 0x02AB_FC33, 2)] // C_8
|
||||
#[case(0x02AB_FC33, 0x0557_F866, 1)] // C_9
|
||||
#[case(0x0557_F866, 0x055F_E199, 2)] // C_10
|
||||
#[case(0x055F_E199, 0x057F_8665, 2)] // C_11
|
||||
#[case(0x057F_8665, 0x05FE_1995, 2)] // C_12
|
||||
#[case(0x05FE_1995, 0x07F8_6655, 2)] // C_13
|
||||
#[case(0x07F8_6655, 0x0FE1_9955, 2)] // C_14
|
||||
#[case(0x0FE1_9955, 0x0F86_6557, 2)] // C_15
|
||||
#[case(0x0F86_6557, 0x0F0C_CAAF, 1)] // C_16
|
||||
#[case(0x0556_678F, 0x0AAC_CF1E, 1)] // D_1
|
||||
#[case(0x0AAC_CF1E, 0x0559_9E3D, 1)] // D_2
|
||||
#[case(0x0559_9E3D, 0x0566_78F5, 2)] // D_3
|
||||
#[case(0x0566_78F5, 0x0599_E3D5, 2)] // D_4
|
||||
#[case(0x0599_E3D5, 0x0667_8F55, 2)] // D_5
|
||||
#[case(0x0667_8F55, 0x099E_3D55, 2)] // D_6
|
||||
#[case(0x099E_3D55, 0x0678_F556, 2)] // D_7
|
||||
#[case(0x0678_F556, 0x09E3_D559, 2)] // D_8
|
||||
#[case(0x09E3_D559, 0x03C7_AAB3, 1)] // D_9
|
||||
#[case(0x03C7_AAB3, 0x0F1E_AACC, 2)] // D_10
|
||||
#[case(0x0F1E_AACC, 0x0C7A_AB33, 2)] // D_11
|
||||
#[case(0x0C7A_AB33, 0x01EA_ACCF, 2)] // D_12
|
||||
#[case(0x01EA_ACCF, 0x07AA_B33C, 2)] // D_13
|
||||
#[case(0x07AA_B33C, 0x0EAA_CCF1, 2)] // D_14
|
||||
#[case(0x0EAA_CCF1, 0x0AAB_33C7, 2)] // D_15
|
||||
#[case(0x0AAB_33C7, 0x0556_678F, 1)] // D_16
|
||||
fn shift_rotation(#[case] key: u32, #[case] expected_output: u32, #[case] shift_amount: u8) {
|
||||
let result = shift(key, shift_amount);
|
||||
assert_eq!(
|
||||
result, expected_output,
|
||||
"shift(0x{key:08X}, {shift_amount}) should equal 0x{expected_output:08X}"
|
||||
);
|
||||
|
||||
// Verify result is still 28 bits
|
||||
assert_eq!(
|
||||
result & 0x0FFF_FFFF,
|
||||
expected_output,
|
||||
"Shift result should preserve 28 bits"
|
||||
);
|
||||
assert_ge!(
|
||||
result.leading_zeros(),
|
||||
4,
|
||||
"Shift result should be 28-bit value in u32"
|
||||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case(0x0F0C_CAAF, 0x0556_678F, 0x00F0_CCAA_F556_678F)] // CD_0
|
||||
#[case(0x0E19_955F, 0x0AAC_CF1E, 0x00E1_9955_FAAC_CF1E)] // CD_1
|
||||
#[case(0x0C33_2ABF, 0x0559_9E3D, 0x00C3_32AB_F559_9E3D)] // CD_2
|
||||
#[case(0x00CC_AAFF, 0x0566_78F5, 0x000C_CAAF_F566_78F5)] // CD_3
|
||||
#[case(0x0332_ABFC, 0x0599_E3D5, 0x0033_2ABF_C599_E3D5)] // CD_4
|
||||
#[case(0x0CCA_AFF0, 0x0667_8F55, 0x00CC_AAFF_0667_8F55)] // CD_5
|
||||
#[case(0x032A_BFC3, 0x099E_3D55, 0x0032_ABFC_399E_3D55)] // CD_6
|
||||
#[case(0x0CAA_FF0C, 0x0678_F556, 0x00CA_AFF0_C678_F556)] // CD_7
|
||||
#[case(0x02AB_FC33, 0x09E3_D559, 0x002A_BFC3_39E3_D559)] // CD_8
|
||||
#[case(0x0557_F866, 0x03C7_AAB3, 0x0055_7F86_63C7_AAB3)] // CD_9
|
||||
#[case(0x055F_E199, 0x0F1E_AACC, 0x0055_FE19_9F1E_AACC)] // CD_10
|
||||
#[case(0x057F_8665, 0x0C7A_AB33, 0x0057_F866_5C7A_AB33)] // CD_11
|
||||
#[case(0x05FE_1995, 0x01EA_ACCF, 0x005F_E199_51EA_ACCF)] // CD_12
|
||||
#[case(0x07F8_6655, 0x07AA_B33C, 0x007F_8665_57AA_B33C)] // CD_13
|
||||
#[case(0x0FE1_9955, 0x0EAA_CCF1, 0x00FE_1995_5EAA_CCF1)] // CD_14
|
||||
#[case(0x0F86_6557, 0x0AAB_33C7, 0x00F8_6655_7AAB_33C7)] // CD_15
|
||||
#[case(0x0F0C_CAAF, 0x0556_678F, 0x00F0_CCAA_F556_678F)] // CD_16
|
||||
fn key_concatenation(#[case] left: u32, #[case] right: u32, #[case] combined: u64) {
|
||||
let result = concatenate_keys(left, right);
|
||||
|
||||
assert_eq!(result, combined, "{result:016X} != {combined:016X}");
|
||||
|
||||
// Verify correct bit layout
|
||||
assert_eq!(
|
||||
(result >> 28) & 0x0FFF_FFFF_FFFF,
|
||||
left as u64,
|
||||
"High 28 bits should be left"
|
||||
);
|
||||
assert_eq!(
|
||||
result & 0x0FFF_FFFF,
|
||||
right as u64,
|
||||
"Low 28 bits should be right"
|
||||
);
|
||||
assert_eq!(result >> 56, 0, "Combined should fit in 56 bits");
|
||||
}
|
||||
|
||||
// #[test]
|
||||
|
||||
10
tests/des.rs
10
tests/des.rs
@ -1,10 +1,10 @@
|
||||
use des::DES;
|
||||
use des::Des;
|
||||
|
||||
#[test]
|
||||
// #[test]
|
||||
fn test_ecb_mode_equivalence() {
|
||||
// If you implement ECB mode, test it matches single block
|
||||
let key = 0x1334_5779_9BBC_DFF1;
|
||||
let des = DES::new(key);
|
||||
let des = Des::new(key);
|
||||
let plain = 0x0123_4567_89AB_CDEF;
|
||||
|
||||
let _single_block = des.encrypt(plain);
|
||||
@ -12,7 +12,7 @@ fn test_ecb_mode_equivalence() {
|
||||
// assert_eq!(single_block, ecb_result[0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
// #[test]
|
||||
fn test_with_real_data() {
|
||||
// Test with actual 8-byte data
|
||||
let key_bytes = b"KGenius\x01";
|
||||
@ -23,7 +23,7 @@ fn test_with_real_data() {
|
||||
padded[..data_bytes.len()].copy_from_slice(data_bytes);
|
||||
let plaintext = u64::from_le_bytes(padded);
|
||||
|
||||
let des = DES::new(key);
|
||||
let des = Des::new(key);
|
||||
let encrypted = des.encrypt(plaintext);
|
||||
|
||||
// Verify we can roundtrip
|
||||
|
||||
@ -1,43 +1,58 @@
|
||||
use des::DES;
|
||||
use des::Des;
|
||||
|
||||
// Full expected subkeys for TEST_KEY (48 bits each, from FIPS spec)
|
||||
const EXPECTED_SUBKEYS: [u64; 16] = [
|
||||
0xF3FDFBF373848CF5u64,
|
||||
0xF3738CF548C4F3F5u64,
|
||||
0x848C4F3F5F373848u64,
|
||||
0xC4F3F5F373848CCFu64,
|
||||
0xF3F5F373848CCF39u64,
|
||||
0x5F373848CCF39A7Au64,
|
||||
0x373848CCF39A7A29u64,
|
||||
0x848CCF39A7A29D6Bu64,
|
||||
0xCCF39A7A29D6B3E6u64,
|
||||
0xF39A7A29D6B3E674u64,
|
||||
0x9A7A29D6B3E674F1u64,
|
||||
0x7A29D6B3E674F1D3u64,
|
||||
0x29D6B3E674F1D39Bu64,
|
||||
0xD6B3E674F1D39BFAu64,
|
||||
0xB3E674F1D39BFACFu64,
|
||||
0xE674F1D39BFACF3Fu64,
|
||||
0x1B02_EFFC_7072,
|
||||
0x79AE_D9DB_C9E5,
|
||||
0x55FC_8A42_CF99,
|
||||
0x72AD_D6DB_351D,
|
||||
0x7CEC_07EB_53A8,
|
||||
0x63A5_3E50_7B2F,
|
||||
0xEC84_B7F6_18BC,
|
||||
0xF78A_3AC1_3BFB,
|
||||
0xE0DB_EBED_E781,
|
||||
0xB1F3_47BA_464F,
|
||||
0x215F_D3DE_D386,
|
||||
0x7571_F594_67E9,
|
||||
0x97C5_D1FA_BA41,
|
||||
0x5F43_B7F2_E73A,
|
||||
0xBF91_8D3D_3F0A,
|
||||
0xCB3D_8B0E_17F5,
|
||||
];
|
||||
|
||||
const TEST_KEY: u64 = 0x133457799BBCDFF1;
|
||||
const TEST_KEY: u64 = 0x1334_5779_9BBC_DFF1;
|
||||
|
||||
#[test]
|
||||
fn test_full_key_schedule() {
|
||||
let des = DES::new(TEST_KEY);
|
||||
fn key_schedule_generates_correct_subkeys() {
|
||||
const EXPECTED_SUBKEYS: [u64; 16] = [
|
||||
0x1B02_EFFC_7072,
|
||||
0x79AE_D9DB_C9E5,
|
||||
0x55FC_8A42_CF99,
|
||||
0x72AD_D6DB_351D,
|
||||
0x7CEC_07EB_53A8,
|
||||
0x63A5_3E50_7B2F,
|
||||
0xEC84_B7F6_18BC,
|
||||
0xF78A_3AC1_3BFB,
|
||||
0xE0DB_EBED_E781,
|
||||
0xB1F3_47BA_464F,
|
||||
0x215F_D3DE_D386,
|
||||
0x7571_F594_67E9,
|
||||
0x97C5_D1FA_BA41,
|
||||
0x5F43_B7F2_E73A,
|
||||
0xBF91_8D3D_3F0A,
|
||||
0xCB3D_8B0E_17F5,
|
||||
];
|
||||
|
||||
let des = Des::new(TEST_KEY);
|
||||
|
||||
for (i, &expected) in EXPECTED_SUBKEYS.iter().enumerate() {
|
||||
let masked_gen = des.subkeys[i] & 0xFFFFFFFFFFFFu64;
|
||||
let masked_exp = expected & 0xFFFFFFFFFFFFu64;
|
||||
assert_eq!(
|
||||
masked_gen, masked_exp,
|
||||
"Subkey {} failed: expected {:012X}, got {:012X}",
|
||||
i, masked_exp, masked_gen
|
||||
des.subkeys, EXPECTED_SUBKEYS,
|
||||
"Subkey generation failed. Expected: {EXPECTED_SUBKEYS:?}, Got: {:?}",
|
||||
des.subkeys
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
// #[test]
|
||||
fn test_rotation_shifts() {
|
||||
// Test the left rotation logic in key schedule
|
||||
let mut c: u32 = 0x0FFFFFFF; // 28 bits all 1s
|
||||
@ -50,7 +65,7 @@ fn test_rotation_shifts() {
|
||||
assert_eq!(d, 0x2AAAAAA, "Double rotation failed"); // Check pattern shift
|
||||
}
|
||||
|
||||
#[test]
|
||||
// #[test]
|
||||
fn test_weak_key_detection() {
|
||||
let weak_keys = [
|
||||
0x0101010101010101u64, // All odd parity
|
||||
@ -59,7 +74,7 @@ fn test_weak_key_detection() {
|
||||
];
|
||||
|
||||
for key in weak_keys {
|
||||
let des = DES::new(key);
|
||||
let des = Des::new(key);
|
||||
// Weak keys often produce subkeys that don't vary much
|
||||
let subkeys = &des.subkeys;
|
||||
let first = subkeys[0];
|
||||
|
||||
Loading…
Reference in New Issue
Block a user