Tests, benchmarks, input stream
This commit is contained in:
1 parent
1fd272c010
commit
dc59f69e80
6 files changed
+838
-173
No files matched your search
+218
@@ -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<Keys> {
|
||||
let mut keys: Vec<Keys> = 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<Keys> = 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+54
-170
@@ -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::<u128>, 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<Keys> {
|
||||
let mut keys: Vec<Keys> = 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<Keys> = 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<dyn std::error::Error>> {
|
||||
let args = Cli::parse();
|
||||
let key: u128 = args.key;
|
||||
let key2: u128 = args.key;
|
||||
let message: u64 = args.message;
|
||||
// let message: u64 = args.message;
|
||||
// println!("message: {:?}, key: {:?}\n", message, key);
|
||||
|
||||
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 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<u8> = 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(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
Reference in new issue
Block a user