mirror of
https://github.com/Noratrieb/crypto-hype.git
synced 2026-01-14 09:15:02 +01:00
SHA-1
This commit is contained in:
parent
6d46c730b9
commit
5ff6bc24fa
6 changed files with 181 additions and 1 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
|
@ -5,3 +5,12 @@ version = 3
|
|||
[[package]]
|
||||
name = "crypto-hype"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"hex-literal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex-literal"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
|
||||
|
|
|
|||
|
|
@ -4,3 +4,4 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
hex-literal = "0.4.1"
|
||||
|
|
|
|||
13
src/bin/sha1sum.rs
Normal file
13
src/bin/sha1sum.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
fn main() {
|
||||
for file in std::env::args().skip(1) {
|
||||
match std::fs::read(&file) {
|
||||
Err(err) => {
|
||||
eprintln!("error reading {file}: {err}")
|
||||
}
|
||||
Ok(content) => {
|
||||
let sum = crypto_hype::hashes::sha1::hash(&content);
|
||||
println!("{sum} {file}");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1,2 @@
|
|||
pub mod md5;
|
||||
pub mod sha1;
|
||||
|
|
|
|||
147
src/hashes/sha1.rs
Normal file
147
src/hashes/sha1.rs
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
//! https://datatracker.ietf.org/doc/html/rfc3174
|
||||
|
||||
use std::num::Wrapping;
|
||||
|
||||
use crate::utils::Fingerprint;
|
||||
|
||||
use crate::utils::WrappingExt;
|
||||
|
||||
const BYTES_IN_WORD: usize = 4;
|
||||
const BITS_IN_BYTE: usize = 8;
|
||||
const BLOCK_WORD_SIZE: usize = 16;
|
||||
|
||||
pub type Sha1Fingerprint = Fingerprint<20>;
|
||||
|
||||
pub fn hash(msg: &[u8]) -> Sha1Fingerprint {
|
||||
// Padding
|
||||
let msg = pad(msg);
|
||||
|
||||
let mut h = [
|
||||
Wrapping(0x67452301_u32),
|
||||
Wrapping(0xEFCDAB89),
|
||||
Wrapping(0x98BADCFE),
|
||||
Wrapping(0x10325476),
|
||||
Wrapping(0xC3D2E1F0),
|
||||
];
|
||||
|
||||
let mut w = [Wrapping(0_u32); 80];
|
||||
|
||||
let read_word = |idx: usize| {
|
||||
let bytes = &msg[(idx * BYTES_IN_WORD)..][..BYTES_IN_WORD];
|
||||
Wrapping(u32::from_be_bytes(bytes.try_into().unwrap()))
|
||||
};
|
||||
|
||||
for block in 0..(msg.len() / (BLOCK_WORD_SIZE * BYTES_IN_WORD)) {
|
||||
for i in 0..16 {
|
||||
w[i] = read_word(BLOCK_WORD_SIZE * block + i);
|
||||
}
|
||||
|
||||
for t in 16..=79 {
|
||||
w[t] = (w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]).w_rotate_left(1);
|
||||
}
|
||||
let [mut a, mut b, mut c, mut d, mut e] = h;
|
||||
for t in 0..=79 {
|
||||
let temp = a.w_rotate_left(5) + f(t, b, c, d) + e + w[t] + k(t);
|
||||
[e, d, c, b, a] = [d, c, b.w_rotate_left(30), a, temp];
|
||||
}
|
||||
|
||||
h = [h[0] + a, h[1] + b, h[2] + c, h[3] + d, h[4] + e];
|
||||
}
|
||||
|
||||
let mut result = [0; 20];
|
||||
for i in 0..5 {
|
||||
result[(BYTES_IN_WORD * i)..(BYTES_IN_WORD * (i + 1))]
|
||||
.copy_from_slice(&h[i].0.to_be_bytes());
|
||||
}
|
||||
|
||||
Fingerprint(result)
|
||||
}
|
||||
|
||||
fn f(t: usize, b: Wrapping<u32>, c: Wrapping<u32>, d: Wrapping<u32>) -> Wrapping<u32> {
|
||||
match t {
|
||||
0..=19 => (b & c) | (!b & d),
|
||||
20..=39 => b ^ c ^ d,
|
||||
40..=59 => (b & c) | (b & d) | (c & d),
|
||||
_ => b ^ c ^ d,
|
||||
}
|
||||
}
|
||||
fn k(t: usize) -> Wrapping<u32> {
|
||||
match t {
|
||||
0..=19 => Wrapping(0x5A827999),
|
||||
20..=39 => Wrapping(0x6ED9EBA1),
|
||||
40..=59 => Wrapping(0x8F1BBCDC),
|
||||
_ => Wrapping(0xCA62C1D6),
|
||||
}
|
||||
}
|
||||
|
||||
fn pad(msg: &[u8]) -> Vec<u8> {
|
||||
// todo: this is pretty duplicated from md5 except len is BE.
|
||||
let mut msg_pad = msg.to_vec();
|
||||
msg_pad.push(0b10000000);
|
||||
|
||||
const ALREADY_PADDED_ZERO_BITS: usize = 7;
|
||||
let len = (msg.len() * BITS_IN_BYTE) + 1; // We always pad a 1
|
||||
let rest = len % 512;
|
||||
|
||||
let total_pad_zero_bits = 448_usize.wrapping_sub(rest) % 512;
|
||||
msg_pad.extend(
|
||||
std::iter::repeat(0).take((total_pad_zero_bits - ALREADY_PADDED_ZERO_BITS) / BITS_IN_BYTE),
|
||||
);
|
||||
msg_pad.extend_from_slice(&((msg.len() * BITS_IN_BYTE) as u64).to_be_bytes());
|
||||
assert!(msg_pad.len() % (512 / BITS_IN_BYTE) == 0);
|
||||
|
||||
msg_pad
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Sha1Fingerprint;
|
||||
use hex_literal::hex;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
fn pad() {
|
||||
let msg = [0b01100001, 0b01100010, 0b01100011, 0b01100100, 0b01100101];
|
||||
let padded = super::pad(&msg);
|
||||
assert_eq!(padded, hex!("61626364 65800000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000028"));
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn assert_same(s: &str, fingerprint: &str) {
|
||||
assert_eq!(
|
||||
super::hash(s.as_bytes()),
|
||||
Sha1Fingerprint::from_str(fingerprint).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hashing() {
|
||||
assert_same("", "da39a3ee5e6b4b0d3255bfef95601890afd80709");
|
||||
assert_same("a", "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8");
|
||||
assert_same("abc", "a9993e364706816aba3e25717850c26c9cd0d89d");
|
||||
assert_same("message digest", "c12252ceda8be8994d5fa0290a47231c1d16aae3");
|
||||
assert_same(
|
||||
"abcdefghijklmnopqrstuvwxyz",
|
||||
"32d10c7b8cf96570ca04ce37f2a19d84240d3a89",
|
||||
);
|
||||
assert_same(
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
||||
"761c457bf73b14d27e9e9265c46f4b4dda11f940",
|
||||
);
|
||||
assert_same(
|
||||
"12345678901234567890123456789012345678901234567890123456789012345678901234567890",
|
||||
"50abf5706a150990a08b2c5ea40fa0e585554732",
|
||||
);
|
||||
assert_same(
|
||||
"8217498327598324983271489372149837214987239847239847238947239847983247298347298347238947238947289\
|
||||
3257239587348957432098574389257438957348975849357438957489357849357439857438957439857438957348957346\
|
||||
289053420574238574395743298543895743890574389574398057348957348957438957439857438957438957438957438\
|
||||
4290854390765493025784932574893578394758943578493574893758493758493758493574389574389573489574389574\
|
||||
4290854390765493025784932574893578394758943578493574893758493758493758493574389574389573489574389574\
|
||||
4290854390765493025784932574893578394758943578493574893758493758493758493574389574389573489574389574\
|
||||
4290854390765493025784932574893578394758943578493574893758493758493758493574389574389573489574389574\
|
||||
4290854390765493025784932574893578394758943578493574893758493758493758493574389574389573489574389574",
|
||||
"bce570bbcccdc49d51d2a8e09ea5000beed0f31e",
|
||||
);
|
||||
}
|
||||
}
|
||||
11
src/utils.rs
11
src/utils.rs
|
|
@ -9,7 +9,7 @@ macro_rules! undefine_variable {
|
|||
};
|
||||
};
|
||||
}
|
||||
use std::{fmt::{Debug, Display}, str::FromStr};
|
||||
use std::{fmt::{Debug, Display}, num::Wrapping, str::FromStr};
|
||||
|
||||
pub(crate) use undefine_variable;
|
||||
|
||||
|
|
@ -58,3 +58,12 @@ impl<const LEN_BYTES: usize> Debug for Fingerprint<LEN_BYTES> {
|
|||
Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait WrappingExt {
|
||||
fn w_rotate_left(self, amount: u32) -> Self;
|
||||
}
|
||||
impl WrappingExt for Wrapping<u32> {
|
||||
fn w_rotate_left(self, amount: u32) -> Self {
|
||||
Self(self.0.rotate_left(amount))
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue