Finish challenge 28 by implementing sha-1
This commit is contained in:
@@ -10,10 +10,11 @@ mod set1;
|
|||||||
mod set2;
|
mod set2;
|
||||||
mod set3;
|
mod set3;
|
||||||
mod set4;
|
mod set4;
|
||||||
|
mod sha1;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
const RUN_ALL: bool = false;
|
const RUN_ALL: bool = true;
|
||||||
if RUN_ALL {
|
if RUN_ALL {
|
||||||
set1::challenge1();
|
set1::challenge1();
|
||||||
set1::challenge2();
|
set1::challenge2();
|
||||||
@@ -43,7 +44,8 @@ fn main() {
|
|||||||
set4::challenge26();
|
set4::challenge26();
|
||||||
set4::challenge27();
|
set4::challenge27();
|
||||||
set4::challenge28();
|
set4::challenge28();
|
||||||
|
set4::challenge29();
|
||||||
} else {
|
} else {
|
||||||
set4::challenge28();
|
set4::challenge29();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
51
src/set4.rs
51
src/set4.rs
@@ -1,4 +1,6 @@
|
|||||||
use crate::{bytes::Bytes, cbc, ctr, parser, utils};
|
#![allow(arithmetic_overflow)]
|
||||||
|
|
||||||
|
use crate::{bytes::Bytes, cbc, ctr, 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");
|
||||||
@@ -138,5 +140,50 @@ pub fn challenge27() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn challenge28() {
|
pub fn challenge28() {
|
||||||
println!("[xxxx] Challenge 28: TBD");
|
let i1 = Bytes(vec![b'a'; 64]);
|
||||||
|
let e1 = Bytes::from_hex("0098ba824b5c16427bd7a1122a5a442a25ec644d");
|
||||||
|
let o1 = sha1::hash(&i1);
|
||||||
|
assert_eq!(e1, o1);
|
||||||
|
|
||||||
|
let i2 = Bytes(vec![b'a'; 128]);
|
||||||
|
let e2 = Bytes::from_hex("ad5b3fdbcb526778c2839d2f151ea753995e26a0");
|
||||||
|
let o2 = sha1::hash(&i2);
|
||||||
|
assert_eq!(e2, o2);
|
||||||
|
|
||||||
|
let i3 = Bytes(vec![b'a'; 3]);
|
||||||
|
let e3 = Bytes::from_hex("7e240de74fb1ed08fa08d38063f6a6a91462a815");
|
||||||
|
let o3 = sha1::hash(&i3);
|
||||||
|
assert_eq!(e3, o3);
|
||||||
|
|
||||||
|
let i4 = Bytes(vec![]);
|
||||||
|
let e4 = Bytes::from_hex("da39a3ee5e6b4b0d3255bfef95601890afd80709");
|
||||||
|
let o4 = sha1::hash(&i4);
|
||||||
|
assert_eq!(e4, o4);
|
||||||
|
|
||||||
|
fn authenticate(message: &Bytes, key: &Bytes) -> Bytes {
|
||||||
|
// Write a function to authenticate a message under a secret key by using a
|
||||||
|
// secret-prefix MAC, which is simply:
|
||||||
|
// SHA1(key || message)
|
||||||
|
let mut c = vec![];
|
||||||
|
c.append(&mut key.0.to_vec());
|
||||||
|
c.append(&mut message.0.to_vec());
|
||||||
|
// how to concatenate better: https://stackoverflow.com/a/56490417
|
||||||
|
sha1::hash(&Bytes(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// secret key.
|
||||||
|
let mut message = Bytes::from_utf8("love, love, love");
|
||||||
|
let key = Bytes::from_utf8("kisses!");
|
||||||
|
let auth = authenticate(&message, &key);
|
||||||
|
message.flip_bit(2, 3);
|
||||||
|
let auth_tempered = authenticate(&message, &key);
|
||||||
|
assert!(auth != auth_tempered);
|
||||||
|
|
||||||
|
println!("[okay] Challenge 28: implemented SHA-1");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn challenge29() {
|
||||||
|
println!("[xxxx] Challenge 29: TBD");
|
||||||
}
|
}
|
||||||
|
|||||||
234
src/sha1.rs
Normal file
234
src/sha1.rs
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
use crate::bytes::Bytes;
|
||||||
|
/// Sha1 implementation based on https://github.com/vog/sha1/blob/master/sha1.hpp
|
||||||
|
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];
|
||||||
|
|
||||||
|
pub struct Sha1 {
|
||||||
|
h: [Wu32; STATE_LEN],
|
||||||
|
block_len: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Sha1 {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
h: [
|
||||||
|
Wrapping(0x67452301),
|
||||||
|
Wrapping(0xEFCDAB89),
|
||||||
|
Wrapping(0x98BADCFE),
|
||||||
|
Wrapping(0x10325476),
|
||||||
|
Wrapping(0xC3D2E1F0),
|
||||||
|
],
|
||||||
|
block_len: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rol(value: Wu32, bits: usize) -> Wu32 {
|
||||||
|
return (value << bits) | (value >> (32 - bits));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blk(block: &Block, i: usize) -> Wu32 {
|
||||||
|
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);
|
||||||
|
*w = rol(*w, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r1(block: &mut Block, v: Wu32, w: &mut Wu32, x: Wu32, y: Wu32, z: &mut Wu32, i: usize) {
|
||||||
|
block[i] = blk(block, i);
|
||||||
|
*z = *z + ((*w & (x ^ y)) ^ y) + block[i] + Wrapping(0x5a827999) + 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) {
|
||||||
|
block[i] = blk(block, i);
|
||||||
|
*z += (*w ^ x ^ y) + block[i] + Wrapping(0x6ed9eba1) + 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) {
|
||||||
|
block[i] = blk(block, i);
|
||||||
|
*z += (((*w | x) & y) | (*w & x)) + block[i] + Wrapping(0x8f1bbcdc) + 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) {
|
||||||
|
block[i] = blk(block, i);
|
||||||
|
*z = *z + (*w ^ x ^ y) + block[i] + Wrapping(0xca62c1d6) + rol(v, 5);
|
||||||
|
*w = rol(*w, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sha1 {
|
||||||
|
#[inline]
|
||||||
|
fn _reset(&mut self) {
|
||||||
|
*self = Default::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transform(&mut self, block: &mut Block) {
|
||||||
|
/* Copy digest[] to working vars */
|
||||||
|
let mut a = self.h[0];
|
||||||
|
let mut b = self.h[1];
|
||||||
|
let mut c = self.h[2];
|
||||||
|
let mut d = self.h[3];
|
||||||
|
let mut e = self.h[4];
|
||||||
|
|
||||||
|
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||||
|
r0(block, a, &mut b, c, d, &mut e, 0);
|
||||||
|
r0(block, e, &mut a, b, c, &mut d, 1);
|
||||||
|
r0(block, d, &mut e, a, b, &mut c, 2);
|
||||||
|
r0(block, c, &mut d, e, a, &mut b, 3);
|
||||||
|
r0(block, b, &mut c, d, e, &mut a, 4);
|
||||||
|
r0(block, a, &mut b, c, d, &mut e, 5);
|
||||||
|
r0(block, e, &mut a, b, c, &mut d, 6);
|
||||||
|
r0(block, d, &mut e, a, b, &mut c, 7);
|
||||||
|
r0(block, c, &mut d, e, a, &mut b, 8);
|
||||||
|
r0(block, b, &mut c, d, e, &mut a, 9);
|
||||||
|
r0(block, a, &mut b, c, d, &mut e, 10);
|
||||||
|
r0(block, e, &mut a, b, c, &mut d, 11);
|
||||||
|
r0(block, d, &mut e, a, b, &mut c, 12);
|
||||||
|
r0(block, c, &mut d, e, a, &mut b, 13);
|
||||||
|
r0(block, b, &mut c, d, e, &mut a, 14);
|
||||||
|
r0(block, a, &mut b, c, d, &mut e, 15);
|
||||||
|
r1(block, e, &mut a, b, c, &mut d, 0);
|
||||||
|
r1(block, d, &mut e, a, b, &mut c, 1);
|
||||||
|
r1(block, c, &mut d, e, a, &mut b, 2);
|
||||||
|
r1(block, b, &mut c, d, e, &mut a, 3);
|
||||||
|
r2(block, a, &mut b, c, d, &mut e, 4);
|
||||||
|
r2(block, e, &mut a, b, c, &mut d, 5);
|
||||||
|
r2(block, d, &mut e, a, b, &mut c, 6);
|
||||||
|
r2(block, c, &mut d, e, a, &mut b, 7);
|
||||||
|
r2(block, b, &mut c, d, e, &mut a, 8);
|
||||||
|
r2(block, a, &mut b, c, d, &mut e, 9);
|
||||||
|
r2(block, e, &mut a, b, c, &mut d, 10);
|
||||||
|
r2(block, d, &mut e, a, b, &mut c, 11);
|
||||||
|
r2(block, c, &mut d, e, a, &mut b, 12);
|
||||||
|
r2(block, b, &mut c, d, e, &mut a, 13);
|
||||||
|
r2(block, a, &mut b, c, d, &mut e, 14);
|
||||||
|
r2(block, e, &mut a, b, c, &mut d, 15);
|
||||||
|
r2(block, d, &mut e, a, b, &mut c, 0);
|
||||||
|
r2(block, c, &mut d, e, a, &mut b, 1);
|
||||||
|
r2(block, b, &mut c, d, e, &mut a, 2);
|
||||||
|
r2(block, a, &mut b, c, d, &mut e, 3);
|
||||||
|
r2(block, e, &mut a, b, c, &mut d, 4);
|
||||||
|
r2(block, d, &mut e, a, b, &mut c, 5);
|
||||||
|
r2(block, c, &mut d, e, a, &mut b, 6);
|
||||||
|
r2(block, b, &mut c, d, e, &mut a, 7);
|
||||||
|
r3(block, a, &mut b, c, d, &mut e, 8);
|
||||||
|
r3(block, e, &mut a, b, c, &mut d, 9);
|
||||||
|
r3(block, d, &mut e, a, b, &mut c, 10);
|
||||||
|
r3(block, c, &mut d, e, a, &mut b, 11);
|
||||||
|
r3(block, b, &mut c, d, e, &mut a, 12);
|
||||||
|
r3(block, a, &mut b, c, d, &mut e, 13);
|
||||||
|
r3(block, e, &mut a, b, c, &mut d, 14);
|
||||||
|
r3(block, d, &mut e, a, b, &mut c, 15);
|
||||||
|
r3(block, c, &mut d, e, a, &mut b, 0);
|
||||||
|
r3(block, b, &mut c, d, e, &mut a, 1);
|
||||||
|
r3(block, a, &mut b, c, d, &mut e, 2);
|
||||||
|
r3(block, e, &mut a, b, c, &mut d, 3);
|
||||||
|
r3(block, d, &mut e, a, b, &mut c, 4);
|
||||||
|
r3(block, c, &mut d, e, a, &mut b, 5);
|
||||||
|
r3(block, b, &mut c, d, e, &mut a, 6);
|
||||||
|
r3(block, a, &mut b, c, d, &mut e, 7);
|
||||||
|
r3(block, e, &mut a, b, c, &mut d, 8);
|
||||||
|
r3(block, d, &mut e, a, b, &mut c, 9);
|
||||||
|
r3(block, c, &mut d, e, a, &mut b, 10);
|
||||||
|
r3(block, b, &mut c, d, e, &mut a, 11);
|
||||||
|
r4(block, a, &mut b, c, d, &mut e, 12);
|
||||||
|
r4(block, e, &mut a, b, c, &mut d, 13);
|
||||||
|
r4(block, d, &mut e, a, b, &mut c, 14);
|
||||||
|
r4(block, c, &mut d, e, a, &mut b, 15);
|
||||||
|
r4(block, b, &mut c, d, e, &mut a, 0);
|
||||||
|
r4(block, a, &mut b, c, d, &mut e, 1);
|
||||||
|
r4(block, e, &mut a, b, c, &mut d, 2);
|
||||||
|
r4(block, d, &mut e, a, b, &mut c, 3);
|
||||||
|
r4(block, c, &mut d, e, a, &mut b, 4);
|
||||||
|
r4(block, b, &mut c, d, e, &mut a, 5);
|
||||||
|
r4(block, a, &mut b, c, d, &mut e, 6);
|
||||||
|
r4(block, e, &mut a, b, c, &mut d, 7);
|
||||||
|
r4(block, d, &mut e, a, b, &mut c, 8);
|
||||||
|
r4(block, c, &mut d, e, a, &mut b, 9);
|
||||||
|
r4(block, b, &mut c, d, e, &mut a, 10);
|
||||||
|
r4(block, a, &mut b, c, d, &mut e, 11);
|
||||||
|
r4(block, e, &mut a, b, c, &mut d, 12);
|
||||||
|
r4(block, d, &mut e, a, b, &mut c, 13);
|
||||||
|
r4(block, c, &mut d, e, a, &mut b, 14);
|
||||||
|
r4(block, b, &mut c, d, e, &mut a, 15);
|
||||||
|
|
||||||
|
/* Add the working vars back into digest[] */
|
||||||
|
self.h[0] += a;
|
||||||
|
self.h[1] += b;
|
||||||
|
self.h[2] += c;
|
||||||
|
self.h[3] += d;
|
||||||
|
self.h[4] += e;
|
||||||
|
|
||||||
|
/* Count the number of transformations */
|
||||||
|
self.block_len += 1;
|
||||||
|
}
|
||||||
|
fn update(&mut self, bytes: &[u8]) {
|
||||||
|
if bytes.len() % BLOCK_BYTES != 0 {
|
||||||
|
panic!("we only support buffers that are a multiples of 64 atm")
|
||||||
|
}
|
||||||
|
let mut block = bytes_to_block(bytes);
|
||||||
|
self.transform(&mut block);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize(&mut self, last_chunk: Vec<u8>) -> Bytes {
|
||||||
|
let mut buffer = last_chunk;
|
||||||
|
let total_bits: u64 = (self.block_len * (BLOCK_BYTES as u64) + buffer.len() as u64) * 8;
|
||||||
|
|
||||||
|
buffer.push(0x80);
|
||||||
|
|
||||||
|
let orig_size = buffer.len();
|
||||||
|
while buffer.len() < BLOCK_BYTES {
|
||||||
|
buffer.push(0x0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut block = bytes_to_block(&buffer);
|
||||||
|
if orig_size > (BLOCK_BYTES - 8) as usize {
|
||||||
|
self.transform(&mut block);
|
||||||
|
for i in 0..(BLOCK_INTS - 2) {
|
||||||
|
block[i] = Wrapping(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
block[BLOCK_INTS - 1] = Wrapping(total_bits as u32);
|
||||||
|
block[BLOCK_INTS - 2] = Wrapping((total_bits >> 32) as u32);
|
||||||
|
self.transform(&mut block);
|
||||||
|
|
||||||
|
Bytes(self.h.iter().map(|i| i.0.to_be_bytes()).flatten().collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
.chunks(4)
|
||||||
|
.map(|c| Wrapping(u32::from_be_bytes(c.try_into().unwrap())))
|
||||||
|
.collect();
|
||||||
|
b.try_into().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hash(bytes: &Bytes) -> Bytes {
|
||||||
|
let mut s = Sha1::default();
|
||||||
|
let mut last_chunk = vec![];
|
||||||
|
for bytes in bytes.0.chunks(BLOCK_BYTES) {
|
||||||
|
if bytes.len() == BLOCK_BYTES {
|
||||||
|
s.update(&bytes);
|
||||||
|
} else {
|
||||||
|
last_chunk = bytes.to_vec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.finalize(last_chunk)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user