mod sha_cfg;
use crate::sha::sha_cfg::{
HASH224_INIT_VALUES, HASH256_INIT_VALUES, HASH384_INIT_VALUES, HASH512_INIT_VALUES, K_224_256,
K_384_512,
};
use std::{u128, usize};
#[cfg(test)]
mod sha_tests {
use super::{sha, ShaType};
#[test]
fn sha224() {
let message: String = String::from("SUNYSUNYSUNYSUNY");
let hash_bytes: Vec<u8> = sha(&message, ShaType::SHA224);
let mut hash_hex_str: String = String::new();
for byte in hash_bytes {
hash_hex_str.push_str(&format!("{:02x}", byte))
}
assert_eq!(
hash_hex_str,
String::from("678669c52c658fba0da32398376f700f367d2adf82291a269308f168")
);
}
#[test]
fn sha256() {
let message: String = String::from("SUNYSUNYSUNYSUNY");
let hash_bytes: Vec<u8> = sha(&message, ShaType::SHA256);
let mut hash_hex_str: String = String::new();
for byte in hash_bytes {
hash_hex_str.push_str(&format!("{:02x}", byte))
}
assert_eq!(
hash_hex_str,
String::from("142ea313267fe7670d878726214c30b6850a1e189edeff9cd4f769ba02371180")
);
}
#[test]
fn sha384() {
let message: String = String::from("SUNYSUNYSUNYSUNYSUNYSUNYSUNYSUNY");
let hash_bytes: Vec<u8> = sha(&message, ShaType::SHA384);
let mut hash_hex_str: String = String::new();
for byte in hash_bytes {
hash_hex_str.push_str(&format!("{:02x}", byte))
}
assert_eq!(
hash_hex_str,
String::from("b206401fad03e08d606bce8eab03f5116e01963dc5af6c8162b4020bc2a98c1ed7417399a0d611d259c04a6e6868f0e4")
);
}
#[test]
fn sha512() {
let message: String = String::from("SUNYSUNYSUNYSUNYSUNYSUNYSUNYSUNY");
let hash_bytes: Vec<u8> = sha(&message, ShaType::SHA512);
let mut hash_hex_str: String = String::new();
for byte in hash_bytes {
hash_hex_str.push_str(&format!("{:02x}", byte))
}
assert_eq!(
hash_hex_str,
String::from("e8d877cad3ada1877203bec43cad9fe6fba800b91afcf874069d0c5559ac4efd3645009564fe7490c0f13c6aa4c069e0d3aed4ea2dc36af77696008602ff459e")
);
}
}
pub enum ShaType {
SHA224,
SHA256,
SHA384,
SHA512,
}
pub fn sha(message: &str, sha_type: ShaType) -> Vec<u8> {
let mut message_padding: Vec<u8> = Vec::from(message);
padding(&mut message_padding, &sha_type);
let mut res: Vec<u8> = Vec::new();
match sha_type {
ShaType::SHA224 => {
let hash: [u32; 8] = iteration_64(&message_padding, &HASH224_INIT_VALUES, &K_224_256);
for word in hash.into_iter().take(7) {
res.append(&mut word.to_be_bytes().to_vec());
}
}
ShaType::SHA256 => {
let hash: [u32; 8] = iteration_64(&message_padding, &HASH256_INIT_VALUES, &K_224_256);
for word in hash {
res.append(&mut word.to_be_bytes().to_vec());
}
}
ShaType::SHA384 => {
let hash: [u64; 8] = iteration_80(&message_padding, &HASH384_INIT_VALUES, &K_384_512);
for word in hash.into_iter().take(6) {
res.append(&mut word.to_be_bytes().to_vec());
}
}
ShaType::SHA512 => {
let hash: [u64; 8] = iteration_80(&message_padding, &HASH512_INIT_VALUES, &K_384_512);
for word in hash {
res.append(&mut word.to_be_bytes().to_vec());
}
}
};
res
}
fn padding(message: &mut Vec<u8>, sha_type: &ShaType) {
let alignment: u32;
let remainer_expect: u32;
let message_bits = (message.len() as u32) * u8::BITS;
let mut message_length: Vec<u8>;
match sha_type {
ShaType::SHA224 | ShaType::SHA256 => {
alignment = 512;
remainer_expect = alignment - u64::BITS;
message_length = Vec::from((message_bits as u64).to_be_bytes());
}
ShaType::SHA384 | ShaType::SHA512 => {
alignment = 1024;
remainer_expect = alignment - u128::BITS;
message_length = Vec::from((message_bits as u128).to_be_bytes());
}
};
let remainer = message_bits % alignment;
let bits_padding = if remainer == remainer_expect {
alignment
} else {
if remainer > remainer_expect {
alignment + remainer_expect - remainer
} else {
remainer_expect - remainer
}
};
message.push(0x80);
for _ in 1..(bits_padding as u32) / u8::BITS {
message.push(0x00);
}
message.append(&mut message_length);
}
fn iteration_64(message_padding: &[u8], hash_init_values: &[u32; 8], k: &[u32; 64]) -> [u32; 8] {
let mut w: [u32; 64] = [0; 64];
let mut m: Vec<u32> = Vec::new();
let mut hash: [u32; 8] = hash_init_values.clone();
for chunk in message_padding.chunks((u32::BITS / u8::BITS) as usize) {
m.push(u32::from_be_bytes(
chunk.try_into().expect("Convert bytes to u32 failed!"),
));
}
let msg_total_bits: usize = m.len() * u32::BITS as usize;
let msg_blocks_num: usize = msg_total_bits / 512;
for mi in 0..msg_blocks_num {
for i in 0..16 {
w[i] = m[(mi * 16)..(mi * 16 + 16)][i];
}
for i in 16..64 {
let s0: u32 = w[i - 15].rotate_right(7) ^ w[i - 15].rotate_right(18) ^ (w[i - 15] >> 3);
let s1: u32 = w[i - 2].rotate_right(17) ^ w[i - 2].rotate_right(19) ^ (w[i - 2] >> 10);
w[i] = s1 + w[i - 7] + s0 + w[i - 16];
}
let mut a: u32 = hash[0];
let mut b: u32 = hash[1];
let mut c: u32 = hash[2];
let mut d: u32 = hash[3];
let mut e: u32 = hash[4];
let mut f: u32 = hash[5];
let mut g: u32 = hash[6];
let mut h: u32 = hash[7];
for i in 0..64 {
let s0: u32 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22);
let s1: u32 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25);
let maj: u32 = (a & b) ^ (a & c) ^ (b & c);
let ch: u32 = (e & f) ^ ((!e) & g);
let t1: u32 = h + s1 + ch + k[i] + w[i];
let t2: u32 = s0 + maj;
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
hash[0] += a;
hash[1] += b;
hash[2] += c;
hash[3] += d;
hash[4] += e;
hash[5] += f;
hash[6] += g;
hash[7] += h;
}
hash
}
fn iteration_80(message_padding: &[u8], hash_init_values: &[u64; 8], k: &[u64; 80]) -> [u64; 8] {
let mut w: [u64; 80] = [0; 80];
let mut m: Vec<u64> = Vec::new();
let mut hash = hash_init_values.clone();
for chunk in message_padding.chunks((u64::BITS / u8::BITS) as usize) {
m.push(u64::from_be_bytes(
chunk.try_into().expect("Convert bytes to u64 failed!"),
));
}
let msg_total_bits: usize = m.len() * u64::BITS as usize;
let msg_blocks_num: usize = msg_total_bits / 1024;
for mi in 0..msg_blocks_num {
for i in 0..16 {
w[i] = m[(mi * 16)..(mi * 16 + 16)][i];
}
for i in 16..80 {
let s0: u64 = w[i - 15].rotate_right(1) ^ w[i - 15].rotate_right(8) ^ (w[i - 15] >> 7);
let s1: u64 = w[i - 2].rotate_right(19) ^ w[i - 2].rotate_right(61) ^ (w[i - 2] >> 6);
w[i] = s1 + w[i - 16] + s0 + w[i - 7];
}
let mut a: u64 = hash[0];
let mut b: u64 = hash[1];
let mut c: u64 = hash[2];
let mut d: u64 = hash[3];
let mut e: u64 = hash[4];
let mut f: u64 = hash[5];
let mut g: u64 = hash[6];
let mut h: u64 = hash[7];
for i in 0..80 {
let s0: u64 = a.rotate_right(28) ^ a.rotate_right(34) ^ a.rotate_right(39);
let s1: u64 = e.rotate_right(14) ^ e.rotate_right(18) ^ e.rotate_right(41);
let maj: u64 = (a & b) ^ (a & c) ^ (b & c);
let ch: u64 = (e & f) ^ ((!e) & g);
let t1: u64 = h + s1 + ch + k[i] + w[i];
let t2: u64 = s0 + maj;
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
hash[0] += a;
hash[1] += b;
hash[2] += c;
hash[3] += d;
hash[4] += e;
hash[5] += f;
hash[6] += g;
hash[7] += h;
}
hash
}