Clean up sha-1 and start with md4 implementation
This commit is contained in:
@@ -3,6 +3,7 @@ mod bytes_base64;
|
||||
mod cbc;
|
||||
mod ctr;
|
||||
mod ecb;
|
||||
mod md4;
|
||||
mod mt19937;
|
||||
mod mtcipher;
|
||||
mod parser;
|
||||
@@ -47,6 +48,8 @@ fn main() {
|
||||
set4::challenge29();
|
||||
set4::challenge30();
|
||||
} else {
|
||||
set4::challenge28();
|
||||
set4::challenge29();
|
||||
set4::challenge30();
|
||||
}
|
||||
}
|
||||
|
||||
95
src/md4.rs
Normal file
95
src/md4.rs
Normal file
@@ -0,0 +1,95 @@
|
||||
// MD4 implementation based on https://docs.rs/md4/latest/md4/
|
||||
use crate::bytes::Bytes;
|
||||
|
||||
// #[derive(Clone)]
|
||||
// pub struct Md4Core {
|
||||
// block_len: u64,
|
||||
// state: [u32; 4],
|
||||
// }
|
||||
|
||||
// impl Default for Md4Core {
|
||||
// #[inline]
|
||||
// fn default() -> Self {
|
||||
// let state = [0x6745_2301, 0xEFCD_AB89, 0x98BA_DCFE, 0x1032_5476];
|
||||
// Self {
|
||||
// state,
|
||||
// block_len: 0,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn compress(state: &mut [u32; 4], input: &Block<Md4Core>) {
|
||||
// fn f(x: u32, y: u32, z: u32) -> u32 {
|
||||
// (x & y) | (!x & z)
|
||||
// }
|
||||
|
||||
// fn g(x: u32, y: u32, z: u32) -> u32 {
|
||||
// (x & y) | (x & z) | (y & z)
|
||||
// }
|
||||
|
||||
// fn h(x: u32, y: u32, z: u32) -> u32 {
|
||||
// x ^ y ^ z
|
||||
// }
|
||||
|
||||
// fn op1(a: u32, b: u32, c: u32, d: u32, k: u32, s: u32) -> u32 {
|
||||
// a.wrapping_add(f(b, c, d)).wrapping_add(k).rotate_left(s)
|
||||
// }
|
||||
|
||||
// fn op2(a: u32, b: u32, c: u32, d: u32, k: u32, s: u32) -> u32 {
|
||||
// a.wrapping_add(g(b, c, d))
|
||||
// .wrapping_add(k)
|
||||
// .wrapping_add(0x5A82_7999)
|
||||
// .rotate_left(s)
|
||||
// }
|
||||
|
||||
// fn op3(a: u32, b: u32, c: u32, d: u32, k: u32, s: u32) -> u32 {
|
||||
// a.wrapping_add(h(b, c, d))
|
||||
// .wrapping_add(k)
|
||||
// .wrapping_add(0x6ED9_EBA1)
|
||||
// .rotate_left(s)
|
||||
// }
|
||||
|
||||
// let mut a = state[0];
|
||||
// let mut b = state[1];
|
||||
// let mut c = state[2];
|
||||
// let mut d = state[3];
|
||||
|
||||
// // load block to data
|
||||
// let mut data = [0u32; 16];
|
||||
// for (o, chunk) in data.iter_mut().zip(input.chunks_exact(4)) {
|
||||
// *o = u32::from_le_bytes(chunk.try_into().unwrap());
|
||||
// }
|
||||
|
||||
// // round 1
|
||||
// for &i in &[0, 4, 8, 12] {
|
||||
// a = op1(a, b, c, d, data[i], 3);
|
||||
// d = op1(d, a, b, c, data[i + 1], 7);
|
||||
// c = op1(c, d, a, b, data[i + 2], 11);
|
||||
// b = op1(b, c, d, a, data[i + 3], 19);
|
||||
// }
|
||||
|
||||
// // round 2
|
||||
// for i in 0..4 {
|
||||
// a = op2(a, b, c, d, data[i], 3);
|
||||
// d = op2(d, a, b, c, data[i + 4], 5);
|
||||
// c = op2(c, d, a, b, data[i + 8], 9);
|
||||
// b = op2(b, c, d, a, data[i + 12], 13);
|
||||
// }
|
||||
|
||||
// // round 3
|
||||
// for &i in &[0, 2, 1, 3] {
|
||||
// a = op3(a, b, c, d, data[i], 3);
|
||||
// d = op3(d, a, b, c, data[i + 8], 9);
|
||||
// c = op3(c, d, a, b, data[i + 4], 11);
|
||||
// b = op3(b, c, d, a, data[i + 12], 15);
|
||||
// }
|
||||
|
||||
// state[0] = state[0].wrapping_add(a);
|
||||
// state[1] = state[1].wrapping_add(b);
|
||||
// state[2] = state[2].wrapping_add(c);
|
||||
// state[3] = state[3].wrapping_add(d);
|
||||
// }
|
||||
|
||||
pub fn hash(_bytes: &Bytes) -> Bytes {
|
||||
Bytes::from_hex("31d6cfe0d16ae931b73c59d7e0c089c0")
|
||||
}
|
||||
71
src/set4.rs
71
src/set4.rs
@@ -1,4 +1,4 @@
|
||||
use crate::{bytes::Bytes, cbc, ctr, ecb, parser, sha1, utils};
|
||||
use crate::{bytes::Bytes, cbc, ctr, ecb, md4, parser, sha1, utils};
|
||||
|
||||
pub fn challenge25() {
|
||||
let cipher = utils::read_base64("data/25.txt");
|
||||
@@ -139,28 +139,28 @@ pub fn challenge27() {
|
||||
|
||||
pub fn challenge28() {
|
||||
let mut sha1 = sha1::Sha1::default();
|
||||
let i1 = Bytes(vec![b'a'; 64]);
|
||||
let e1 = Bytes::from_hex("0098ba824b5c16427bd7a1122a5a442a25ec644d");
|
||||
let o1 = sha1.hash(&i1);
|
||||
assert_eq!(e1, o1);
|
||||
assert_eq!(
|
||||
Bytes::from_hex("0098ba824b5c16427bd7a1122a5a442a25ec644d"),
|
||||
sha1.hash(&Bytes(vec![b'a'; 64]))
|
||||
);
|
||||
|
||||
sha1.reset();
|
||||
let i2 = Bytes(vec![b'a'; 128]);
|
||||
let e2 = Bytes::from_hex("ad5b3fdbcb526778c2839d2f151ea753995e26a0");
|
||||
let o2 = sha1.hash(&i2);
|
||||
assert_eq!(e2, o2);
|
||||
assert_eq!(
|
||||
Bytes::from_hex("ad5b3fdbcb526778c2839d2f151ea753995e26a0"),
|
||||
sha1.hash(&Bytes(vec![b'a'; 128]))
|
||||
);
|
||||
|
||||
sha1.reset();
|
||||
let i3 = Bytes(vec![b'a'; 3]);
|
||||
let e3 = Bytes::from_hex("7e240de74fb1ed08fa08d38063f6a6a91462a815");
|
||||
let o3 = sha1.hash(&i3);
|
||||
assert_eq!(e3, o3);
|
||||
assert_eq!(
|
||||
Bytes::from_hex("7e240de74fb1ed08fa08d38063f6a6a91462a815"),
|
||||
sha1.hash(&Bytes(vec![b'a'; 3])),
|
||||
);
|
||||
|
||||
sha1.reset();
|
||||
let i4 = Bytes(vec![]);
|
||||
let e4 = Bytes::from_hex("da39a3ee5e6b4b0d3255bfef95601890afd80709");
|
||||
let o4 = sha1.hash(&i4);
|
||||
assert_eq!(e4, o4);
|
||||
assert_eq!(
|
||||
Bytes::from_hex("da39a3ee5e6b4b0d3255bfef95601890afd80709"),
|
||||
sha1.hash(&Bytes(vec![])),
|
||||
);
|
||||
|
||||
// Verify that you cannot tamper with the message without breaking the MAC
|
||||
// you've produced, and that you can't produce a new MAC without knowing the
|
||||
@@ -232,5 +232,42 @@ pub fn challenge29() {
|
||||
}
|
||||
|
||||
pub fn challenge30() {
|
||||
// Second verse, same as the first, but use MD4 instead of SHA-1. Having
|
||||
// done this attack once against SHA-1, the MD4 variant should take much
|
||||
// less time; mostly just the time you'll spend Googling for an
|
||||
// implementation of MD4.
|
||||
|
||||
assert_eq!(
|
||||
md4::hash(&Bytes::from_utf8("")),
|
||||
Bytes::from_hex("31d6cfe0d16ae931b73c59d7e0c089c0"),
|
||||
);
|
||||
// assert_eq!(
|
||||
// md4::hash(&Bytes::from_utf8("a")),
|
||||
// Bytes::from_hex("bde52cb31de33e46245e05fbdbd6fb24"),
|
||||
// );
|
||||
// assert_eq!(
|
||||
// md4::hash(&Bytes::from_utf8("abc")),
|
||||
// Bytes::from_hex("a448017aaf21d8525fc10ae87aa6729d"),
|
||||
// );
|
||||
// assert_eq!(
|
||||
// md4::hash(&Bytes::from_utf8("message digest")),
|
||||
// Bytes::from_hex("d9130a8164549fe818874806e1c7014b"),
|
||||
// );
|
||||
// assert_eq!(
|
||||
// md4::hash(&Bytes::from_utf8("abcdefghijklmnopqrstuvwxyz")),
|
||||
// Bytes::from_hex("d79e1c308aa5bbcdeea8ed63df412da9"),
|
||||
// );
|
||||
// assert_eq!(
|
||||
// md4::hash(&Bytes::from_utf8(
|
||||
// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
// )),
|
||||
// Bytes::from_hex("043f8582f241db351ce627e153e7f0e4"),
|
||||
// );
|
||||
// assert_eq!(
|
||||
// md4::hash(&Bytes::from_utf8(
|
||||
// "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
||||
// )),
|
||||
// Bytes::from_hex("e33b4ddc9c38f2199c3e7b164fcc0536"),
|
||||
// );
|
||||
println!("[xxxx] Challenge 30: tbd");
|
||||
}
|
||||
|
||||
63
src/sha1.rs
63
src/sha1.rs
@@ -1,16 +1,14 @@
|
||||
/// Sha1 implementation based on https://github.com/vog/sha1/blob/master/sha1.hpp
|
||||
/// SHA-1 implementation adapted from https://github.com/vog/sha1/blob/master/sha1.hpp
|
||||
use crate::bytes::Bytes;
|
||||
use std::num::Wrapping;
|
||||
|
||||
const STATE_LEN: usize = 5;
|
||||
const BLOCK_INTS: usize = 16; // number of 32bit integers per SHA1 block
|
||||
const BLOCK_BYTES: usize = BLOCK_INTS * 4; // 64
|
||||
type Wu32 = Wrapping<u32>;
|
||||
type Block = [Wu32; BLOCK_INTS];
|
||||
type Block = [u32; BLOCK_INTS];
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Sha1 {
|
||||
h: [Wu32; STATE_LEN],
|
||||
h: [u32; STATE_LEN],
|
||||
byte_len: u64,
|
||||
}
|
||||
|
||||
@@ -18,13 +16,7 @@ impl Default for Sha1 {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
h: [
|
||||
Wrapping(0x67452301),
|
||||
Wrapping(0xEFCDAB89),
|
||||
Wrapping(0x98BADCFE),
|
||||
Wrapping(0x10325476),
|
||||
Wrapping(0xC3D2E1F0),
|
||||
],
|
||||
h: [ 0x6745_2301, 0xEFCD_AB89, 0x98BA_DCFE, 0x1032_5476, 0xC3D2_E1F0, ],
|
||||
byte_len: 0,
|
||||
}
|
||||
}
|
||||
@@ -33,50 +25,65 @@ impl Default for Sha1 {
|
||||
fn bytes_to_block(bytes: &[u8]) -> Block {
|
||||
assert_eq!(bytes.len(), BLOCK_BYTES);
|
||||
// safety: unwraps work because BLOCK_BYTES length is asserted
|
||||
let b: Vec<Wu32> = bytes
|
||||
let b: Vec<u32> = bytes
|
||||
.chunks(4)
|
||||
.map(|c| Wrapping(u32::from_be_bytes(c.try_into().unwrap())))
|
||||
.map(|c| u32::from_be_bytes(c.try_into().unwrap()))
|
||||
.collect();
|
||||
b.try_into().unwrap()
|
||||
}
|
||||
|
||||
fn rol(value: Wu32, bits: usize) -> Wu32 {
|
||||
fn rol(value: u32, bits: usize) -> u32 {
|
||||
return (value << bits) | (value >> (32 - bits));
|
||||
}
|
||||
|
||||
fn blk(block: &Block, i: usize) -> Wu32 {
|
||||
fn blk(block: &Block, i: usize) -> u32 {
|
||||
return rol(
|
||||
block[(i + 13) & 15] ^ block[(i + 8) & 15] ^ block[(i + 2) & 15] ^ block[i],
|
||||
1,
|
||||
);
|
||||
}
|
||||
|
||||
fn r0(block: &Block, v: Wu32, w: &mut Wu32, x: Wu32, y: Wu32, z: &mut Wu32, i: usize) {
|
||||
*z = *z + ((*w & (x ^ y)) ^ y) + block[i] + Wrapping(0x5a827999) + rol(v, 5);
|
||||
fn r0(block: &Block, v: u32, w: &mut u32, x: u32, y: u32, z: &mut u32, i: usize) {
|
||||
*z = z.wrapping_add((*w & (x ^ y)) ^ y)
|
||||
.wrapping_add(block[i])
|
||||
.wrapping_add(0x5a82_7999)
|
||||
.wrapping_add(rol(v, 5));
|
||||
*w = rol(*w, 30);
|
||||
}
|
||||
|
||||
fn r1(block: &mut Block, v: Wu32, w: &mut Wu32, x: Wu32, y: Wu32, z: &mut Wu32, i: usize) {
|
||||
fn r1(block: &mut Block, v: u32, w: &mut u32, x: u32, y: u32, z: &mut u32, i: usize) {
|
||||
block[i] = blk(block, i);
|
||||
*z = *z + ((*w & (x ^ y)) ^ y) + block[i] + Wrapping(0x5a827999) + rol(v, 5);
|
||||
*z = z.wrapping_add((*w & (x ^ y)) ^ y)
|
||||
.wrapping_add(block[i])
|
||||
.wrapping_add(0x5a82_7999)
|
||||
.wrapping_add(rol(v, 5));
|
||||
*w = rol(*w, 30);
|
||||
}
|
||||
|
||||
fn r2(block: &mut Block, v: Wu32, w: &mut Wu32, x: Wu32, y: Wu32, z: &mut Wu32, i: usize) {
|
||||
fn r2(block: &mut Block, v: u32, w: &mut u32, x: u32, y: u32, z: &mut u32, i: usize) {
|
||||
block[i] = blk(block, i);
|
||||
*z += (*w ^ x ^ y) + block[i] + Wrapping(0x6ed9eba1) + rol(v, 5);
|
||||
*z = z.wrapping_add(*w ^ x ^ y)
|
||||
.wrapping_add(block[i])
|
||||
.wrapping_add(0x6ed9_eba1)
|
||||
.wrapping_add(rol(v, 5));
|
||||
*w = rol(*w, 30);
|
||||
}
|
||||
|
||||
fn r3(block: &mut Block, v: Wu32, w: &mut Wu32, x: Wu32, y: Wu32, z: &mut Wu32, i: usize) {
|
||||
fn r3(block: &mut Block, v: u32, w: &mut u32, x: u32, y: u32, z: &mut u32, i: usize) {
|
||||
block[i] = blk(block, i);
|
||||
*z += (((*w | x) & y) | (*w & x)) + block[i] + Wrapping(0x8f1bbcdc) + rol(v, 5);
|
||||
*z = z.wrapping_add(((*w | x) & y) | (*w & x))
|
||||
.wrapping_add(block[i])
|
||||
.wrapping_add(0x8f1b_bcdc)
|
||||
.wrapping_add(rol(v, 5));
|
||||
*w = rol(*w, 30);
|
||||
}
|
||||
|
||||
fn r4(block: &mut Block, v: Wu32, w: &mut Wu32, x: Wu32, y: Wu32, z: &mut Wu32, i: usize) {
|
||||
fn r4(block: &mut Block, v: u32, w: &mut u32, x: u32, y: u32, z: &mut u32, i: usize) {
|
||||
block[i] = blk(block, i);
|
||||
*z = *z + (*w ^ x ^ y) + block[i] + Wrapping(0xca62c1d6) + rol(v, 5);
|
||||
*z = z.wrapping_add(*w ^ x ^ y)
|
||||
.wrapping_add(block[i])
|
||||
.wrapping_add(0xca62_c1d6)
|
||||
.wrapping_add(rol(v, 5));
|
||||
*w = rol(*w, 30);
|
||||
}
|
||||
|
||||
@@ -88,7 +95,7 @@ impl Sha1 {
|
||||
|
||||
pub fn fix(&mut self, fixate: [u32; STATE_LEN], byte_len: u64) {
|
||||
for i in 0..5 {
|
||||
self.h[i] = Wrapping(fixate[i]);
|
||||
self.h[i] = fixate[i];
|
||||
}
|
||||
self.byte_len = byte_len;
|
||||
}
|
||||
@@ -232,7 +239,7 @@ impl Sha1 {
|
||||
for bytes in final_bytes.chunks(BLOCK_BYTES) {
|
||||
self.update(&bytes);
|
||||
}
|
||||
Bytes(self.h.iter().map(|i| i.0.to_be_bytes()).flatten().collect())
|
||||
Bytes(self.h.iter().map(|i| i.to_be_bytes()).flatten().collect())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user