mirror of
https://github.com/kristoferssolo/des-rs.git
synced 2025-12-20 11:04:38 +00:00
test: pass all tests
This commit is contained in:
parent
bd5a5748d1
commit
509b6a92aa
@ -1,6 +1,6 @@
|
|||||||
mod constants;
|
mod constants;
|
||||||
|
|
||||||
use crate::constants::{E_BOX, IP, PC1_TABLE, PC2_TABLE, P_BOX, ROUND_ROTATIONS, S_BOXES};
|
use crate::constants::{E_BOX, FP, IP, PC1_TABLE, PC2_TABLE, P_BOX, ROUND_ROTATIONS, S_BOXES};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Des {
|
pub struct Des {
|
||||||
@ -39,7 +39,7 @@ impl Des {
|
|||||||
process_feistel_rounds(permutated_block, &reversed_subkeys)
|
process_feistel_rounds(permutated_block, &reversed_subkeys)
|
||||||
};
|
};
|
||||||
|
|
||||||
let combined = concatenate_halves(right, left, 64);
|
let combined = concatenate_halves(right, left, 32);
|
||||||
fp(combined)
|
fp(combined)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,9 +97,10 @@ const fn shift(key: u32, shift: u8) -> u32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Concatenates two `input_bits`-bit numbers into 2*`input_bits`-bit number
|
/// Concatenates two `input_bits`-bit numbers into 2*`input_bits`-bit number
|
||||||
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn concatenate_halves(left: u32, right: u32, input_bits: u32) -> u64 {
|
fn concatenate_halves(left: u32, right: u32, bit_offset: u8) -> u64 {
|
||||||
(u64::from(left) << input_bits) | u64::from(right)
|
(u64::from(left) << bit_offset) | u64::from(right)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate 16 subkeys from the 64-bit key.
|
/// Generate 16 subkeys from the 64-bit key.
|
||||||
@ -152,12 +153,14 @@ fn permutate(input: u64, input_bits: u32, output_bits: u32, position_table: &[u8
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn ip(message: u64) -> u64 {
|
fn ip(message: u64) -> u64 {
|
||||||
permutate(message, 64, 64, &IP)
|
permutate(message, 64, 64, &IP)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expand the right side of the data from 32 bits to 48.
|
/// Expand the right side of the data from 32 bits to 48.
|
||||||
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn expansion_permutation(right: u32) -> u64 {
|
fn expansion_permutation(right: u32) -> u64 {
|
||||||
permutate(u64::from(right), 32, 48, &E_BOX)
|
permutate(u64::from(right), 32, 48, &E_BOX)
|
||||||
@ -181,14 +184,16 @@ fn s_box_substitution(block: u64) -> u32 {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn p_box_permutation(input: u32) -> u32 {
|
fn p_box_permutation(input: u32) -> u32 {
|
||||||
u32::try_from(permutate(u64::from(input), 32, 32, &P_BOX)).expect("32-bit value")
|
u32::try_from(permutate(u64::from(input), 32, 32, &P_BOX)).expect("32-bit value")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn fp(input: u64) -> u64 {
|
pub fn fp(block: u64) -> u64 {
|
||||||
todo!()
|
permutate(block, 64, 64, &FP)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process 16 Feistel rounds for ECB encryption/decryption.
|
/// Process 16 Feistel rounds for ECB encryption/decryption.
|
||||||
@ -199,7 +204,7 @@ fn process_feistel_rounds(initial_block: u64, subkeys: &[u64]) -> (u32, u32) {
|
|||||||
(left, right) = feistel(left, right, subkey);
|
(left, right) = feistel(left, right, subkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
(right, left) // left and right should be swapped
|
(left, right)
|
||||||
}
|
}
|
||||||
/// Feistel function: Expand, XOR with subkey, S-box, permute.
|
/// Feistel function: Expand, XOR with subkey, S-box, permute.
|
||||||
/// `R_i` = `L_(i-1)` XOR f(`R_(i-1)`, `K_1`)
|
/// `R_i` = `L_(i-1)` XOR f(`R_(i-1)`, `K_1`)
|
||||||
@ -209,9 +214,10 @@ fn feistel(left: u32, right: u32, subkey: u64) -> (u32, u32) {
|
|||||||
let new_right = left ^ function_output;
|
let new_right = left ^ function_output;
|
||||||
// L_i = R_(i-1)
|
// L_i = R_(i-1)
|
||||||
let new_left = right;
|
let new_left = right;
|
||||||
(new_right, new_left)
|
(new_left, new_right)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn f_function(right: u32, subkey: u64) -> u32 {
|
fn f_function(right: u32, subkey: u64) -> u32 {
|
||||||
let expanded = expansion_permutation(right);
|
let expanded = expansion_permutation(right);
|
||||||
let xored = expanded ^ subkey;
|
let xored = expanded ^ subkey;
|
||||||
@ -222,26 +228,27 @@ fn f_function(right: u32, subkey: u64) -> u32 {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::constants::S_BOXES;
|
use claims::assert_ge;
|
||||||
use claims::{assert_ge, assert_le};
|
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
const TEST_KEY: u64 = 0x1334_5779_9BBC_DFF1;
|
const TEST_KEY: u64 = 0x1334_5779_9BBC_DFF1;
|
||||||
|
|
||||||
const TEST_PLAINTEXT: u64 = 0x0123_4567_89AB_CDEF;
|
const TEST_PLAINTEXT: u64 = 0x0123_4567_89AB_CDEF;
|
||||||
const TEST_CIPHERTEXT: u64 = 0x85E8_1354_0F0A_B405;
|
const TEST_CIPHERTEXT: u64 = 0x85E8_1354_0F0A_B405;
|
||||||
|
|
||||||
const TEST_PC1_RESULT: u64 = 0x00F0_CCAA_F556_678F; // From calculator after PC-1
|
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
|
|
||||||
|
|
||||||
#[test]
|
/// Helper to create a test Des instance (use your actual key schedule)
|
||||||
fn initial_permutation() {
|
fn des_instance() -> Des {
|
||||||
let expected_ip = 0xCC00_CCFF_F0AA_F0AA;
|
Des::new(TEST_KEY)
|
||||||
let result = ip(TEST_PLAINTEXT);
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(TEST_PLAINTEXT, 0xCC00_CCFF_F0AA_F0AA)]
|
||||||
|
fn initial_permutation(#[case] input: u64, #[case] output: u64) {
|
||||||
|
let result = ip(input);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result, expected_ip,
|
result, output,
|
||||||
"Initial permulation failed expected 0x{expected_ip:016X}, got 0x{result:016X}"
|
"Initial permutation failed. Expected 0x{output:016X}, got 0x{result:016X}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,4 +482,36 @@ mod tests {
|
|||||||
let result = p_box_permutation(block);
|
let result = p_box_permutation(block);
|
||||||
assert_eq!(result, output, "Expected {output:08X}, got {result:08X}");
|
assert_eq!(result, output, "Expected {output:08X}, got {result:08X}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(0x0A4C_D995_4342_3234, 0x85E8_1354_0F0A_B405)]
|
||||||
|
fn final_permutation(#[case] input: u64, #[case] output: u64) {
|
||||||
|
let result = fp(input);
|
||||||
|
assert_eq!(
|
||||||
|
result, output,
|
||||||
|
"Final permutation failed. Expected 0x{output:016X}, got 0x{result:016X}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn encrypt_decrypt_roundtrip() {
|
||||||
|
let des = des_instance();
|
||||||
|
|
||||||
|
let ciphertext = des.encrypt(TEST_PLAINTEXT);
|
||||||
|
let dectrypted = des.decrypt(ciphertext);
|
||||||
|
let re_ciphertext = des.encrypt(dectrypted);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
ciphertext, TEST_CIPHERTEXT,
|
||||||
|
"Encyption failed. Expected 0x{ciphertext:016X}, got 0x{TEST_CIPHERTEXT:016X}"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
dectrypted, TEST_PLAINTEXT,
|
||||||
|
"Decyption failed. Expected 0x{dectrypted:016X}, got 0x{TEST_PLAINTEXT:016X}"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
re_ciphertext, TEST_CIPHERTEXT,
|
||||||
|
"Re-encyption failed. Expected 0x{re_ciphertext:016X}, got 0x{TEST_CIPHERTEXT:016X}"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
use rand::random;
|
use rstest::rstest;
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
use des::Des;
|
use des::Des;
|
||||||
|
|
||||||
@ -12,7 +11,7 @@ fn des_instance() -> Des {
|
|||||||
Des::new(TEST_KEY)
|
Des::new(TEST_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
fn test_ecb_mode_equivalence() {
|
fn test_ecb_mode_equivalence() {
|
||||||
// If you implement ECB mode, test it matches single block
|
// If you implement ECB mode, test it matches single block
|
||||||
let key = 0x1334_5779_9BBC_DFF1;
|
let key = 0x1334_5779_9BBC_DFF1;
|
||||||
@ -24,27 +23,50 @@ fn test_ecb_mode_equivalence() {
|
|||||||
// assert_eq!(single_block, ecb_result[0]);
|
// assert_eq!(single_block, ecb_result[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[rstest]
|
||||||
fn test_with_real_data() {
|
#[case(TEST_PLAINTEXT, TEST_CIPHERTEXT, TEST_KEY)]
|
||||||
// Test with actual 8-byte data
|
fn encrypt_decrypt_roundtrip(
|
||||||
let key_bytes = b"KGenius\x01";
|
#[case] plaintext: u64,
|
||||||
let key = u64::from_le_bytes(*key_bytes);
|
#[case] expected_ciphertext: u64,
|
||||||
|
#[case] key: u64,
|
||||||
let data_bytes = b"HelloDES!";
|
) {
|
||||||
let mut padded = [0u8; 8];
|
|
||||||
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
|
let ciphertext = des.encrypt(plaintext);
|
||||||
let decrypted = des.decrypt(encrypted);
|
let dectrypted = des.decrypt(ciphertext);
|
||||||
let decrypted_bytes = decrypted.to_le_bytes();
|
let re_ciphertext = des.encrypt(dectrypted);
|
||||||
assert_eq!(decrypted_bytes[..data_bytes.len()], *data_bytes);
|
|
||||||
|
assert_eq!(
|
||||||
|
ciphertext, expected_ciphertext,
|
||||||
|
"Encyption failed. Expected 0x{ciphertext:016X}, got 0x{expected_ciphertext:016X}"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
dectrypted, plaintext,
|
||||||
|
"Decyption failed. Expected 0x{dectrypted:016X}, got 0x{plaintext:016X}"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
re_ciphertext, expected_ciphertext,
|
||||||
|
"Re-encyption failed. Expected 0x{re_ciphertext:016X}, got 0x{expected_ciphertext:016X}"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
|
fn weak_keys_rejected() {
|
||||||
|
let weak_keys = [0x0101010101010101, 0xFEFEFEFEFEFEFEFE, 0xE001E001E001E001];
|
||||||
|
|
||||||
|
for key in weak_keys {
|
||||||
|
let des = Des::new(key);
|
||||||
|
let plaintext = TEST_PLAINTEXT;
|
||||||
|
let encrypted = des.encrypt(plaintext);
|
||||||
|
let dectrypted = des.decrypt(encrypted);
|
||||||
|
assert_eq!(
|
||||||
|
dectrypted, plaintext,
|
||||||
|
"Weak key {key:016X} failed roundtrip"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
fn all_zero_paintext() {
|
fn all_zero_paintext() {
|
||||||
let des = des_instance();
|
let des = des_instance();
|
||||||
|
|
||||||
@ -54,70 +76,22 @@ fn all_zero_paintext() {
|
|||||||
assert_eq!(decrypted, plain, "All-zero plaintext failed");
|
assert_eq!(decrypted, plain, "All-zero plaintext failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
#[should_panic(expected = "Invalid key size")]
|
|
||||||
fn invalid_key_size() {
|
|
||||||
let _ = Des::new(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
fn encrypt_decrypt_roundtrip() {
|
|
||||||
let des = des_instance();
|
|
||||||
let plaintext = TEST_PLAINTEXT;
|
|
||||||
let ciphertext = des.encrypt(plaintext);
|
|
||||||
let dectrypted = des.decrypt(plaintext);
|
|
||||||
let re_ciphertext = des.encrypt(dectrypted);
|
|
||||||
|
|
||||||
assert_eq!(ciphertext, TEST_CIPHERTEXT, "Encyption failed");
|
|
||||||
assert_eq!(re_ciphertext, TEST_CIPHERTEXT, "Re-Encyption failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
fn weak_keys_rejected() {
|
|
||||||
let weak_keys = [0x0101010101010101, 0xFEFEFEFEFEFEFEFE, 0xE001E001E001E001];
|
|
||||||
|
|
||||||
for key in weak_keys {
|
|
||||||
let des = Des::new(key);
|
|
||||||
let plaintext = TEST_PLAINTEXT;
|
|
||||||
let encrypted = des.encrypt(plaintext);
|
|
||||||
let dectrypted = des.decrypt(encrypted);
|
|
||||||
assert_eq!(dectrypted, plaintext, "Weak key {key} failed roundtrip");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
fn multiple_blocks() {
|
|
||||||
let des = des_instance();
|
|
||||||
let blocks = [
|
|
||||||
(0x0123456789ABCDEFu64, 0x85E813540F0AB405u64),
|
|
||||||
(0xFEDCBA9876543210u64, 0xC08BF0FF627D3E6Fu64), // Another test vector
|
|
||||||
(0x0000000000000000u64, 0x474D5E3B6F8A07F8u64), // Zero block
|
|
||||||
];
|
|
||||||
for (plaintext, expected) in blocks {
|
|
||||||
let encrypted = des.encrypt(plaintext);
|
|
||||||
assert_eq!(encrypted, expected, "Failed on plaintext: {plaintext:016X}");
|
|
||||||
|
|
||||||
let dectrypted = des.decrypt(encrypted);
|
|
||||||
assert_eq!(dectrypted, plaintext, "Roundtrip failed on block");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
fn all_one_paintext() {
|
fn all_one_paintext() {
|
||||||
let des = des_instance();
|
let des = des_instance();
|
||||||
|
|
||||||
let plain = 1;
|
let plain = u64::MAX;
|
||||||
let encrypted = des.encrypt(plain);
|
let encrypted = des.encrypt(plain);
|
||||||
let decrypted = des.decrypt(encrypted);
|
let decrypted = des.decrypt(encrypted);
|
||||||
assert_eq!(decrypted, plain, "All-one plaintext failed");
|
assert_eq!(decrypted, plain, "All-one plaintext failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
fn different_inputs() {
|
fn different_inputs() {
|
||||||
let des = des_instance();
|
let des = des_instance();
|
||||||
|
|
||||||
let plain1 = 0x0000000000000001;
|
let plain1 = 1;
|
||||||
let plain2 = 0x0000000000000002;
|
let plain2 = 2;
|
||||||
let enc1 = des.encrypt(plain1);
|
let enc1 = des.encrypt(plain1);
|
||||||
let enc2 = des.encrypt(plain2);
|
let enc2 = des.encrypt(plain2);
|
||||||
assert_ne!(
|
assert_ne!(
|
||||||
@ -125,43 +99,3 @@ fn different_inputs() {
|
|||||||
"Encryption not deterministic for different inputs"
|
"Encryption not deterministic for different inputs"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
|
||||||
fn performance() {
|
|
||||||
let des = des_instance();
|
|
||||||
let plaintext = TEST_PLAINTEXT;
|
|
||||||
|
|
||||||
let start = Instant::now();
|
|
||||||
for _ in 0..10000 {
|
|
||||||
let _ = des.encrypt(plaintext);
|
|
||||||
}
|
|
||||||
let duration = start.elapsed();
|
|
||||||
|
|
||||||
println!("10k encryption took: {duration:?}");
|
|
||||||
// Reasonable benchmark: should be under 1ms on modern hardware
|
|
||||||
assert!(duration.as_millis() < 100, "Performance degraded");
|
|
||||||
}
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
fn fuzz_properties() {
|
|
||||||
let des = des_instance();
|
|
||||||
|
|
||||||
for _ in 0..100 {
|
|
||||||
let plaintext = random();
|
|
||||||
let encrypted = des.encrypt(plaintext);
|
|
||||||
let decrypted = des.decrypt(plaintext);
|
|
||||||
|
|
||||||
assert_eq!(decrypted, encrypted, "Fuzz roundtrip failed");
|
|
||||||
assert_ne!(encrypted, plaintext, "Encryption is identity function");
|
|
||||||
|
|
||||||
let key2 = random();
|
|
||||||
if key2 != TEST_KEY {
|
|
||||||
let des2 = Des::new(key2);
|
|
||||||
let encrypted2 = des2.encrypt(plaintext);
|
|
||||||
assert_ne!(
|
|
||||||
encrypted, encrypted2,
|
|
||||||
"Different keys produced same encryption"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -24,25 +24,6 @@ const TEST_KEY: u64 = 0x1334_5779_9BBC_DFF1;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn key_schedule_generates_correct_subkeys() {
|
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);
|
let des = Des::new(TEST_KEY);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -51,41 +32,3 @@ fn key_schedule_generates_correct_subkeys() {
|
|||||||
des.subkeys
|
des.subkeys
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[test]
|
|
||||||
fn test_rotation_shifts() {
|
|
||||||
// Test the left rotation logic in key schedule
|
|
||||||
let mut c: u32 = 0x0FFFFFFF; // 28 bits all 1s
|
|
||||||
c = c.rotate_left(1);
|
|
||||||
assert_eq!(c, 0x1FFFFFFF >> 4, "Single bit rotation failed");
|
|
||||||
|
|
||||||
// Test double shift
|
|
||||||
let mut d: u32 = 0xAAAAAAA; // 101010... pattern
|
|
||||||
d = d.rotate_left(2);
|
|
||||||
assert_eq!(d, 0x2AAAAAA, "Double rotation failed"); // Check pattern shift
|
|
||||||
}
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
fn test_weak_key_detection() {
|
|
||||||
let weak_keys = [
|
|
||||||
0x0101010101010101u64, // All odd parity
|
|
||||||
0xFEFEFEFEFEFEFEFEu64, // All even parity
|
|
||||||
0x1F1F1F1F0E0E0E0Eu64, // Semi-weak
|
|
||||||
];
|
|
||||||
|
|
||||||
for key in weak_keys {
|
|
||||||
let des = Des::new(key);
|
|
||||||
// Weak keys often produce subkeys that don't vary much
|
|
||||||
let subkeys = &des.subkeys;
|
|
||||||
let first = subkeys[0];
|
|
||||||
let last = subkeys[15];
|
|
||||||
// For true weak keys, many subkeys may be identical
|
|
||||||
// This is just a basic check - implement full weak key analysis if desired
|
|
||||||
println!(
|
|
||||||
"Weak key {} subkeys: first={:012X}, last={:012X}",
|
|
||||||
key,
|
|
||||||
first & 0xFFFFFFFFFFFF,
|
|
||||||
last & 0xFFFFFFFFFFFF
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user