Clean up sha-1 and start with md4 implementation
This commit is contained in:
@@ -3,6 +3,7 @@ mod bytes_base64;
|
|||||||
mod cbc;
|
mod cbc;
|
||||||
mod ctr;
|
mod ctr;
|
||||||
mod ecb;
|
mod ecb;
|
||||||
|
mod md4;
|
||||||
mod mt19937;
|
mod mt19937;
|
||||||
mod mtcipher;
|
mod mtcipher;
|
||||||
mod parser;
|
mod parser;
|
||||||
@@ -47,6 +48,8 @@ fn main() {
|
|||||||
set4::challenge29();
|
set4::challenge29();
|
||||||
set4::challenge30();
|
set4::challenge30();
|
||||||
} else {
|
} else {
|
||||||
|
set4::challenge28();
|
||||||
|
set4::challenge29();
|
||||||
set4::challenge30();
|
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() {
|
pub fn challenge25() {
|
||||||
let cipher = utils::read_base64("data/25.txt");
|
let cipher = utils::read_base64("data/25.txt");
|
||||||
@@ -139,28 +139,28 @@ pub fn challenge27() {
|
|||||||
|
|
||||||
pub fn challenge28() {
|
pub fn challenge28() {
|
||||||
let mut sha1 = sha1::Sha1::default();
|
let mut sha1 = sha1::Sha1::default();
|
||||||
let i1 = Bytes(vec![b'a'; 64]);
|
assert_eq!(
|
||||||
let e1 = Bytes::from_hex("0098ba824b5c16427bd7a1122a5a442a25ec644d");
|
Bytes::from_hex("0098ba824b5c16427bd7a1122a5a442a25ec644d"),
|
||||||
let o1 = sha1.hash(&i1);
|
sha1.hash(&Bytes(vec![b'a'; 64]))
|
||||||
assert_eq!(e1, o1);
|
);
|
||||||
|
|
||||||
sha1.reset();
|
sha1.reset();
|
||||||
let i2 = Bytes(vec![b'a'; 128]);
|
assert_eq!(
|
||||||
let e2 = Bytes::from_hex("ad5b3fdbcb526778c2839d2f151ea753995e26a0");
|
Bytes::from_hex("ad5b3fdbcb526778c2839d2f151ea753995e26a0"),
|
||||||
let o2 = sha1.hash(&i2);
|
sha1.hash(&Bytes(vec![b'a'; 128]))
|
||||||
assert_eq!(e2, o2);
|
);
|
||||||
|
|
||||||
sha1.reset();
|
sha1.reset();
|
||||||
let i3 = Bytes(vec![b'a'; 3]);
|
assert_eq!(
|
||||||
let e3 = Bytes::from_hex("7e240de74fb1ed08fa08d38063f6a6a91462a815");
|
Bytes::from_hex("7e240de74fb1ed08fa08d38063f6a6a91462a815"),
|
||||||
let o3 = sha1.hash(&i3);
|
sha1.hash(&Bytes(vec![b'a'; 3])),
|
||||||
assert_eq!(e3, o3);
|
);
|
||||||
|
|
||||||
sha1.reset();
|
sha1.reset();
|
||||||
let i4 = Bytes(vec![]);
|
assert_eq!(
|
||||||
let e4 = Bytes::from_hex("da39a3ee5e6b4b0d3255bfef95601890afd80709");
|
Bytes::from_hex("da39a3ee5e6b4b0d3255bfef95601890afd80709"),
|
||||||
let o4 = sha1.hash(&i4);
|
sha1.hash(&Bytes(vec![])),
|
||||||
assert_eq!(e4, o4);
|
);
|
||||||
|
|
||||||
// Verify that you cannot tamper with the message without breaking the MAC
|
// 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
|
// 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() {
|
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");
|
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 crate::bytes::Bytes;
|
||||||
use std::num::Wrapping;
|
|
||||||
|
|
||||||
const STATE_LEN: usize = 5;
|
const STATE_LEN: usize = 5;
|
||||||
const BLOCK_INTS: usize = 16; // number of 32bit integers per SHA1 block
|
const BLOCK_INTS: usize = 16; // number of 32bit integers per SHA1 block
|
||||||
const BLOCK_BYTES: usize = BLOCK_INTS * 4; // 64
|
const BLOCK_BYTES: usize = BLOCK_INTS * 4; // 64
|
||||||
type Wu32 = Wrapping<u32>;
|
type Block = [u32; BLOCK_INTS];
|
||||||
type Block = [Wu32; BLOCK_INTS];
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Sha1 {
|
pub struct Sha1 {
|
||||||
h: [Wu32; STATE_LEN],
|
h: [u32; STATE_LEN],
|
||||||
byte_len: u64,
|
byte_len: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,13 +16,7 @@ impl Default for Sha1 {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
h: [
|
h: [ 0x6745_2301, 0xEFCD_AB89, 0x98BA_DCFE, 0x1032_5476, 0xC3D2_E1F0, ],
|
||||||
Wrapping(0x67452301),
|
|
||||||
Wrapping(0xEFCDAB89),
|
|
||||||
Wrapping(0x98BADCFE),
|
|
||||||
Wrapping(0x10325476),
|
|
||||||
Wrapping(0xC3D2E1F0),
|
|
||||||
],
|
|
||||||
byte_len: 0,
|
byte_len: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,50 +25,65 @@ impl Default for Sha1 {
|
|||||||
fn bytes_to_block(bytes: &[u8]) -> Block {
|
fn bytes_to_block(bytes: &[u8]) -> Block {
|
||||||
assert_eq!(bytes.len(), BLOCK_BYTES);
|
assert_eq!(bytes.len(), BLOCK_BYTES);
|
||||||
// safety: unwraps work because BLOCK_BYTES length is asserted
|
// safety: unwraps work because BLOCK_BYTES length is asserted
|
||||||
let b: Vec<Wu32> = bytes
|
let b: Vec<u32> = bytes
|
||||||
.chunks(4)
|
.chunks(4)
|
||||||
.map(|c| Wrapping(u32::from_be_bytes(c.try_into().unwrap())))
|
.map(|c| u32::from_be_bytes(c.try_into().unwrap()))
|
||||||
.collect();
|
.collect();
|
||||||
b.try_into().unwrap()
|
b.try_into().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rol(value: Wu32, bits: usize) -> Wu32 {
|
fn rol(value: u32, bits: usize) -> u32 {
|
||||||
return (value << bits) | (value >> (32 - bits));
|
return (value << bits) | (value >> (32 - bits));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn blk(block: &Block, i: usize) -> Wu32 {
|
fn blk(block: &Block, i: usize) -> u32 {
|
||||||
return rol(
|
return rol(
|
||||||
block[(i + 13) & 15] ^ block[(i + 8) & 15] ^ block[(i + 2) & 15] ^ block[i],
|
block[(i + 13) & 15] ^ block[(i + 8) & 15] ^ block[(i + 2) & 15] ^ block[i],
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn r0(block: &Block, v: Wu32, w: &mut Wu32, x: Wu32, y: Wu32, z: &mut Wu32, i: usize) {
|
fn r0(block: &Block, v: u32, w: &mut u32, x: u32, y: u32, z: &mut u32, i: usize) {
|
||||||
*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);
|
*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);
|
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);
|
*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);
|
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);
|
*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);
|
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);
|
*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);
|
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);
|
*w = rol(*w, 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +95,7 @@ impl Sha1 {
|
|||||||
|
|
||||||
pub fn fix(&mut self, fixate: [u32; STATE_LEN], byte_len: u64) {
|
pub fn fix(&mut self, fixate: [u32; STATE_LEN], byte_len: u64) {
|
||||||
for i in 0..5 {
|
for i in 0..5 {
|
||||||
self.h[i] = Wrapping(fixate[i]);
|
self.h[i] = fixate[i];
|
||||||
}
|
}
|
||||||
self.byte_len = byte_len;
|
self.byte_len = byte_len;
|
||||||
}
|
}
|
||||||
@@ -232,7 +239,7 @@ impl Sha1 {
|
|||||||
for bytes in final_bytes.chunks(BLOCK_BYTES) {
|
for bytes in final_bytes.chunks(BLOCK_BYTES) {
|
||||||
self.update(&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