#![allow(clippy::indexing_slicing, clippy::arithmetic_side_effects)]
use crate::algorithms::*;
pub const OUTPUT_SIZE: usize = 32;
pub const BLOCK_SIZE: usize = 64;
const INITIAL_STATE: [u32; 8] = [
0x6A09E667,
0xBB67AE85,
0x3C6EF372,
0xA54FF53A,
0x510E527F,
0x9B05688C,
0x1F83D9AB,
0x5BE0CD19,
];
pub fn sha256(data: &[u8]) -> [u8; OUTPUT_SIZE] {
let mut hasher = Sha256::new();
hasher.update(data);
hasher.finalize()
}
#[derive(Clone)]
pub struct Sha256 {
total: u64, state: [u32; 8], buffer: [u8; BLOCK_SIZE],
}
impl Drop for Sha256 {
fn drop(&mut self) {
crate::zeroize::Zeroize::zeroize(&mut self.state);
crate::zeroize::Zeroize::zeroize(&mut self.buffer);
self.total = 0;
}
}
impl Default for Sha256 {
fn default() -> Self {
Self::new()
}
}
impl core::fmt::Debug for Sha256 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("Sha256 { .. }")
}
}
impl Sha256 {
pub fn new() -> Self {
Sha256 { total: 0, state: INITIAL_STATE, buffer: [0u8; BLOCK_SIZE] }
}
pub fn reset(&mut self) {
*self = Self::new();
}
pub fn update(&mut self, mut input: &[u8]) {
if input.is_empty() { return; }
let mut left = (self.total & 0x3F) as usize;
let fill = 64 - left;
self.total = self.total.wrapping_add(input.len() as u64);
if left != 0 && input.len() >= fill {
self.buffer[left..].copy_from_slice(&input[..fill]);
process(&mut self.state, &self.buffer);
input = &input[fill..];
left = 0;
}
while input.len() >= 64 {
process(&mut self.state, &input[..64]);
input = &input[64..];
}
if !input.is_empty() {
self.buffer[left..left + input.len()].copy_from_slice(input);
}
}
pub fn finalize(mut self) -> [u8; OUTPUT_SIZE] {
let mut digest = [0u8; OUTPUT_SIZE];
self.finish(&mut digest);
digest
}
pub fn finalize_reset(&mut self) -> [u8; OUTPUT_SIZE] {
let mut digest = [0u8; OUTPUT_SIZE];
self.finish(&mut digest);
self.reset();
digest
}
fn finish(&mut self, digest: &mut [u8; OUTPUT_SIZE]) {
let mut last = (self.total & 0x3F) as usize;
self.buffer[last] = 0x80;
last += 1;
if last <= 56 {
self.buffer[last..56].fill(0);
} else {
self.buffer[last..].fill(0);
process(&mut self.state, &self.buffer);
self.buffer[..56].fill(0);
};
let bits = self.total.wrapping_shl(3);
let high: u32 = (bits >> 32) as u32;
let low: u32 = bits as u32;
put_u32(high, &mut self.buffer, 56);
put_u32(low , &mut self.buffer, 60);
process(&mut self.state, &self.buffer);
for (i, word) in self.state.iter().enumerate() {
put_u32(*word, digest, i * 4);
}
}
}
pub(crate) fn process(state: &mut [u32; 8], data: &[u8]) {
assert!(data.len() == 64, "invalid data length");
let mut w: [u32; 64] = [0; 64];
w[0] = get_u32(data, 0);
w[1] = get_u32(data, 4);
w[2] = get_u32(data, 8);
w[3] = get_u32(data, 12);
w[4] = get_u32(data, 16);
w[5] = get_u32(data, 20);
w[6] = get_u32(data, 24);
w[7] = get_u32(data, 28);
w[8] = get_u32(data, 32);
w[9] = get_u32(data, 36);
w[10] = get_u32(data, 40);
w[11] = get_u32(data, 44);
w[12] = get_u32(data, 48);
w[13] = get_u32(data, 52);
w[14] = get_u32(data, 56);
w[15] = get_u32(data, 60);
let mut a = state[0];
let mut b = state[1];
let mut c = state[2];
let mut d = state[3];
let mut e = state[4];
let mut f = state[5];
let mut g = state[6];
let mut h = state[7];
p( a, b, c, &mut d, e, f, g, &mut h, w[ 0], 0x428A2F98 );
p( h, a, b, &mut c, d, e, f, &mut g, w[ 1], 0x71374491 );
p( g, h, a, &mut b, c, d, e, &mut f, w[ 2], 0xB5C0FBCF );
p( f, g, h, &mut a, b, c, d, &mut e, w[ 3], 0xE9B5DBA5 );
p( e, f, g, &mut h, a, b, c, &mut d, w[ 4], 0x3956C25B );
p( d, e, f, &mut g, h, a, b, &mut c, w[ 5], 0x59F111F1 );
p( c, d, e, &mut f, g, h, a, &mut b, w[ 6], 0x923F82A4 );
p( b, c, d, &mut e, f, g, h, &mut a, w[ 7], 0xAB1C5ED5 );
p( a, b, c, &mut d, e, f, g, &mut h, w[ 8], 0xD807AA98 );
p( h, a, b, &mut c, d, e, f, &mut g, w[ 9], 0x12835B01 );
p( g, h, a, &mut b, c, d, e, &mut f, w[10], 0x243185BE );
p( f, g, h, &mut a, b, c, d, &mut e, w[11], 0x550C7DC3 );
p( e, f, g, &mut h, a, b, c, &mut d, w[12], 0x72BE5D74 );
p( d, e, f, &mut g, h, a, b, &mut c, w[13], 0x80DEB1FE );
p( c, d, e, &mut f, g, h, a, &mut b, w[14], 0x9BDC06A7 );
p( b, c, d, &mut e, f, g, h, &mut a, w[15], 0xC19BF174 );
p( a, b, c, &mut d, e, f, g, &mut h, r(&mut w, 16), 0xE49B69C1 );
p( h, a, b, &mut c, d, e, f, &mut g, r(&mut w, 17), 0xEFBE4786 );
p( g, h, a, &mut b, c, d, e, &mut f, r(&mut w, 18), 0x0FC19DC6 );
p( f, g, h, &mut a, b, c, d, &mut e, r(&mut w, 19), 0x240CA1CC );
p( e, f, g, &mut h, a, b, c, &mut d, r(&mut w, 20), 0x2DE92C6F );
p( d, e, f, &mut g, h, a, b, &mut c, r(&mut w, 21), 0x4A7484AA );
p( c, d, e, &mut f, g, h, a, &mut b, r(&mut w, 22), 0x5CB0A9DC );
p( b, c, d, &mut e, f, g, h, &mut a, r(&mut w, 23), 0x76F988DA );
p( a, b, c, &mut d, e, f, g, &mut h, r(&mut w, 24), 0x983E5152 );
p( h, a, b, &mut c, d, e, f, &mut g, r(&mut w, 25), 0xA831C66D );
p( g, h, a, &mut b, c, d, e, &mut f, r(&mut w, 26), 0xB00327C8 );
p( f, g, h, &mut a, b, c, d, &mut e, r(&mut w, 27), 0xBF597FC7 );
p( e, f, g, &mut h, a, b, c, &mut d, r(&mut w, 28), 0xC6E00BF3 );
p( d, e, f, &mut g, h, a, b, &mut c, r(&mut w, 29), 0xD5A79147 );
p( c, d, e, &mut f, g, h, a, &mut b, r(&mut w, 30), 0x06CA6351 );
p( b, c, d, &mut e, f, g, h, &mut a, r(&mut w, 31), 0x14292967 );
p( a, b, c, &mut d, e, f, g, &mut h, r(&mut w, 32), 0x27B70A85 );
p( h, a, b, &mut c, d, e, f, &mut g, r(&mut w, 33), 0x2E1B2138 );
p( g, h, a, &mut b, c, d, e, &mut f, r(&mut w, 34), 0x4D2C6DFC );
p( f, g, h, &mut a, b, c, d, &mut e, r(&mut w, 35), 0x53380D13 );
p( e, f, g, &mut h, a, b, c, &mut d, r(&mut w, 36), 0x650A7354 );
p( d, e, f, &mut g, h, a, b, &mut c, r(&mut w, 37), 0x766A0ABB );
p( c, d, e, &mut f, g, h, a, &mut b, r(&mut w, 38), 0x81C2C92E );
p( b, c, d, &mut e, f, g, h, &mut a, r(&mut w, 39), 0x92722C85 );
p( a, b, c, &mut d, e, f, g, &mut h, r(&mut w, 40), 0xA2BFE8A1 );
p( h, a, b, &mut c, d, e, f, &mut g, r(&mut w, 41), 0xA81A664B );
p( g, h, a, &mut b, c, d, e, &mut f, r(&mut w, 42), 0xC24B8B70 );
p( f, g, h, &mut a, b, c, d, &mut e, r(&mut w, 43), 0xC76C51A3 );
p( e, f, g, &mut h, a, b, c, &mut d, r(&mut w, 44), 0xD192E819 );
p( d, e, f, &mut g, h, a, b, &mut c, r(&mut w, 45), 0xD6990624 );
p( c, d, e, &mut f, g, h, a, &mut b, r(&mut w, 46), 0xF40E3585 );
p( b, c, d, &mut e, f, g, h, &mut a, r(&mut w, 47), 0x106AA070 );
p( a, b, c, &mut d, e, f, g, &mut h, r(&mut w, 48), 0x19A4C116 );
p( h, a, b, &mut c, d, e, f, &mut g, r(&mut w, 49), 0x1E376C08 );
p( g, h, a, &mut b, c, d, e, &mut f, r(&mut w, 50), 0x2748774C );
p( f, g, h, &mut a, b, c, d, &mut e, r(&mut w, 51), 0x34B0BCB5 );
p( e, f, g, &mut h, a, b, c, &mut d, r(&mut w, 52), 0x391C0CB3 );
p( d, e, f, &mut g, h, a, b, &mut c, r(&mut w, 53), 0x4ED8AA4A );
p( c, d, e, &mut f, g, h, a, &mut b, r(&mut w, 54), 0x5B9CCA4F );
p( b, c, d, &mut e, f, g, h, &mut a, r(&mut w, 55), 0x682E6FF3 );
p( a, b, c, &mut d, e, f, g, &mut h, r(&mut w, 56), 0x748F82EE );
p( h, a, b, &mut c, d, e, f, &mut g, r(&mut w, 57), 0x78A5636F );
p( g, h, a, &mut b, c, d, e, &mut f, r(&mut w, 58), 0x84C87814 );
p( f, g, h, &mut a, b, c, d, &mut e, r(&mut w, 59), 0x8CC70208 );
p( e, f, g, &mut h, a, b, c, &mut d, r(&mut w, 60), 0x90BEFFFA );
p( d, e, f, &mut g, h, a, b, &mut c, r(&mut w, 61), 0xA4506CEB );
p( c, d, e, &mut f, g, h, a, &mut b, r(&mut w, 62), 0xBEF9A3F7 );
p( b, c, d, &mut e, f, g, h, &mut a, r(&mut w, 63), 0xC67178F2 );
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);
state[4] = state[4].wrapping_add(e);
state[5] = state[5].wrapping_add(f);
state[6] = state[6].wrapping_add(g);
state[7] = state[7].wrapping_add(h);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::util::SliceToHex;
fn hex(msg: &[u8]) -> String {
<[u8]>::slice_to_hex(&sha256(msg))
}
#[test]
fn one_block_message() {
assert_eq!(hex(b"abc"), "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
}
#[test]
fn multi_block_message() {
let msg = b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
let mut ctx = Sha256::new();
ctx.update(msg);
assert_eq!(ctx.state, INITIAL_STATE);
assert_eq!(<[u8]>::slice_to_hex(&ctx.finalize()),
"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1");
}
#[test]
#[cfg_attr(miri, ignore = "too slow under Miri")]
fn long_message() {
let msg = "a".repeat(1000000);
assert_eq!(hex(msg.as_bytes()), "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
}
#[test]
fn padding_boundaries() {
let cases: [(usize, &str); 4] = [
(0, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"),
(55, "9f4390f8d30c2dd92ec9f095b65e2b9ae9b0a925a5258e241c9f1e910f734318"),
(56, "b35439a4ac6f0948b6d6f9e3c6af0f5f590ce20f1bde7090ef7970686ec6738a"),
(64, "ffe054fe7ae0cb6dc65c3af9b61d5209f439851db43d0ba5997337df154668eb"),
];
for &(len, val) in cases.iter() {
assert_eq!(hex("a".repeat(len).as_bytes()), val, "length {}", len);
}
}
#[test]
#[cfg_attr(miri, ignore = "too slow under Miri")]
fn chunked_message() {
let msg = "a".repeat(1000000);
let mut ctx = Sha256::new();
for chunk in msg.as_bytes().chunks(37) {
ctx.update(chunk);
}
assert_eq!(<[u8]>::slice_to_hex(&ctx.finalize_reset()),
"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
ctx.update(b"abc");
assert_eq!(ctx.finalize(), sha256(b"abc"));
}
}