mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-31 13:40:15 +03:00
auto merge of #8174 : DaGenix/rust/digest-improvements, r=brson
Same content as #8097, but bors had an issue with that pull request. Opening a new one.
This commit is contained in:
@@ -0,0 +1,327 @@
|
||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::num::One;
|
||||
use std::vec::bytes::{MutableByteVector, copy_memory};
|
||||
|
||||
|
||||
/// Write a u64 into a vector, which must be 8 bytes long. The value is written in big-endian
|
||||
/// format.
|
||||
pub fn write_u64_be(dst: &mut[u8], input: u64) {
|
||||
use std::cast::transmute;
|
||||
use std::unstable::intrinsics::to_be64;
|
||||
assert!(dst.len() == 8);
|
||||
unsafe {
|
||||
let x: *mut i64 = transmute(dst.unsafe_mut_ref(0));
|
||||
*x = to_be64(input as i64);
|
||||
}
|
||||
}
|
||||
|
||||
/// Write a u32 into a vector, which must be 4 bytes long. The value is written in big-endian
|
||||
/// format.
|
||||
pub fn write_u32_be(dst: &mut[u8], input: u32) {
|
||||
use std::cast::transmute;
|
||||
use std::unstable::intrinsics::to_be32;
|
||||
assert!(dst.len() == 4);
|
||||
unsafe {
|
||||
let x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
|
||||
*x = to_be32(input as i32);
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a vector of bytes into a vector of u64s. The values are read in big-endian format.
|
||||
pub fn read_u64v_be(dst: &mut[u64], input: &[u8]) {
|
||||
use std::cast::transmute;
|
||||
use std::unstable::intrinsics::to_be64;
|
||||
assert!(dst.len() * 8 == input.len());
|
||||
unsafe {
|
||||
let mut x: *mut i64 = transmute(dst.unsafe_mut_ref(0));
|
||||
let mut y: *i64 = transmute(input.unsafe_ref(0));
|
||||
do dst.len().times() {
|
||||
*x = to_be64(*y);
|
||||
x = x.offset(1);
|
||||
y = y.offset(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a vector of bytes into a vector of u32s. The values are read in big-endian format.
|
||||
pub fn read_u32v_be(dst: &mut[u32], input: &[u8]) {
|
||||
use std::cast::transmute;
|
||||
use std::unstable::intrinsics::to_be32;
|
||||
assert!(dst.len() * 4 == input.len());
|
||||
unsafe {
|
||||
let mut x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
|
||||
let mut y: *i32 = transmute(input.unsafe_ref(0));
|
||||
do dst.len().times() {
|
||||
*x = to_be32(*y);
|
||||
x = x.offset(1);
|
||||
y = y.offset(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Returns true if adding the two parameters will result in integer overflow
|
||||
pub fn will_add_overflow<T: Int + Unsigned>(x: T, y: T) -> bool {
|
||||
// This doesn't handle negative values! Don't copy this code elsewhere without considering if
|
||||
// negative values are important to you!
|
||||
let max: T = Bounded::max_value();
|
||||
return x > max - y;
|
||||
}
|
||||
|
||||
/// Shifts the second parameter and then adds it to the first. fails!() if there would be unsigned
|
||||
/// integer overflow.
|
||||
pub fn shift_add_check_overflow<T: Int + Unsigned + Clone>(x: T, mut y: T, shift: T) -> T {
|
||||
if y.leading_zeros() < shift {
|
||||
fail!("Could not add values - integer overflow.");
|
||||
}
|
||||
y = y << shift;
|
||||
|
||||
if will_add_overflow(x.clone(), y.clone()) {
|
||||
fail!("Could not add values - integer overflow.");
|
||||
}
|
||||
|
||||
return x + y;
|
||||
}
|
||||
|
||||
/// Shifts the second parameter and then adds it to the first, which is a tuple where the first
|
||||
/// element is the high order value. fails!() if there would be unsigned integer overflow.
|
||||
pub fn shift_add_check_overflow_tuple
|
||||
<T: Int + Unsigned + Clone>
|
||||
(x: (T, T), mut y: T, shift: T) -> (T, T) {
|
||||
if y.leading_zeros() < shift {
|
||||
fail!("Could not add values - integer overflow.");
|
||||
}
|
||||
y = y << shift;
|
||||
|
||||
match x {
|
||||
(hi, low) => {
|
||||
let one: T = One::one();
|
||||
if will_add_overflow(low.clone(), y.clone()) {
|
||||
if will_add_overflow(hi.clone(), one.clone()) {
|
||||
fail!("Could not add values - integer overflow.");
|
||||
} else {
|
||||
return (hi + one, low + y);
|
||||
}
|
||||
} else {
|
||||
return (hi, low + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A FixedBuffer, likes its name implies, is a fixed size buffer. When the buffer becomes full, it
|
||||
/// must be processed. The input() method takes care of processing and then clearing the buffer
|
||||
/// automatically. However, other methods do not and require the caller to process the buffer. Any
|
||||
/// method that modifies the buffer directory or provides the caller with bytes that can be modifies
|
||||
/// results in those bytes being marked as used by the buffer.
|
||||
pub trait FixedBuffer {
|
||||
/// Input a vector of bytes. If the buffer becomes full, proccess it with the provided
|
||||
/// function and then clear the buffer.
|
||||
fn input(&mut self, input: &[u8], func: &fn(&[u8]));
|
||||
|
||||
/// Reset the buffer.
|
||||
fn reset(&mut self);
|
||||
|
||||
/// Zero the buffer up until the specified index. The buffer position currently must not be
|
||||
/// greater than that index.
|
||||
fn zero_until(&mut self, idx: uint);
|
||||
|
||||
/// Get a slice of the buffer of the specified size. There must be at least that many bytes
|
||||
/// remaining in the buffer.
|
||||
fn next<'s>(&'s mut self, len: uint) -> &'s mut [u8];
|
||||
|
||||
/// Get the current buffer. The buffer must already be full. This clears the buffer as well.
|
||||
fn full_buffer<'s>(&'s mut self) -> &'s [u8];
|
||||
|
||||
/// Get the current position of the buffer.
|
||||
fn position(&self) -> uint;
|
||||
|
||||
/// Get the number of bytes remaining in the buffer until it is full.
|
||||
fn remaining(&self) -> uint;
|
||||
|
||||
/// Get the size of the buffer
|
||||
fn size(&self) -> uint;
|
||||
}
|
||||
|
||||
macro_rules! impl_fixed_buffer( ($name:ident, $size:expr) => (
|
||||
impl FixedBuffer for $name {
|
||||
fn input(&mut self, input: &[u8], func: &fn(&[u8])) {
|
||||
let mut i = 0;
|
||||
|
||||
// FIXME: #6304 - This local variable shouldn't be necessary.
|
||||
let size = $size;
|
||||
|
||||
// If there is already data in the buffer, copy as much as we can into it and process
|
||||
// the data if the buffer becomes full.
|
||||
if self.buffer_idx != 0 {
|
||||
let buffer_remaining = size - self.buffer_idx;
|
||||
if input.len() >= buffer_remaining {
|
||||
copy_memory(
|
||||
self.buffer.mut_slice(self.buffer_idx, size),
|
||||
input.slice_to(buffer_remaining),
|
||||
buffer_remaining);
|
||||
self.buffer_idx = 0;
|
||||
func(self.buffer);
|
||||
i += buffer_remaining;
|
||||
} else {
|
||||
copy_memory(
|
||||
self.buffer.mut_slice(self.buffer_idx, self.buffer_idx + input.len()),
|
||||
input,
|
||||
input.len());
|
||||
self.buffer_idx += input.len();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// While we have at least a full buffer size chunks's worth of data, process that data
|
||||
// without copying it into the buffer
|
||||
while input.len() - i >= size {
|
||||
func(input.slice(i, i + size));
|
||||
i += size;
|
||||
}
|
||||
|
||||
// Copy any input data into the buffer. At this point in the method, the ammount of
|
||||
// data left in the input vector will be less than the buffer size and the buffer will
|
||||
// be empty.
|
||||
let input_remaining = input.len() - i;
|
||||
copy_memory(
|
||||
self.buffer.mut_slice(0, input_remaining),
|
||||
input.slice_from(i),
|
||||
input.len() - i);
|
||||
self.buffer_idx += input_remaining;
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.buffer_idx = 0;
|
||||
}
|
||||
|
||||
fn zero_until(&mut self, idx: uint) {
|
||||
assert!(idx >= self.buffer_idx);
|
||||
self.buffer.mut_slice(self.buffer_idx, idx).set_memory(0);
|
||||
self.buffer_idx = idx;
|
||||
}
|
||||
|
||||
fn next<'s>(&'s mut self, len: uint) -> &'s mut [u8] {
|
||||
self.buffer_idx += len;
|
||||
return self.buffer.mut_slice(self.buffer_idx - len, self.buffer_idx);
|
||||
}
|
||||
|
||||
fn full_buffer<'s>(&'s mut self) -> &'s [u8] {
|
||||
assert!(self.buffer_idx == $size);
|
||||
self.buffer_idx = 0;
|
||||
return self.buffer.slice_to($size);
|
||||
}
|
||||
|
||||
fn position(&self) -> uint { self.buffer_idx }
|
||||
|
||||
fn remaining(&self) -> uint { $size - self.buffer_idx }
|
||||
|
||||
fn size(&self) -> uint { $size }
|
||||
}
|
||||
))
|
||||
|
||||
|
||||
/// A fixed size buffer of 64 bytes useful for cryptographic operations.
|
||||
pub struct FixedBuffer64 {
|
||||
priv buffer: [u8, ..64],
|
||||
priv buffer_idx: uint,
|
||||
}
|
||||
|
||||
impl FixedBuffer64 {
|
||||
/// Create a new buffer
|
||||
pub fn new() -> FixedBuffer64 {
|
||||
return FixedBuffer64 {
|
||||
buffer: [0u8, ..64],
|
||||
buffer_idx: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl_fixed_buffer!(FixedBuffer64, 64)
|
||||
|
||||
/// A fixed size buffer of 128 bytes useful for cryptographic operations.
|
||||
pub struct FixedBuffer128 {
|
||||
priv buffer: [u8, ..128],
|
||||
priv buffer_idx: uint,
|
||||
}
|
||||
|
||||
impl FixedBuffer128 {
|
||||
/// Create a new buffer
|
||||
pub fn new() -> FixedBuffer128 {
|
||||
return FixedBuffer128 {
|
||||
buffer: [0u8, ..128],
|
||||
buffer_idx: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl_fixed_buffer!(FixedBuffer128, 128)
|
||||
|
||||
|
||||
/// The StandardPadding trait adds a method useful for various hash algorithms to a FixedBuffer
|
||||
/// struct.
|
||||
pub trait StandardPadding {
|
||||
/// Add standard padding to the buffer. The buffer must not be full when this method is called
|
||||
/// and is guaranteed to have exactly rem remaining bytes when it returns. If there are not at
|
||||
/// least rem bytes available, the buffer will be zero padded, processed, cleared, and then
|
||||
/// filled with zeros again until only rem bytes are remaining.
|
||||
fn standard_padding(&mut self, rem: uint, func: &fn(&[u8]));
|
||||
}
|
||||
|
||||
impl <T: FixedBuffer> StandardPadding for T {
|
||||
fn standard_padding(&mut self, rem: uint, func: &fn(&[u8])) {
|
||||
let size = self.size();
|
||||
|
||||
self.next(1)[0] = 128;
|
||||
|
||||
if self.remaining() < rem {
|
||||
self.zero_until(size);
|
||||
func(self.full_buffer());
|
||||
}
|
||||
|
||||
self.zero_until(size - rem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::rand::IsaacRng;
|
||||
use std::rand::RngUtil;
|
||||
use std::vec;
|
||||
|
||||
use digest::Digest;
|
||||
|
||||
/// Feed 1,000,000 'a's into the digest with varying input sizes and check that the result is
|
||||
/// correct.
|
||||
pub fn test_digest_1million_random<D: Digest>(digest: &mut D, blocksize: uint, expected: &str) {
|
||||
let total_size = 1000000;
|
||||
let buffer = vec::from_elem(blocksize * 2, 'a' as u8);
|
||||
let mut rng = IsaacRng::new_unseeded();
|
||||
let mut count = 0;
|
||||
|
||||
digest.reset();
|
||||
|
||||
while count < total_size {
|
||||
let next: uint = rng.gen_uint_range(0, 2 * blocksize + 1);
|
||||
let remaining = total_size - count;
|
||||
let size = if next > remaining { remaining } else { next };
|
||||
digest.input(buffer.slice_to(size));
|
||||
count += size;
|
||||
}
|
||||
|
||||
let result_str = digest.result_str();
|
||||
|
||||
assert!(expected == result_str);
|
||||
}
|
||||
}
|
||||
@@ -8,10 +8,10 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
use std::uint;
|
||||
use std::vec;
|
||||
|
||||
|
||||
/**
|
||||
* The Digest trait specifies an interface common to digest functions, such as SHA-1 and the SHA-2
|
||||
* family of digest functions.
|
||||
@@ -28,6 +28,10 @@ pub trait Digest {
|
||||
|
||||
/**
|
||||
* Retrieve the digest result. This method may be called multiple times.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * out - the vector to hold the result. Must be large enough to contain output_bits().
|
||||
*/
|
||||
fn result(&mut self, out: &mut [u8]);
|
||||
|
||||
@@ -41,6 +45,27 @@ pub trait Digest {
|
||||
* Get the output size in bits.
|
||||
*/
|
||||
fn output_bits(&self) -> uint;
|
||||
|
||||
/**
|
||||
* Convenience functon that feeds a string into a digest
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * in The string to feed into the digest
|
||||
*/
|
||||
fn input_str(&mut self, input: &str) {
|
||||
self.input(input.as_bytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience functon that retrieves the result of a digest as a
|
||||
* ~str in hexadecimal format.
|
||||
*/
|
||||
fn result_str(&mut self) -> ~str {
|
||||
let mut buf = vec::from_elem((self.output_bits()+7)/8, 0u8);
|
||||
self.result(buf);
|
||||
return to_hex(buf);
|
||||
}
|
||||
}
|
||||
|
||||
fn to_hex(rr: &[u8]) -> ~str {
|
||||
@@ -54,34 +79,3 @@ fn to_hex(rr: &[u8]) -> ~str {
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/// Contains utility methods for Digests.
|
||||
/// FIXME: #7339: Convert to default methods when issues with them are resolved.
|
||||
pub trait DigestUtil {
|
||||
/**
|
||||
* Convenience functon that feeds a string into a digest
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * in The string to feed into the digest
|
||||
*/
|
||||
fn input_str(&mut self, input: &str);
|
||||
|
||||
/**
|
||||
* Convenience functon that retrieves the result of a digest as a
|
||||
* ~str in hexadecimal format.
|
||||
*/
|
||||
fn result_str(&mut self) -> ~str;
|
||||
}
|
||||
|
||||
impl<D: Digest> DigestUtil for D {
|
||||
fn input_str(&mut self, input: &str) {
|
||||
self.input(input.as_bytes());
|
||||
}
|
||||
|
||||
fn result_str(&mut self) -> ~str {
|
||||
let mut buf = vec::from_elem((self.output_bits()+7)/8, 0u8);
|
||||
self.result(buf);
|
||||
return to_hex(buf);
|
||||
}
|
||||
}
|
||||
|
||||
+48
-123
@@ -23,6 +23,8 @@
|
||||
*/
|
||||
|
||||
|
||||
use cryptoutil::{write_u32_be, read_u32v_be, shift_add_check_overflow, FixedBuffer, FixedBuffer64,
|
||||
StandardPadding};
|
||||
use digest::Digest;
|
||||
|
||||
/*
|
||||
@@ -33,7 +35,6 @@
|
||||
|
||||
// Some unexported constants
|
||||
static DIGEST_BUF_LEN: uint = 5u;
|
||||
static MSG_BLOCK_LEN: uint = 64u;
|
||||
static WORK_BUF_LEN: uint = 80u;
|
||||
static K0: u32 = 0x5A827999u32;
|
||||
static K1: u32 = 0x6ED9EBA1u32;
|
||||
@@ -43,58 +44,38 @@
|
||||
/// Structure representing the state of a Sha1 computation
|
||||
pub struct Sha1 {
|
||||
priv h: [u32, ..DIGEST_BUF_LEN],
|
||||
priv len_low: u32,
|
||||
priv len_high: u32,
|
||||
priv msg_block: [u8, ..MSG_BLOCK_LEN],
|
||||
priv msg_block_idx: uint,
|
||||
priv length_bits: u64,
|
||||
priv buffer: FixedBuffer64,
|
||||
priv computed: bool,
|
||||
priv work_buf: [u32, ..WORK_BUF_LEN]
|
||||
}
|
||||
|
||||
fn add_input(st: &mut Sha1, msg: &[u8]) {
|
||||
assert!((!st.computed));
|
||||
foreach element in msg.iter() {
|
||||
st.msg_block[st.msg_block_idx] = *element;
|
||||
st.msg_block_idx += 1;
|
||||
st.len_low += 8;
|
||||
if st.len_low == 0 {
|
||||
st.len_high += 1;
|
||||
if st.len_high == 0 {
|
||||
// FIXME: Need better failure mode (#2346)
|
||||
fail!();
|
||||
}
|
||||
}
|
||||
if st.msg_block_idx == MSG_BLOCK_LEN { process_msg_block(st); }
|
||||
}
|
||||
// Assumes that msg.len() can be converted to u64 without overflow
|
||||
st.length_bits = shift_add_check_overflow(st.length_bits, msg.len() as u64, 3);
|
||||
st.buffer.input(msg, |d: &[u8]| { process_msg_block(d, &mut st.h); });
|
||||
}
|
||||
|
||||
fn process_msg_block(st: &mut Sha1) {
|
||||
fn process_msg_block(data: &[u8], h: &mut [u32, ..DIGEST_BUF_LEN]) {
|
||||
let mut t: int; // Loop counter
|
||||
let mut w = st.work_buf;
|
||||
|
||||
let mut w = [0u32, ..WORK_BUF_LEN];
|
||||
|
||||
// Initialize the first 16 words of the vector w
|
||||
t = 0;
|
||||
while t < 16 {
|
||||
let mut tmp;
|
||||
tmp = (st.msg_block[t * 4] as u32) << 24u32;
|
||||
tmp = tmp | (st.msg_block[t * 4 + 1] as u32) << 16u32;
|
||||
tmp = tmp | (st.msg_block[t * 4 + 2] as u32) << 8u32;
|
||||
tmp = tmp | (st.msg_block[t * 4 + 3] as u32);
|
||||
w[t] = tmp;
|
||||
t += 1;
|
||||
}
|
||||
read_u32v_be(w.mut_slice(0, 16), data);
|
||||
|
||||
// Initialize the rest of vector w
|
||||
t = 16;
|
||||
while t < 80 {
|
||||
let val = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16];
|
||||
w[t] = circular_shift(1, val);
|
||||
t += 1;
|
||||
}
|
||||
let mut a = st.h[0];
|
||||
let mut b = st.h[1];
|
||||
let mut c = st.h[2];
|
||||
let mut d = st.h[3];
|
||||
let mut e = st.h[4];
|
||||
let mut a = h[0];
|
||||
let mut b = h[1];
|
||||
let mut c = h[2];
|
||||
let mut d = h[3];
|
||||
let mut e = h[4];
|
||||
let mut temp: u32;
|
||||
t = 0;
|
||||
while t < 20 {
|
||||
@@ -135,12 +116,11 @@ fn process_msg_block(st: &mut Sha1) {
|
||||
a = temp;
|
||||
t += 1;
|
||||
}
|
||||
st.h[0] = st.h[0] + a;
|
||||
st.h[1] = st.h[1] + b;
|
||||
st.h[2] = st.h[2] + c;
|
||||
st.h[3] = st.h[3] + d;
|
||||
st.h[4] = st.h[4] + e;
|
||||
st.msg_block_idx = 0;
|
||||
h[0] += a;
|
||||
h[1] += b;
|
||||
h[2] += c;
|
||||
h[3] += d;
|
||||
h[4] += e;
|
||||
}
|
||||
|
||||
fn circular_shift(bits: u32, word: u32) -> u32 {
|
||||
@@ -148,60 +128,20 @@ fn circular_shift(bits: u32, word: u32) -> u32 {
|
||||
}
|
||||
|
||||
fn mk_result(st: &mut Sha1, rs: &mut [u8]) {
|
||||
if !st.computed { pad_msg(st); st.computed = true; }
|
||||
let mut i = 0;
|
||||
foreach ptr_hpart in st.h.mut_iter() {
|
||||
let hpart = *ptr_hpart;
|
||||
rs[i] = (hpart >> 24u32 & 0xFFu32) as u8;
|
||||
rs[i+1] = (hpart >> 16u32 & 0xFFu32) as u8;
|
||||
rs[i+2] = (hpart >> 8u32 & 0xFFu32) as u8;
|
||||
rs[i+3] = (hpart & 0xFFu32) as u8;
|
||||
i += 4;
|
||||
}
|
||||
}
|
||||
if !st.computed {
|
||||
st.buffer.standard_padding(8, |d: &[u8]| { process_msg_block(d, &mut st.h) });
|
||||
write_u32_be(st.buffer.next(4), (st.length_bits >> 32) as u32 );
|
||||
write_u32_be(st.buffer.next(4), st.length_bits as u32);
|
||||
process_msg_block(st.buffer.full_buffer(), &mut st.h);
|
||||
|
||||
/*
|
||||
* According to the standard, the message must be padded to an even
|
||||
* 512 bits. The first padding bit must be a '1'. The last 64 bits
|
||||
* represent the length of the original message. All bits in between
|
||||
* should be 0. This function will pad the message according to those
|
||||
* rules by filling the msg_block vector accordingly. It will also
|
||||
* call process_msg_block() appropriately. When it returns, it
|
||||
* can be assumed that the message digest has been computed.
|
||||
*/
|
||||
fn pad_msg(st: &mut Sha1) {
|
||||
/*
|
||||
* Check to see if the current message block is too small to hold
|
||||
* the initial padding bits and length. If so, we will pad the
|
||||
* block, process it, and then continue padding into a second block.
|
||||
*/
|
||||
if st.msg_block_idx > 55 {
|
||||
st.msg_block[st.msg_block_idx] = 0x80;
|
||||
st.msg_block_idx += 1;
|
||||
while st.msg_block_idx < MSG_BLOCK_LEN {
|
||||
st.msg_block[st.msg_block_idx] = 0;
|
||||
st.msg_block_idx += 1;
|
||||
}
|
||||
process_msg_block(st);
|
||||
} else {
|
||||
st.msg_block[st.msg_block_idx] = 0x80;
|
||||
st.msg_block_idx += 1;
|
||||
}
|
||||
while st.msg_block_idx < 56 {
|
||||
st.msg_block[st.msg_block_idx] = 0u8;
|
||||
st.msg_block_idx += 1;
|
||||
st.computed = true;
|
||||
}
|
||||
|
||||
// Store the message length as the last 8 octets
|
||||
st.msg_block[56] = (st.len_high >> 24u32 & 0xFFu32) as u8;
|
||||
st.msg_block[57] = (st.len_high >> 16u32 & 0xFFu32) as u8;
|
||||
st.msg_block[58] = (st.len_high >> 8u32 & 0xFFu32) as u8;
|
||||
st.msg_block[59] = (st.len_high & 0xFFu32) as u8;
|
||||
st.msg_block[60] = (st.len_low >> 24u32 & 0xFFu32) as u8;
|
||||
st.msg_block[61] = (st.len_low >> 16u32 & 0xFFu32) as u8;
|
||||
st.msg_block[62] = (st.len_low >> 8u32 & 0xFFu32) as u8;
|
||||
st.msg_block[63] = (st.len_low & 0xFFu32) as u8;
|
||||
process_msg_block(st);
|
||||
write_u32_be(rs.mut_slice(0, 4), st.h[0]);
|
||||
write_u32_be(rs.mut_slice(4, 8), st.h[1]);
|
||||
write_u32_be(rs.mut_slice(8, 12), st.h[2]);
|
||||
write_u32_be(rs.mut_slice(12, 16), st.h[3]);
|
||||
write_u32_be(rs.mut_slice(16, 20), st.h[4]);
|
||||
}
|
||||
|
||||
impl Sha1 {
|
||||
@@ -209,12 +149,9 @@ impl Sha1 {
|
||||
pub fn new() -> Sha1 {
|
||||
let mut st = Sha1 {
|
||||
h: [0u32, ..DIGEST_BUF_LEN],
|
||||
len_low: 0u32,
|
||||
len_high: 0u32,
|
||||
msg_block: [0u8, ..MSG_BLOCK_LEN],
|
||||
msg_block_idx: 0,
|
||||
length_bits: 0u64,
|
||||
buffer: FixedBuffer64::new(),
|
||||
computed: false,
|
||||
work_buf: [0u32, ..WORK_BUF_LEN]
|
||||
};
|
||||
st.reset();
|
||||
return st;
|
||||
@@ -223,14 +160,13 @@ pub fn new() -> Sha1 {
|
||||
|
||||
impl Digest for Sha1 {
|
||||
pub fn reset(&mut self) {
|
||||
self.len_low = 0;
|
||||
self.len_high = 0;
|
||||
self.msg_block_idx = 0;
|
||||
self.length_bits = 0;
|
||||
self.h[0] = 0x67452301u32;
|
||||
self.h[1] = 0xEFCDAB89u32;
|
||||
self.h[2] = 0x98BADCFEu32;
|
||||
self.h[3] = 0x10325476u32;
|
||||
self.h[4] = 0xC3D2E1F0u32;
|
||||
self.buffer.reset();
|
||||
self.computed = false;
|
||||
}
|
||||
pub fn input(&mut self, msg: &[u8]) { add_input(self, msg); }
|
||||
@@ -240,8 +176,8 @@ pub fn output_bits(&self) -> uint { 160 }
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use digest::{Digest, DigestUtil};
|
||||
use cryptoutil::test::test_digest_1million_random;
|
||||
use digest::Digest;
|
||||
use sha1::Sha1;
|
||||
|
||||
#[deriving(Clone)]
|
||||
@@ -253,15 +189,6 @@ struct Test {
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
fn a_million_letter_a() -> ~str {
|
||||
let mut i = 0;
|
||||
let mut rs = ~"";
|
||||
while i < 100000 {
|
||||
rs.push_str("aaaaaaaaaa");
|
||||
i += 1;
|
||||
}
|
||||
return rs;
|
||||
}
|
||||
// Test messages from FIPS 180-1
|
||||
|
||||
let fips_180_1_tests = ~[
|
||||
@@ -289,17 +216,6 @@ fn a_million_letter_a() -> ~str {
|
||||
],
|
||||
output_str: ~"84983e441c3bd26ebaae4aa1f95129e5e54670f1"
|
||||
},
|
||||
Test {
|
||||
input: a_million_letter_a(),
|
||||
output: ~[
|
||||
0x34u8, 0xAAu8, 0x97u8, 0x3Cu8,
|
||||
0xD4u8, 0xC4u8, 0xDAu8, 0xA4u8,
|
||||
0xF6u8, 0x1Eu8, 0xEBu8, 0x2Bu8,
|
||||
0xDBu8, 0xADu8, 0x27u8, 0x31u8,
|
||||
0x65u8, 0x34u8, 0x01u8, 0x6Fu8,
|
||||
],
|
||||
output_str: ~"34aa973cd4c4daa4f61eeb2bdbad27316534016f"
|
||||
},
|
||||
];
|
||||
// Examples from wikipedia
|
||||
|
||||
@@ -366,6 +282,15 @@ fn a_million_letter_a() -> ~str {
|
||||
sh.reset();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_1million_random_sha1() {
|
||||
let mut sh = Sha1::new();
|
||||
test_digest_1million_random(
|
||||
&mut sh,
|
||||
64,
|
||||
"34aa973cd4c4daa4f61eeb2bdbad27316534016f");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
+548
-733
@@ -8,47 +8,35 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::uint;
|
||||
|
||||
use cryptoutil::{write_u64_be, write_u32_be, read_u64v_be, read_u32v_be, shift_add_check_overflow,
|
||||
shift_add_check_overflow_tuple, FixedBuffer, FixedBuffer128, FixedBuffer64, StandardPadding};
|
||||
use digest::Digest;
|
||||
|
||||
// BitCounter is a specialized structure intended simply for counting the
|
||||
// number of bits that have been processed by the SHA-2 512 family of functions.
|
||||
// It does very little overflow checking since such checking is not necessary
|
||||
// for how it is used. A more generic structure would have to do this checking.
|
||||
// So, don't copy this structure and use it elsewhere!
|
||||
struct BitCounter {
|
||||
high_bit_count: u64,
|
||||
low_byte_count: u64
|
||||
}
|
||||
|
||||
impl BitCounter {
|
||||
fn add_bytes(&mut self, bytes: uint) {
|
||||
self.low_byte_count += bytes as u64;
|
||||
if(self.low_byte_count > 0x1fffffffffffffffu64) {
|
||||
self.high_bit_count += (self.low_byte_count >> 61);
|
||||
self.low_byte_count &= 0x1fffffffffffffffu64;
|
||||
// Sha-512 and Sha-256 use basically the same calculations which are implemented by these macros.
|
||||
// Inlining the calculations seems to result in better generated code.
|
||||
macro_rules! schedule_round( ($t:expr) => (
|
||||
W[$t] = sigma1(W[$t - 2]) + W[$t - 7] + sigma0(W[$t - 15]) + W[$t - 16];
|
||||
)
|
||||
)
|
||||
|
||||
macro_rules! sha2_round(
|
||||
($A:ident, $B:ident, $C:ident, $D:ident,
|
||||
$E:ident, $F:ident, $G:ident, $H:ident, $K:ident, $t:expr) => (
|
||||
{
|
||||
$H += sum1($E) + ch($E, $F, $G) + $K[$t] + W[$t];
|
||||
$D += $H;
|
||||
$H += sum0($A) + maj($A, $B, $C);
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.low_byte_count = 0;
|
||||
self.high_bit_count = 0;
|
||||
}
|
||||
|
||||
fn get_low_bit_count(&self) -> u64 {
|
||||
self.low_byte_count << 3
|
||||
}
|
||||
|
||||
fn get_high_bit_count(&self) -> u64 {
|
||||
self.high_bit_count
|
||||
}
|
||||
}
|
||||
|
||||
// A structure that represents that state of a digest computation
|
||||
// for the SHA-2 512 family of digest functions
|
||||
struct Engine512 {
|
||||
input_buffer: [u8, ..8],
|
||||
input_buffer_idx: uint,
|
||||
bit_counter: BitCounter,
|
||||
// A structure that represents that state of a digest computation for the SHA-2 512 family of digest
|
||||
// functions
|
||||
struct Engine512State {
|
||||
H0: u64,
|
||||
H1: u64,
|
||||
H2: u64,
|
||||
@@ -57,91 +45,34 @@ struct Engine512 {
|
||||
H5: u64,
|
||||
H6: u64,
|
||||
H7: u64,
|
||||
W: [u64, ..80],
|
||||
W_idx: uint,
|
||||
finished: bool,
|
||||
}
|
||||
|
||||
// Convert a [u8] to a u64 in big-endian format
|
||||
fn to_u64(input: &[u8]) -> u64 {
|
||||
(input[0] as u64) << 56 |
|
||||
(input[1] as u64) << 48 |
|
||||
(input[2] as u64) << 40 |
|
||||
(input[3] as u64) << 32 |
|
||||
(input[4] as u64) << 24 |
|
||||
(input[5] as u64) << 16 |
|
||||
(input[6] as u64) << 8 |
|
||||
(input[7] as u64)
|
||||
}
|
||||
|
||||
// Convert a u64 to a [u8] in big endian format
|
||||
fn from_u64(input: u64, out: &mut [u8]) {
|
||||
out[0] = (input >> 56) as u8;
|
||||
out[1] = (input >> 48) as u8;
|
||||
out[2] = (input >> 40) as u8;
|
||||
out[3] = (input >> 32) as u8;
|
||||
out[4] = (input >> 24) as u8;
|
||||
out[5] = (input >> 16) as u8;
|
||||
out[6] = (input >> 8) as u8;
|
||||
out[7] = input as u8;
|
||||
}
|
||||
|
||||
impl Engine512 {
|
||||
fn input_byte(&mut self, input: u8) {
|
||||
assert!(!self.finished)
|
||||
|
||||
self.input_buffer[self.input_buffer_idx] = input;
|
||||
self.input_buffer_idx += 1;
|
||||
|
||||
if (self.input_buffer_idx == 8) {
|
||||
self.input_buffer_idx = 0;
|
||||
let w = to_u64(self.input_buffer);
|
||||
self.process_word(w);
|
||||
}
|
||||
|
||||
self.bit_counter.add_bytes(1);
|
||||
impl Engine512State {
|
||||
fn new(h: &[u64, ..8]) -> Engine512State {
|
||||
return Engine512State {
|
||||
H0: h[0],
|
||||
H1: h[1],
|
||||
H2: h[2],
|
||||
H3: h[3],
|
||||
H4: h[4],
|
||||
H5: h[5],
|
||||
H6: h[6],
|
||||
H7: h[7]
|
||||
};
|
||||
}
|
||||
|
||||
fn input_vec(&mut self, input: &[u8]) {
|
||||
assert!(!self.finished)
|
||||
|
||||
let mut i = 0;
|
||||
|
||||
while i < input.len() && self.input_buffer_idx != 0 {
|
||||
self.input_byte(input[i]);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
while input.len() - i >= 8 {
|
||||
let w = to_u64(input.slice(i, i + 8));
|
||||
self.process_word(w);
|
||||
self.bit_counter.add_bytes(8);
|
||||
i += 8;
|
||||
}
|
||||
|
||||
while i < input.len() {
|
||||
self.input_byte(input[i]);
|
||||
i += 1;
|
||||
}
|
||||
fn reset(&mut self, h: &[u64, ..8]) {
|
||||
self.H0 = h[0];
|
||||
self.H1 = h[1];
|
||||
self.H2 = h[2];
|
||||
self.H3 = h[3];
|
||||
self.H4 = h[4];
|
||||
self.H5 = h[5];
|
||||
self.H6 = h[6];
|
||||
self.H7 = h[7];
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.bit_counter.reset();
|
||||
self.finished = false;
|
||||
self.input_buffer_idx = 0;
|
||||
self.W_idx = 0;
|
||||
}
|
||||
|
||||
fn process_word(&mut self, input: u64) {
|
||||
self.W[self.W_idx] = input;
|
||||
self.W_idx += 1;
|
||||
if (self.W_idx == 16) {
|
||||
self.W_idx = 0;
|
||||
self.process_block();
|
||||
}
|
||||
}
|
||||
|
||||
fn process_block(&mut self) {
|
||||
fn process_block(&mut self, data: &[u8]) {
|
||||
fn ch(x: u64, y: u64, z: u64) -> u64 {
|
||||
((x & y) ^ ((!x) & z))
|
||||
}
|
||||
@@ -166,11 +97,6 @@ fn sigma1(x: u64) -> u64 {
|
||||
((x << 45) | (x >> 19)) ^ ((x << 3) | (x >> 61)) ^ (x >> 6)
|
||||
}
|
||||
|
||||
foreach t in range(16u, 80) {
|
||||
self.W[t] = sigma1(self.W[t - 2]) + self.W[t - 7] + sigma0(self.W[t - 15]) +
|
||||
self.W[t - 16];
|
||||
}
|
||||
|
||||
let mut a = self.H0;
|
||||
let mut b = self.H1;
|
||||
let mut c = self.H2;
|
||||
@@ -180,47 +106,41 @@ fn sigma1(x: u64) -> u64 {
|
||||
let mut g = self.H6;
|
||||
let mut h = self.H7;
|
||||
|
||||
let mut t = 0;
|
||||
foreach _ in range(0u, 10) {
|
||||
h += sum1(e) + ch(e, f, g) + K64[t] + self.W[t];
|
||||
d += h;
|
||||
h += sum0(a) + maj(a, b, c);
|
||||
t += 1;
|
||||
let mut W = [0u64, ..80];
|
||||
|
||||
g += sum1(d) + ch(d, e, f) + K64[t] + self.W[t];
|
||||
c += g;
|
||||
g += sum0(h) + maj(h, a, b);
|
||||
t += 1;
|
||||
read_u64v_be(W.mut_slice(0, 16), data);
|
||||
|
||||
f += sum1(c) + ch(c, d, e) + K64[t] + self.W[t];
|
||||
b += f;
|
||||
f += sum0(g) + maj(g, h, a);
|
||||
t += 1;
|
||||
// Putting the message schedule inside the same loop as the round calculations allows for
|
||||
// the compiler to generate better code.
|
||||
for uint::range_step(0, 64, 8) |t| {
|
||||
schedule_round!(t + 16);
|
||||
schedule_round!(t + 17);
|
||||
schedule_round!(t + 18);
|
||||
schedule_round!(t + 19);
|
||||
schedule_round!(t + 20);
|
||||
schedule_round!(t + 21);
|
||||
schedule_round!(t + 22);
|
||||
schedule_round!(t + 23);
|
||||
|
||||
e += sum1(b) + ch(b, c, d) + K64[t] + self.W[t];
|
||||
a += e;
|
||||
e += sum0(f) + maj(f, g, h);
|
||||
t += 1;
|
||||
sha2_round!(a, b, c, d, e, f, g, h, K64, t);
|
||||
sha2_round!(h, a, b, c, d, e, f, g, K64, t + 1);
|
||||
sha2_round!(g, h, a, b, c, d, e, f, K64, t + 2);
|
||||
sha2_round!(f, g, h, a, b, c, d, e, K64, t + 3);
|
||||
sha2_round!(e, f, g, h, a, b, c, d, K64, t + 4);
|
||||
sha2_round!(d, e, f, g, h, a, b, c, K64, t + 5);
|
||||
sha2_round!(c, d, e, f, g, h, a, b, K64, t + 6);
|
||||
sha2_round!(b, c, d, e, f, g, h, a, K64, t + 7);
|
||||
}
|
||||
|
||||
d += sum1(a) + ch(a, b, c) + K64[t] + self.W[t];
|
||||
h += d;
|
||||
d += sum0(e) + maj(e, f, g);
|
||||
t += 1;
|
||||
|
||||
c += sum1(h) + ch(h, a, b) + K64[t] + self.W[t];
|
||||
g += c;
|
||||
c += sum0(d) + maj(d, e, f);
|
||||
t += 1;
|
||||
|
||||
b += sum1(g) + ch(g, h, a) + K64[t] + self.W[t];
|
||||
f += b;
|
||||
b += sum0(c) + maj(c, d, e);
|
||||
t += 1;
|
||||
|
||||
a += sum1(f) + ch(f, g, h) + K64[t] + self.W[t];
|
||||
e += a;
|
||||
a += sum0(b) + maj(b, c, d);
|
||||
t += 1;
|
||||
for uint::range_step(64, 80, 8) |t| {
|
||||
sha2_round!(a, b, c, d, e, f, g, h, K64, t);
|
||||
sha2_round!(h, a, b, c, d, e, f, g, K64, t + 1);
|
||||
sha2_round!(g, h, a, b, c, d, e, f, K64, t + 2);
|
||||
sha2_round!(f, g, h, a, b, c, d, e, K64, t + 3);
|
||||
sha2_round!(e, f, g, h, a, b, c, d, K64, t + 4);
|
||||
sha2_round!(d, e, f, g, h, a, b, c, K64, t + 5);
|
||||
sha2_round!(c, d, e, f, g, h, a, b, K64, t + 6);
|
||||
sha2_round!(b, c, d, e, f, g, h, a, K64, t + 7);
|
||||
}
|
||||
|
||||
self.H0 += a;
|
||||
@@ -232,113 +152,286 @@ fn sigma1(x: u64) -> u64 {
|
||||
self.H6 += g;
|
||||
self.H7 += h;
|
||||
}
|
||||
|
||||
fn finish(&mut self) {
|
||||
if (self.finished) {
|
||||
return;
|
||||
}
|
||||
|
||||
// must get message length before padding is added
|
||||
let high_bit_count = self.bit_counter.get_high_bit_count();
|
||||
let low_bit_count = self.bit_counter.get_low_bit_count();
|
||||
|
||||
// add padding
|
||||
self.input_byte(128u8);
|
||||
|
||||
while self.input_buffer_idx != 0 {
|
||||
self.input_byte(0u8);
|
||||
}
|
||||
|
||||
// add length
|
||||
if (self.W_idx > 14) {
|
||||
foreach _ in range(self.W_idx, 16) {
|
||||
self.process_word(0);
|
||||
}
|
||||
}
|
||||
|
||||
while self.W_idx < 14 {
|
||||
self.process_word(0);
|
||||
}
|
||||
|
||||
self.process_word(high_bit_count);
|
||||
self.process_word(low_bit_count);
|
||||
|
||||
self.finished = true;
|
||||
}
|
||||
|
||||
fn result_512(&mut self, out: &mut [u8]) {
|
||||
self.finish();
|
||||
|
||||
from_u64(self.H0, out.mut_slice(0, 8));
|
||||
from_u64(self.H1, out.mut_slice(8, 16));
|
||||
from_u64(self.H2, out.mut_slice(16, 24));
|
||||
from_u64(self.H3, out.mut_slice(24, 32));
|
||||
from_u64(self.H4, out.mut_slice(32, 40));
|
||||
from_u64(self.H5, out.mut_slice(40, 48));
|
||||
from_u64(self.H6, out.mut_slice(48, 56));
|
||||
from_u64(self.H7, out.mut_slice(56, 64));
|
||||
}
|
||||
|
||||
fn result_384(&mut self, out: &mut [u8]) {
|
||||
self.finish();
|
||||
|
||||
from_u64(self.H0, out.mut_slice(0, 8));
|
||||
from_u64(self.H1, out.mut_slice(8, 16));
|
||||
from_u64(self.H2, out.mut_slice(16, 24));
|
||||
from_u64(self.H3, out.mut_slice(24, 32));
|
||||
from_u64(self.H4, out.mut_slice(32, 40));
|
||||
from_u64(self.H5, out.mut_slice(40, 48));
|
||||
}
|
||||
|
||||
fn result_256(&mut self, out: &mut [u8]) {
|
||||
self.finish();
|
||||
|
||||
from_u64(self.H0, out.mut_slice(0, 8));
|
||||
from_u64(self.H1, out.mut_slice(8, 16));
|
||||
from_u64(self.H2, out.mut_slice(16, 24));
|
||||
from_u64(self.H3, out.mut_slice(24, 32));
|
||||
}
|
||||
|
||||
fn result_224(&mut self, out: &mut [u8]) {
|
||||
self.finish();
|
||||
|
||||
from_u64(self.H0, out.mut_slice(0, 8));
|
||||
from_u64(self.H1, out.mut_slice(8, 16));
|
||||
from_u64(self.H2, out.mut_slice(16, 24));
|
||||
from_u32((self.H3 >> 32) as u32, out.mut_slice(24, 28));
|
||||
}
|
||||
}
|
||||
|
||||
// Constants necessary for SHA-2 512 family of digests.
|
||||
static K64: [u64, ..80] = [
|
||||
0x428a2f98d728ae22u64, 0x7137449123ef65cdu64, 0xb5c0fbcfec4d3b2fu64, 0xe9b5dba58189dbbcu64,
|
||||
0x3956c25bf348b538u64, 0x59f111f1b605d019u64, 0x923f82a4af194f9bu64, 0xab1c5ed5da6d8118u64,
|
||||
0xd807aa98a3030242u64, 0x12835b0145706fbeu64, 0x243185be4ee4b28cu64, 0x550c7dc3d5ffb4e2u64,
|
||||
0x72be5d74f27b896fu64, 0x80deb1fe3b1696b1u64, 0x9bdc06a725c71235u64, 0xc19bf174cf692694u64,
|
||||
0xe49b69c19ef14ad2u64, 0xefbe4786384f25e3u64, 0x0fc19dc68b8cd5b5u64, 0x240ca1cc77ac9c65u64,
|
||||
0x2de92c6f592b0275u64, 0x4a7484aa6ea6e483u64, 0x5cb0a9dcbd41fbd4u64, 0x76f988da831153b5u64,
|
||||
0x983e5152ee66dfabu64, 0xa831c66d2db43210u64, 0xb00327c898fb213fu64, 0xbf597fc7beef0ee4u64,
|
||||
0xc6e00bf33da88fc2u64, 0xd5a79147930aa725u64, 0x06ca6351e003826fu64, 0x142929670a0e6e70u64,
|
||||
0x27b70a8546d22ffcu64, 0x2e1b21385c26c926u64, 0x4d2c6dfc5ac42aedu64, 0x53380d139d95b3dfu64,
|
||||
0x650a73548baf63deu64, 0x766a0abb3c77b2a8u64, 0x81c2c92e47edaee6u64, 0x92722c851482353bu64,
|
||||
0xa2bfe8a14cf10364u64, 0xa81a664bbc423001u64, 0xc24b8b70d0f89791u64, 0xc76c51a30654be30u64,
|
||||
0xd192e819d6ef5218u64, 0xd69906245565a910u64, 0xf40e35855771202au64, 0x106aa07032bbd1b8u64,
|
||||
0x19a4c116b8d2d0c8u64, 0x1e376c085141ab53u64, 0x2748774cdf8eeb99u64, 0x34b0bcb5e19b48a8u64,
|
||||
0x391c0cb3c5c95a63u64, 0x4ed8aa4ae3418acbu64, 0x5b9cca4f7763e373u64, 0x682e6ff3d6b2b8a3u64,
|
||||
0x748f82ee5defb2fcu64, 0x78a5636f43172f60u64, 0x84c87814a1f0ab72u64, 0x8cc702081a6439ecu64,
|
||||
0x90befffa23631e28u64, 0xa4506cebde82bde9u64, 0xbef9a3f7b2c67915u64, 0xc67178f2e372532bu64,
|
||||
0xca273eceea26619cu64, 0xd186b8c721c0c207u64, 0xeada7dd6cde0eb1eu64, 0xf57d4f7fee6ed178u64,
|
||||
0x06f067aa72176fbau64, 0x0a637dc5a2c898a6u64, 0x113f9804bef90daeu64, 0x1b710b35131c471bu64,
|
||||
0x28db77f523047d84u64, 0x32caab7b40c72493u64, 0x3c9ebe0a15c9bebcu64, 0x431d67c49c100d4cu64,
|
||||
0x4cc5d4becb3e42b6u64, 0x597f299cfc657e2au64, 0x5fcb6fab3ad6faecu64, 0x6c44198c4a475817u64
|
||||
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
|
||||
0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
|
||||
0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
|
||||
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
|
||||
0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
|
||||
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
|
||||
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
|
||||
0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
|
||||
0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
|
||||
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
|
||||
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
|
||||
0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
|
||||
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
|
||||
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
|
||||
0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
|
||||
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
|
||||
0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
|
||||
0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
|
||||
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
|
||||
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
|
||||
];
|
||||
|
||||
// A structure that represents that state of a digest computation
|
||||
// for the SHA-2 256 family of digest functions
|
||||
struct Engine256 {
|
||||
input_buffer: [u8, ..4],
|
||||
input_buffer_idx: uint,
|
||||
length_bytes: u64,
|
||||
|
||||
// A structure that keeps track of the state of the Sha-512 operation and contains the logic
|
||||
// necessary to perform the final calculations.
|
||||
struct Engine512 {
|
||||
length_bits: (u64, u64),
|
||||
buffer: FixedBuffer128,
|
||||
state: Engine512State,
|
||||
finished: bool,
|
||||
}
|
||||
|
||||
impl Engine512 {
|
||||
fn new(h: &[u64, ..8]) -> Engine512 {
|
||||
return Engine512 {
|
||||
length_bits: (0, 0),
|
||||
buffer: FixedBuffer128::new(),
|
||||
state: Engine512State::new(h),
|
||||
finished: false
|
||||
}
|
||||
}
|
||||
|
||||
fn reset(&mut self, h: &[u64, ..8]) {
|
||||
self.length_bits = (0, 0);
|
||||
self.buffer.reset();
|
||||
self.state.reset(h);
|
||||
self.finished = false;
|
||||
}
|
||||
|
||||
fn input(&mut self, input: &[u8]) {
|
||||
assert!(!self.finished)
|
||||
// Assumes that input.len() can be converted to u64 without overflow
|
||||
self.length_bits = shift_add_check_overflow_tuple(self.length_bits, input.len() as u64, 3);
|
||||
self.buffer.input(input, |input: &[u8]| { self.state.process_block(input) });
|
||||
}
|
||||
|
||||
fn finish(&mut self) {
|
||||
if self.finished {
|
||||
return;
|
||||
}
|
||||
|
||||
self.buffer.standard_padding(16, |input: &[u8]| { self.state.process_block(input) });
|
||||
match self.length_bits {
|
||||
(hi, low) => {
|
||||
write_u64_be(self.buffer.next(8), hi);
|
||||
write_u64_be(self.buffer.next(8), low);
|
||||
}
|
||||
}
|
||||
self.state.process_block(self.buffer.full_buffer());
|
||||
|
||||
self.finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct Sha512 {
|
||||
priv engine: Engine512
|
||||
}
|
||||
|
||||
impl Sha512 {
|
||||
/**
|
||||
* Construct an new instance of a SHA-512 digest.
|
||||
*/
|
||||
pub fn new() -> Sha512 {
|
||||
return Sha512 {
|
||||
engine: Engine512::new(&H512)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl Digest for Sha512 {
|
||||
fn input(&mut self, d: &[u8]) {
|
||||
self.engine.input(d);
|
||||
}
|
||||
|
||||
fn result(&mut self, out: &mut [u8]) {
|
||||
self.engine.finish();
|
||||
|
||||
write_u64_be(out.mut_slice(0, 8), self.engine.state.H0);
|
||||
write_u64_be(out.mut_slice(8, 16), self.engine.state.H1);
|
||||
write_u64_be(out.mut_slice(16, 24), self.engine.state.H2);
|
||||
write_u64_be(out.mut_slice(24, 32), self.engine.state.H3);
|
||||
write_u64_be(out.mut_slice(32, 40), self.engine.state.H4);
|
||||
write_u64_be(out.mut_slice(40, 48), self.engine.state.H5);
|
||||
write_u64_be(out.mut_slice(48, 56), self.engine.state.H6);
|
||||
write_u64_be(out.mut_slice(56, 64), self.engine.state.H7);
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.engine.reset(&H512);
|
||||
}
|
||||
|
||||
fn output_bits(&self) -> uint { 512 }
|
||||
}
|
||||
|
||||
static H512: [u64, ..8] = [
|
||||
0x6a09e667f3bcc908,
|
||||
0xbb67ae8584caa73b,
|
||||
0x3c6ef372fe94f82b,
|
||||
0xa54ff53a5f1d36f1,
|
||||
0x510e527fade682d1,
|
||||
0x9b05688c2b3e6c1f,
|
||||
0x1f83d9abfb41bd6b,
|
||||
0x5be0cd19137e2179
|
||||
];
|
||||
|
||||
|
||||
struct Sha384 {
|
||||
priv engine: Engine512
|
||||
}
|
||||
|
||||
impl Sha384 {
|
||||
/**
|
||||
* Construct an new instance of a SHA-384 digest.
|
||||
*/
|
||||
pub fn new() -> Sha384 {
|
||||
Sha384 {
|
||||
engine: Engine512::new(&H384)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Digest for Sha384 {
|
||||
fn input(&mut self, d: &[u8]) {
|
||||
self.engine.input(d);
|
||||
}
|
||||
|
||||
fn result(&mut self, out: &mut [u8]) {
|
||||
self.engine.finish();
|
||||
|
||||
write_u64_be(out.mut_slice(0, 8), self.engine.state.H0);
|
||||
write_u64_be(out.mut_slice(8, 16), self.engine.state.H1);
|
||||
write_u64_be(out.mut_slice(16, 24), self.engine.state.H2);
|
||||
write_u64_be(out.mut_slice(24, 32), self.engine.state.H3);
|
||||
write_u64_be(out.mut_slice(32, 40), self.engine.state.H4);
|
||||
write_u64_be(out.mut_slice(40, 48), self.engine.state.H5);
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.engine.reset(&H384);
|
||||
}
|
||||
|
||||
fn output_bits(&self) -> uint { 384 }
|
||||
}
|
||||
|
||||
static H384: [u64, ..8] = [
|
||||
0xcbbb9d5dc1059ed8,
|
||||
0x629a292a367cd507,
|
||||
0x9159015a3070dd17,
|
||||
0x152fecd8f70e5939,
|
||||
0x67332667ffc00b31,
|
||||
0x8eb44a8768581511,
|
||||
0xdb0c2e0d64f98fa7,
|
||||
0x47b5481dbefa4fa4
|
||||
];
|
||||
|
||||
|
||||
struct Sha512Trunc256 {
|
||||
priv engine: Engine512
|
||||
}
|
||||
|
||||
impl Sha512Trunc256 {
|
||||
/**
|
||||
* Construct an new instance of a SHA-512/256 digest.
|
||||
*/
|
||||
pub fn new() -> Sha512Trunc256 {
|
||||
Sha512Trunc256 {
|
||||
engine: Engine512::new(&H512_TRUNC_256)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Digest for Sha512Trunc256 {
|
||||
fn input(&mut self, d: &[u8]) {
|
||||
self.engine.input(d);
|
||||
}
|
||||
|
||||
fn result(&mut self, out: &mut [u8]) {
|
||||
self.engine.finish();
|
||||
|
||||
write_u64_be(out.mut_slice(0, 8), self.engine.state.H0);
|
||||
write_u64_be(out.mut_slice(8, 16), self.engine.state.H1);
|
||||
write_u64_be(out.mut_slice(16, 24), self.engine.state.H2);
|
||||
write_u64_be(out.mut_slice(24, 32), self.engine.state.H3);
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.engine.reset(&H512_TRUNC_256);
|
||||
}
|
||||
|
||||
fn output_bits(&self) -> uint { 256 }
|
||||
}
|
||||
|
||||
static H512_TRUNC_256: [u64, ..8] = [
|
||||
0x22312194fc2bf72c,
|
||||
0x9f555fa3c84c64c2,
|
||||
0x2393b86b6f53b151,
|
||||
0x963877195940eabd,
|
||||
0x96283ee2a88effe3,
|
||||
0xbe5e1e2553863992,
|
||||
0x2b0199fc2c85b8aa,
|
||||
0x0eb72ddc81c52ca2
|
||||
];
|
||||
|
||||
|
||||
struct Sha512Trunc224 {
|
||||
priv engine: Engine512
|
||||
}
|
||||
|
||||
impl Sha512Trunc224 {
|
||||
/**
|
||||
* Construct an new instance of a SHA-512/224 digest.
|
||||
*/
|
||||
pub fn new() -> Sha512Trunc224 {
|
||||
Sha512Trunc224 {
|
||||
engine: Engine512::new(&H512_TRUNC_224)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Digest for Sha512Trunc224 {
|
||||
fn input(&mut self, d: &[u8]) {
|
||||
self.engine.input(d);
|
||||
}
|
||||
|
||||
fn result(&mut self, out: &mut [u8]) {
|
||||
self.engine.finish();
|
||||
|
||||
write_u64_be(out.mut_slice(0, 8), self.engine.state.H0);
|
||||
write_u64_be(out.mut_slice(8, 16), self.engine.state.H1);
|
||||
write_u64_be(out.mut_slice(16, 24), self.engine.state.H2);
|
||||
write_u32_be(out.mut_slice(24, 28), (self.engine.state.H3 >> 32) as u32);
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.engine.reset(&H512_TRUNC_224);
|
||||
}
|
||||
|
||||
fn output_bits(&self) -> uint { 224 }
|
||||
}
|
||||
|
||||
static H512_TRUNC_224: [u64, ..8] = [
|
||||
0x8c3d37c819544da2,
|
||||
0x73e1996689dcd4d6,
|
||||
0x1dfab7ae32ff9c82,
|
||||
0x679dd514582f9fcf,
|
||||
0x0f6d2b697bd44da8,
|
||||
0x77e36f7304c48942,
|
||||
0x3f9d85a86a1d36c8,
|
||||
0x1112e6ad91d692a1,
|
||||
];
|
||||
|
||||
|
||||
// A structure that represents that state of a digest computation for the SHA-2 512 family of digest
|
||||
// functions
|
||||
struct Engine256State {
|
||||
H0: u32,
|
||||
H1: u32,
|
||||
H2: u32,
|
||||
@@ -347,84 +440,34 @@ struct Engine256 {
|
||||
H5: u32,
|
||||
H6: u32,
|
||||
H7: u32,
|
||||
W: [u32, ..64],
|
||||
W_idx: uint,
|
||||
finished: bool
|
||||
}
|
||||
|
||||
// Convert a [u8] to a u32 in big endian format
|
||||
fn to_u32(input: &[u8]) -> u32 {
|
||||
(input[0] as u32) << 24 |
|
||||
(input[1] as u32) << 16 |
|
||||
(input[2] as u32) << 8 |
|
||||
(input[3] as u32)
|
||||
}
|
||||
|
||||
// Convert a u32 to a [u8] in big endian format
|
||||
fn from_u32(input: u32, out: &mut [u8]) {
|
||||
out[0] = (input >> 24) as u8;
|
||||
out[1] = (input >> 16) as u8;
|
||||
out[2] = (input >> 8) as u8;
|
||||
out[3] = input as u8;
|
||||
}
|
||||
|
||||
impl Engine256 {
|
||||
fn input_byte(&mut self, input: u8) {
|
||||
assert!(!self.finished)
|
||||
|
||||
self.input_buffer[self.input_buffer_idx] = input;
|
||||
self.input_buffer_idx += 1;
|
||||
|
||||
if (self.input_buffer_idx == 4) {
|
||||
self.input_buffer_idx = 0;
|
||||
let w = to_u32(self.input_buffer);
|
||||
self.process_word(w);
|
||||
}
|
||||
|
||||
self.length_bytes += 1;
|
||||
impl Engine256State {
|
||||
fn new(h: &[u32, ..8]) -> Engine256State {
|
||||
return Engine256State {
|
||||
H0: h[0],
|
||||
H1: h[1],
|
||||
H2: h[2],
|
||||
H3: h[3],
|
||||
H4: h[4],
|
||||
H5: h[5],
|
||||
H6: h[6],
|
||||
H7: h[7]
|
||||
};
|
||||
}
|
||||
|
||||
fn input_vec(&mut self, input: &[u8]) {
|
||||
assert!(!self.finished)
|
||||
|
||||
let mut i = 0;
|
||||
|
||||
while i < input.len() && self.input_buffer_idx != 0 {
|
||||
self.input_byte(input[i]);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
while input.len() - i >= 4 {
|
||||
let w = to_u32(input.slice(i, i + 4));
|
||||
self.process_word(w);
|
||||
self.length_bytes += 4;
|
||||
i += 4;
|
||||
}
|
||||
|
||||
while i < input.len() {
|
||||
self.input_byte(input[i]);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
fn reset(&mut self, h: &[u32, ..8]) {
|
||||
self.H0 = h[0];
|
||||
self.H1 = h[1];
|
||||
self.H2 = h[2];
|
||||
self.H3 = h[3];
|
||||
self.H4 = h[4];
|
||||
self.H5 = h[5];
|
||||
self.H6 = h[6];
|
||||
self.H7 = h[7];
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.length_bytes = 0;
|
||||
self.finished = false;
|
||||
self.input_buffer_idx = 0;
|
||||
self.W_idx = 0;
|
||||
}
|
||||
|
||||
fn process_word(&mut self, input: u32) {
|
||||
self.W[self.W_idx] = input;
|
||||
self.W_idx += 1;
|
||||
if (self.W_idx == 16) {
|
||||
self.W_idx = 0;
|
||||
self.process_block();
|
||||
}
|
||||
}
|
||||
|
||||
fn process_block(&mut self) {
|
||||
fn process_block(&mut self, data: &[u8]) {
|
||||
fn ch(x: u32, y: u32, z: u32) -> u32 {
|
||||
((x & y) ^ ((!x) & z))
|
||||
}
|
||||
@@ -449,11 +492,6 @@ fn sigma1(x: u32) -> u32 {
|
||||
((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ (x >> 10)
|
||||
}
|
||||
|
||||
foreach t in range(16u, 64) {
|
||||
self.W[t] = sigma1(self.W[t - 2]) + self.W[t - 7] + sigma0(self.W[t - 15]) +
|
||||
self.W[t - 16];
|
||||
}
|
||||
|
||||
let mut a = self.H0;
|
||||
let mut b = self.H1;
|
||||
let mut c = self.H2;
|
||||
@@ -463,47 +501,41 @@ fn sigma1(x: u32) -> u32 {
|
||||
let mut g = self.H6;
|
||||
let mut h = self.H7;
|
||||
|
||||
let mut t = 0;
|
||||
foreach _ in range(0u, 8) {
|
||||
h += sum1(e) + ch(e, f, g) + K32[t] + self.W[t];
|
||||
d += h;
|
||||
h += sum0(a) + maj(a, b, c);
|
||||
t += 1;
|
||||
let mut W = [0u32, ..64];
|
||||
|
||||
g += sum1(d) + ch(d, e, f) + K32[t] + self.W[t];
|
||||
c += g;
|
||||
g += sum0(h) + maj(h, a, b);
|
||||
t += 1;
|
||||
read_u32v_be(W.mut_slice(0, 16), data);
|
||||
|
||||
f += sum1(c) + ch(c, d, e) + K32[t] + self.W[t];
|
||||
b += f;
|
||||
f += sum0(g) + maj(g, h, a);
|
||||
t += 1;
|
||||
// Putting the message schedule inside the same loop as the round calculations allows for
|
||||
// the compiler to generate better code.
|
||||
for uint::range_step(0, 48, 8) |t| {
|
||||
schedule_round!(t + 16);
|
||||
schedule_round!(t + 17);
|
||||
schedule_round!(t + 18);
|
||||
schedule_round!(t + 19);
|
||||
schedule_round!(t + 20);
|
||||
schedule_round!(t + 21);
|
||||
schedule_round!(t + 22);
|
||||
schedule_round!(t + 23);
|
||||
|
||||
e += sum1(b) + ch(b, c, d) + K32[t] + self.W[t];
|
||||
a += e;
|
||||
e += sum0(f) + maj(f, g, h);
|
||||
t += 1;
|
||||
sha2_round!(a, b, c, d, e, f, g, h, K32, t);
|
||||
sha2_round!(h, a, b, c, d, e, f, g, K32, t + 1);
|
||||
sha2_round!(g, h, a, b, c, d, e, f, K32, t + 2);
|
||||
sha2_round!(f, g, h, a, b, c, d, e, K32, t + 3);
|
||||
sha2_round!(e, f, g, h, a, b, c, d, K32, t + 4);
|
||||
sha2_round!(d, e, f, g, h, a, b, c, K32, t + 5);
|
||||
sha2_round!(c, d, e, f, g, h, a, b, K32, t + 6);
|
||||
sha2_round!(b, c, d, e, f, g, h, a, K32, t + 7);
|
||||
}
|
||||
|
||||
d += sum1(a) + ch(a, b, c) + K32[t] + self.W[t];
|
||||
h += d;
|
||||
d += sum0(e) + maj(e, f, g);
|
||||
t += 1;
|
||||
|
||||
c += sum1(h) + ch(h, a, b) + K32[t] + self.W[t];
|
||||
g += c;
|
||||
c += sum0(d) + maj(d, e, f);
|
||||
t += 1;
|
||||
|
||||
b += sum1(g) + ch(g, h, a) + K32[t] + self.W[t];
|
||||
f += b;
|
||||
b += sum0(c) + maj(c, d, e);
|
||||
t += 1;
|
||||
|
||||
a += sum1(f) + ch(f, g, h) + K32[t] + self.W[t];
|
||||
e += a;
|
||||
a += sum0(b) + maj(b, c, d);
|
||||
t += 1;
|
||||
for uint::range_step(48, 64, 8) |t| {
|
||||
sha2_round!(a, b, c, d, e, f, g, h, K32, t);
|
||||
sha2_round!(h, a, b, c, d, e, f, g, K32, t + 1);
|
||||
sha2_round!(g, h, a, b, c, d, e, f, K32, t + 2);
|
||||
sha2_round!(f, g, h, a, b, c, d, e, K32, t + 3);
|
||||
sha2_round!(e, f, g, h, a, b, c, d, K32, t + 4);
|
||||
sha2_round!(d, e, f, g, h, a, b, c, K32, t + 5);
|
||||
sha2_round!(c, d, e, f, g, h, a, b, K32, t + 6);
|
||||
sha2_round!(b, c, d, e, f, g, h, a, K32, t + 7);
|
||||
}
|
||||
|
||||
self.H0 += a;
|
||||
@@ -515,418 +547,182 @@ fn sigma1(x: u32) -> u32 {
|
||||
self.H6 += g;
|
||||
self.H7 += h;
|
||||
}
|
||||
|
||||
fn finish(&mut self) {
|
||||
if (self.finished) {
|
||||
return;
|
||||
}
|
||||
|
||||
// must get length before adding padding
|
||||
let bit_length = self.length_bytes << 3;
|
||||
|
||||
// add padding
|
||||
self.input_byte(128u8);
|
||||
|
||||
while self.input_buffer_idx != 0 {
|
||||
self.input_byte(0u8);
|
||||
}
|
||||
|
||||
// add length
|
||||
if (self.W_idx > 14) {
|
||||
foreach _ in range(self.W_idx, 16) {
|
||||
self.process_word(0);
|
||||
}
|
||||
}
|
||||
|
||||
while self.W_idx < 14 {
|
||||
self.process_word(0);
|
||||
}
|
||||
|
||||
self.process_word((bit_length >> 32) as u32);
|
||||
self.process_word(bit_length as u32);
|
||||
|
||||
self.finished = true;
|
||||
}
|
||||
|
||||
fn result_256(&mut self, out: &mut [u8]) {
|
||||
self.finish();
|
||||
|
||||
from_u32(self.H0, out.mut_slice(0, 4));
|
||||
from_u32(self.H1, out.mut_slice(4, 8));
|
||||
from_u32(self.H2, out.mut_slice(8, 12));
|
||||
from_u32(self.H3, out.mut_slice(12, 16));
|
||||
from_u32(self.H4, out.mut_slice(16, 20));
|
||||
from_u32(self.H5, out.mut_slice(20, 24));
|
||||
from_u32(self.H6, out.mut_slice(24, 28));
|
||||
from_u32(self.H7, out.mut_slice(28, 32));
|
||||
}
|
||||
|
||||
fn result_224(&mut self, out: &mut [u8]) {
|
||||
self.finish();
|
||||
|
||||
from_u32(self.H0, out.mut_slice(0, 4));
|
||||
from_u32(self.H1, out.mut_slice(4, 8));
|
||||
from_u32(self.H2, out.mut_slice(8, 12));
|
||||
from_u32(self.H3, out.mut_slice(12, 16));
|
||||
from_u32(self.H4, out.mut_slice(16, 20));
|
||||
from_u32(self.H5, out.mut_slice(20, 24));
|
||||
from_u32(self.H6, out.mut_slice(24, 28));
|
||||
}
|
||||
}
|
||||
|
||||
static K32: [u32, ..64] = [
|
||||
0x428a2f98u32, 0x71374491u32, 0xb5c0fbcfu32, 0xe9b5dba5u32,
|
||||
0x3956c25bu32, 0x59f111f1u32, 0x923f82a4u32, 0xab1c5ed5u32,
|
||||
0xd807aa98u32, 0x12835b01u32, 0x243185beu32, 0x550c7dc3u32,
|
||||
0x72be5d74u32, 0x80deb1feu32, 0x9bdc06a7u32, 0xc19bf174u32,
|
||||
0xe49b69c1u32, 0xefbe4786u32, 0x0fc19dc6u32, 0x240ca1ccu32,
|
||||
0x2de92c6fu32, 0x4a7484aau32, 0x5cb0a9dcu32, 0x76f988dau32,
|
||||
0x983e5152u32, 0xa831c66du32, 0xb00327c8u32, 0xbf597fc7u32,
|
||||
0xc6e00bf3u32, 0xd5a79147u32, 0x06ca6351u32, 0x14292967u32,
|
||||
0x27b70a85u32, 0x2e1b2138u32, 0x4d2c6dfcu32, 0x53380d13u32,
|
||||
0x650a7354u32, 0x766a0abbu32, 0x81c2c92eu32, 0x92722c85u32,
|
||||
0xa2bfe8a1u32, 0xa81a664bu32, 0xc24b8b70u32, 0xc76c51a3u32,
|
||||
0xd192e819u32, 0xd6990624u32, 0xf40e3585u32, 0x106aa070u32,
|
||||
0x19a4c116u32, 0x1e376c08u32, 0x2748774cu32, 0x34b0bcb5u32,
|
||||
0x391c0cb3u32, 0x4ed8aa4au32, 0x5b9cca4fu32, 0x682e6ff3u32,
|
||||
0x748f82eeu32, 0x78a5636fu32, 0x84c87814u32, 0x8cc70208u32,
|
||||
0x90befffau32, 0xa4506cebu32, 0xbef9a3f7u32, 0xc67178f2u32
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
||||
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
||||
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
];
|
||||
|
||||
struct Sha512 {
|
||||
priv engine: Engine512
|
||||
|
||||
// A structure that keeps track of the state of the Sha-256 operation and contains the logic
|
||||
// necessary to perform the final calculations.
|
||||
struct Engine256 {
|
||||
length_bits: u64,
|
||||
buffer: FixedBuffer64,
|
||||
state: Engine256State,
|
||||
finished: bool,
|
||||
}
|
||||
|
||||
struct Sha384 {
|
||||
priv engine: Engine512
|
||||
impl Engine256 {
|
||||
fn new(h: &[u32, ..8]) -> Engine256 {
|
||||
return Engine256 {
|
||||
length_bits: 0,
|
||||
buffer: FixedBuffer64::new(),
|
||||
state: Engine256State::new(h),
|
||||
finished: false
|
||||
}
|
||||
}
|
||||
|
||||
fn reset(&mut self, h: &[u32, ..8]) {
|
||||
self.length_bits = 0;
|
||||
self.buffer.reset();
|
||||
self.state.reset(h);
|
||||
self.finished = false;
|
||||
}
|
||||
|
||||
fn input(&mut self, input: &[u8]) {
|
||||
assert!(!self.finished)
|
||||
// Assumes that input.len() can be converted to u64 without overflow
|
||||
self.length_bits = shift_add_check_overflow(self.length_bits, input.len() as u64, 3);
|
||||
self.buffer.input(input, |input: &[u8]| { self.state.process_block(input) });
|
||||
}
|
||||
|
||||
fn finish(&mut self) {
|
||||
if self.finished {
|
||||
return;
|
||||
}
|
||||
|
||||
self.buffer.standard_padding(8, |input: &[u8]| { self.state.process_block(input) });
|
||||
write_u32_be(self.buffer.next(4), (self.length_bits >> 32) as u32 );
|
||||
write_u32_be(self.buffer.next(4), self.length_bits as u32);
|
||||
self.state.process_block(self.buffer.full_buffer());
|
||||
|
||||
self.finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
struct Sha512Trunc256 {
|
||||
priv engine: Engine512
|
||||
}
|
||||
|
||||
struct Sha512Trunc224 {
|
||||
priv engine: Engine512
|
||||
}
|
||||
|
||||
struct Sha256 {
|
||||
priv engine: Engine256
|
||||
}
|
||||
|
||||
struct Sha224 {
|
||||
priv engine: Engine256
|
||||
}
|
||||
|
||||
impl Sha512 {
|
||||
/**
|
||||
* Construct an new instance of a SHA-512 digest.
|
||||
*/
|
||||
pub fn new() -> Sha512 {
|
||||
Sha512 {
|
||||
engine: Engine512 {
|
||||
input_buffer: [0u8, ..8],
|
||||
input_buffer_idx: 0,
|
||||
bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 },
|
||||
H0: 0x6a09e667f3bcc908u64,
|
||||
H1: 0xbb67ae8584caa73bu64,
|
||||
H2: 0x3c6ef372fe94f82bu64,
|
||||
H3: 0xa54ff53a5f1d36f1u64,
|
||||
H4: 0x510e527fade682d1u64,
|
||||
H5: 0x9b05688c2b3e6c1fu64,
|
||||
H6: 0x1f83d9abfb41bd6bu64,
|
||||
H7: 0x5be0cd19137e2179u64,
|
||||
W: [0u64, ..80],
|
||||
W_idx: 0,
|
||||
finished: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sha384 {
|
||||
/**
|
||||
* Construct an new instance of a SHA-384 digest.
|
||||
*/
|
||||
pub fn new() -> Sha384 {
|
||||
Sha384 {
|
||||
engine: Engine512 {
|
||||
input_buffer: [0u8, ..8],
|
||||
input_buffer_idx: 0,
|
||||
bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 },
|
||||
H0: 0xcbbb9d5dc1059ed8u64,
|
||||
H1: 0x629a292a367cd507u64,
|
||||
H2: 0x9159015a3070dd17u64,
|
||||
H3: 0x152fecd8f70e5939u64,
|
||||
H4: 0x67332667ffc00b31u64,
|
||||
H5: 0x8eb44a8768581511u64,
|
||||
H6: 0xdb0c2e0d64f98fa7u64,
|
||||
H7: 0x47b5481dbefa4fa4u64,
|
||||
W: [0u64, ..80],
|
||||
W_idx: 0,
|
||||
finished: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sha512Trunc256 {
|
||||
/**
|
||||
* Construct an new instance of a SHA-512/256 digest.
|
||||
*/
|
||||
pub fn new() -> Sha512Trunc256 {
|
||||
Sha512Trunc256 {
|
||||
engine: Engine512 {
|
||||
input_buffer: [0u8, ..8],
|
||||
input_buffer_idx: 0,
|
||||
bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 },
|
||||
H0: 0x22312194fc2bf72cu64,
|
||||
H1: 0x9f555fa3c84c64c2u64,
|
||||
H2: 0x2393b86b6f53b151u64,
|
||||
H3: 0x963877195940eabdu64,
|
||||
H4: 0x96283ee2a88effe3u64,
|
||||
H5: 0xbe5e1e2553863992u64,
|
||||
H6: 0x2b0199fc2c85b8aau64,
|
||||
H7: 0x0eb72ddc81c52ca2u64,
|
||||
W: [0u64, ..80],
|
||||
W_idx: 0,
|
||||
finished: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sha512Trunc224 {
|
||||
/**
|
||||
* Construct an new instance of a SHA-512/224 digest.
|
||||
*/
|
||||
pub fn new() -> Sha512Trunc224 {
|
||||
Sha512Trunc224 {
|
||||
engine: Engine512 {
|
||||
input_buffer: [0u8, ..8],
|
||||
input_buffer_idx: 0,
|
||||
bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 },
|
||||
H0: 0x8c3d37c819544da2u64,
|
||||
H1: 0x73e1996689dcd4d6u64,
|
||||
H2: 0x1dfab7ae32ff9c82u64,
|
||||
H3: 0x679dd514582f9fcfu64,
|
||||
H4: 0x0f6d2b697bd44da8u64,
|
||||
H5: 0x77e36f7304c48942u64,
|
||||
H6: 0x3f9d85a86a1d36c8u64,
|
||||
H7: 0x1112e6ad91d692a1u64,
|
||||
W: [0u64, ..80],
|
||||
W_idx: 0,
|
||||
finished: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sha256 {
|
||||
/**
|
||||
* Construct an new instance of a SHA-256 digest.
|
||||
*/
|
||||
pub fn new() -> Sha256 {
|
||||
Sha256 {
|
||||
engine: Engine256 {
|
||||
input_buffer: [0u8, ..4],
|
||||
input_buffer_idx: 0,
|
||||
length_bytes: 0,
|
||||
H0: 0x6a09e667u32,
|
||||
H1: 0xbb67ae85u32,
|
||||
H2: 0x3c6ef372u32,
|
||||
H3: 0xa54ff53au32,
|
||||
H4: 0x510e527fu32,
|
||||
H5: 0x9b05688cu32,
|
||||
H6: 0x1f83d9abu32,
|
||||
H7: 0x5be0cd19u32,
|
||||
W: [0u32, ..64],
|
||||
W_idx: 0,
|
||||
finished: false,
|
||||
}
|
||||
engine: Engine256::new(&H256)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Digest for Sha256 {
|
||||
fn input(&mut self, d: &[u8]) {
|
||||
self.engine.input(d);
|
||||
}
|
||||
|
||||
fn result(&mut self, out: &mut [u8]) {
|
||||
self.engine.finish();
|
||||
|
||||
write_u32_be(out.mut_slice(0, 4), self.engine.state.H0);
|
||||
write_u32_be(out.mut_slice(4, 8), self.engine.state.H1);
|
||||
write_u32_be(out.mut_slice(8, 12), self.engine.state.H2);
|
||||
write_u32_be(out.mut_slice(12, 16), self.engine.state.H3);
|
||||
write_u32_be(out.mut_slice(16, 20), self.engine.state.H4);
|
||||
write_u32_be(out.mut_slice(20, 24), self.engine.state.H5);
|
||||
write_u32_be(out.mut_slice(24, 28), self.engine.state.H6);
|
||||
write_u32_be(out.mut_slice(28, 32), self.engine.state.H7);
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.engine.reset(&H256);
|
||||
}
|
||||
|
||||
fn output_bits(&self) -> uint { 256 }
|
||||
}
|
||||
|
||||
static H256: [u32, ..8] = [
|
||||
0x6a09e667,
|
||||
0xbb67ae85,
|
||||
0x3c6ef372,
|
||||
0xa54ff53a,
|
||||
0x510e527f,
|
||||
0x9b05688c,
|
||||
0x1f83d9ab,
|
||||
0x5be0cd19
|
||||
];
|
||||
|
||||
|
||||
struct Sha224 {
|
||||
priv engine: Engine256
|
||||
}
|
||||
|
||||
impl Sha224 {
|
||||
/**
|
||||
* Construct an new instance of a SHA-224 digest.
|
||||
*/
|
||||
pub fn new() -> Sha224 {
|
||||
Sha224 {
|
||||
engine: Engine256 {
|
||||
input_buffer: [0u8, ..4],
|
||||
input_buffer_idx: 0,
|
||||
length_bytes: 0,
|
||||
H0: 0xc1059ed8u32,
|
||||
H1: 0x367cd507u32,
|
||||
H2: 0x3070dd17u32,
|
||||
H3: 0xf70e5939u32,
|
||||
H4: 0xffc00b31u32,
|
||||
H5: 0x68581511u32,
|
||||
H6: 0x64f98fa7u32,
|
||||
H7: 0xbefa4fa4u32,
|
||||
W: [0u32, ..64],
|
||||
W_idx: 0,
|
||||
finished: false,
|
||||
}
|
||||
engine: Engine256::new(&H224)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Digest for Sha512 {
|
||||
fn input(&mut self, d: &[u8]) {
|
||||
self.engine.input_vec(d);
|
||||
}
|
||||
|
||||
fn result(&mut self, out: &mut [u8]) {
|
||||
self.engine.result_512(out)
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.engine.reset();
|
||||
|
||||
self.engine.H0 = 0x6a09e667f3bcc908u64;
|
||||
self.engine.H1 = 0xbb67ae8584caa73bu64;
|
||||
self.engine.H2 = 0x3c6ef372fe94f82bu64;
|
||||
self.engine.H3 = 0xa54ff53a5f1d36f1u64;
|
||||
self.engine.H4 = 0x510e527fade682d1u64;
|
||||
self.engine.H5 = 0x9b05688c2b3e6c1fu64;
|
||||
self.engine.H6 = 0x1f83d9abfb41bd6bu64;
|
||||
self.engine.H7 = 0x5be0cd19137e2179u64;
|
||||
}
|
||||
|
||||
fn output_bits(&self) -> uint { 512 }
|
||||
}
|
||||
|
||||
impl Digest for Sha384 {
|
||||
fn input(&mut self, d: &[u8]) {
|
||||
self.engine.input_vec(d);
|
||||
}
|
||||
|
||||
fn result(&mut self, out: &mut [u8]) {
|
||||
self.engine.result_384(out)
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.engine.reset();
|
||||
|
||||
self.engine.H0 = 0xcbbb9d5dc1059ed8u64;
|
||||
self.engine.H1 = 0x629a292a367cd507u64;
|
||||
self.engine.H2 = 0x9159015a3070dd17u64;
|
||||
self.engine.H3 = 0x152fecd8f70e5939u64;
|
||||
self.engine.H4 = 0x67332667ffc00b31u64;
|
||||
self.engine.H5 = 0x8eb44a8768581511u64;
|
||||
self.engine.H6 = 0xdb0c2e0d64f98fa7u64;
|
||||
self.engine.H7 = 0x47b5481dbefa4fa4u64;
|
||||
}
|
||||
|
||||
fn output_bits(&self) -> uint { 384 }
|
||||
}
|
||||
|
||||
impl Digest for Sha512Trunc256 {
|
||||
fn input(&mut self, d: &[u8]) {
|
||||
self.engine.input_vec(d);
|
||||
}
|
||||
|
||||
fn result(&mut self, out: &mut [u8]) {
|
||||
self.engine.result_256(out)
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.engine.reset();
|
||||
|
||||
self.engine.H0 = 0x22312194fc2bf72cu64;
|
||||
self.engine.H1 = 0x9f555fa3c84c64c2u64;
|
||||
self.engine.H2 = 0x2393b86b6f53b151u64;
|
||||
self.engine.H3 = 0x963877195940eabdu64;
|
||||
self.engine.H4 = 0x96283ee2a88effe3u64;
|
||||
self.engine.H5 = 0xbe5e1e2553863992u64;
|
||||
self.engine.H6 = 0x2b0199fc2c85b8aau64;
|
||||
self.engine.H7 = 0x0eb72ddc81c52ca2u64;
|
||||
}
|
||||
|
||||
fn output_bits(&self) -> uint { 256 }
|
||||
}
|
||||
|
||||
impl Digest for Sha512Trunc224 {
|
||||
fn input(&mut self, d: &[u8]) {
|
||||
self.engine.input_vec(d);
|
||||
}
|
||||
|
||||
fn result(&mut self, out: &mut [u8]) {
|
||||
self.engine.result_224(out)
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.engine.reset();
|
||||
|
||||
self.engine.H0 = 0x8c3d37c819544da2u64;
|
||||
self.engine.H1 = 0x73e1996689dcd4d6u64;
|
||||
self.engine.H2 = 0x1dfab7ae32ff9c82u64;
|
||||
self.engine.H3 = 0x679dd514582f9fcfu64;
|
||||
self.engine.H4 = 0x0f6d2b697bd44da8u64;
|
||||
self.engine.H5 = 0x77e36f7304c48942u64;
|
||||
self.engine.H6 = 0x3f9d85a86a1d36c8u64;
|
||||
self.engine.H7 = 0x1112e6ad91d692a1u64;
|
||||
}
|
||||
|
||||
fn output_bits(&self) -> uint { 224 }
|
||||
}
|
||||
|
||||
impl Digest for Sha256 {
|
||||
fn input(&mut self, d: &[u8]) {
|
||||
self.engine.input_vec(d);
|
||||
}
|
||||
|
||||
fn result(&mut self, out: &mut [u8]) {
|
||||
self.engine.result_256(out)
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.engine.reset();
|
||||
|
||||
self.engine.H0 = 0x6a09e667u32;
|
||||
self.engine.H1 = 0xbb67ae85u32;
|
||||
self.engine.H2 = 0x3c6ef372u32;
|
||||
self.engine.H3 = 0xa54ff53au32;
|
||||
self.engine.H4 = 0x510e527fu32;
|
||||
self.engine.H5 = 0x9b05688cu32;
|
||||
self.engine.H6 = 0x1f83d9abu32;
|
||||
self.engine.H7 = 0x5be0cd19u32;
|
||||
}
|
||||
|
||||
fn output_bits(&self) -> uint { 256 }
|
||||
}
|
||||
|
||||
impl Digest for Sha224 {
|
||||
fn input(&mut self, d: &[u8]) {
|
||||
self.engine.input_vec(d);
|
||||
self.engine.input(d);
|
||||
}
|
||||
|
||||
fn result(&mut self, out: &mut [u8]) {
|
||||
self.engine.result_224(out)
|
||||
self.engine.finish();
|
||||
write_u32_be(out.mut_slice(0, 4), self.engine.state.H0);
|
||||
write_u32_be(out.mut_slice(4, 8), self.engine.state.H1);
|
||||
write_u32_be(out.mut_slice(8, 12), self.engine.state.H2);
|
||||
write_u32_be(out.mut_slice(12, 16), self.engine.state.H3);
|
||||
write_u32_be(out.mut_slice(16, 20), self.engine.state.H4);
|
||||
write_u32_be(out.mut_slice(20, 24), self.engine.state.H5);
|
||||
write_u32_be(out.mut_slice(24, 28), self.engine.state.H6);
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.engine.reset();
|
||||
|
||||
self.engine.H0 = 0xc1059ed8u32;
|
||||
self.engine.H1 = 0x367cd507u32;
|
||||
self.engine.H2 = 0x3070dd17u32;
|
||||
self.engine.H3 = 0xf70e5939u32;
|
||||
self.engine.H4 = 0xffc00b31u32;
|
||||
self.engine.H5 = 0x68581511u32;
|
||||
self.engine.H6 = 0x64f98fa7u32;
|
||||
self.engine.H7 = 0xbefa4fa4u32;
|
||||
self.engine.reset(&H224);
|
||||
}
|
||||
|
||||
fn output_bits(&self) -> uint { 224 }
|
||||
}
|
||||
|
||||
static H224: [u32, ..8] = [
|
||||
0xc1059ed8,
|
||||
0x367cd507,
|
||||
0x3070dd17,
|
||||
0xf70e5939,
|
||||
0xffc00b31,
|
||||
0x68581511,
|
||||
0x64f98fa7,
|
||||
0xbefa4fa4
|
||||
];
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use digest::{Digest, DigestUtil};
|
||||
use cryptoutil::test::test_digest_1million_random;
|
||||
use digest::Digest;
|
||||
use sha2::{Sha512, Sha384, Sha512Trunc256, Sha512Trunc224, Sha256, Sha224};
|
||||
|
||||
struct Test {
|
||||
@@ -1117,6 +913,25 @@ fn test_sha224() {
|
||||
|
||||
test_hash(sh, tests);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_1million_random_sha512() {
|
||||
let mut sh = Sha512::new();
|
||||
test_digest_1million_random(
|
||||
&mut sh,
|
||||
128,
|
||||
"e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb" +
|
||||
"de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_1million_random_sha256() {
|
||||
let mut sh = Sha256::new();
|
||||
test_digest_1million_random(
|
||||
&mut sh,
|
||||
64,
|
||||
"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -67,6 +67,8 @@
|
||||
pub mod treemap;
|
||||
|
||||
// Crypto
|
||||
#[path="crypto/cryptoutil.rs"]
|
||||
mod cryptoutil;
|
||||
#[path="crypto/digest.rs"]
|
||||
pub mod digest;
|
||||
#[path="crypto/sha1.rs"]
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
|
||||
#[allow(missing_doc)];
|
||||
|
||||
|
||||
use digest::DigestUtil;
|
||||
use digest::Digest;
|
||||
use json;
|
||||
use sha1::Sha1;
|
||||
use serialize::{Encoder, Encodable, Decoder, Decodable};
|
||||
|
||||
Reference in New Issue
Block a user