diff options
| author | Palmer Cox <p@lmercox.com> | 2013-10-26 16:49:51 -0400 |
|---|---|---|
| committer | Palmer Cox <p@lmercox.com> | 2013-10-27 21:25:19 -0400 |
| commit | 2d5cb5d99a68d9b603675b1c4284dbe37333332c (patch) | |
| tree | c5bcb630d21739824839e9d0cfd71405c5aa8979 | |
| parent | ff9e573a6752cde4760fafdb94f7337c9e133905 (diff) | |
| download | rust-2d5cb5d99a68d9b603675b1c4284dbe37333332c.tar.gz rust-2d5cb5d99a68d9b603675b1c4284dbe37333332c.zip | |
Integrate the code in the digest and cryptoutil modules directly into the sha1 module.
| -rw-r--r-- | src/librustpkg/cryptoutil.rs | 271 | ||||
| -rw-r--r-- | src/librustpkg/digest.rs | 81 | ||||
| -rw-r--r-- | src/librustpkg/rustpkg.rs | 2 | ||||
| -rw-r--r-- | src/librustpkg/sha1.rs | 323 | ||||
| -rw-r--r-- | src/librustpkg/workcache_support.rs | 3 |
5 files changed, 315 insertions, 365 deletions
diff --git a/src/librustpkg/cryptoutil.rs b/src/librustpkg/cryptoutil.rs deleted file mode 100644 index 55199b1f2cc..00000000000 --- a/src/librustpkg/cryptoutil.rs +++ /dev/null @@ -1,271 +0,0 @@ -// 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::{Zero, CheckedAdd}; -use std::vec::bytes::{MutableByteVector, copy_memory}; - - -/// 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 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); - } - } -} - - -trait ToBits { - /// Convert the value in bytes to the number of bits, a tuple where the 1st item is the - /// high-order value and the 2nd item is the low order value. - fn to_bits(self) -> (Self, Self); -} - -impl ToBits for u64 { - fn to_bits(self) -> (u64, u64) { - return (self >> 61, self << 3); - } -} - -/// Adds the specified number of bytes to the bit count. fail!() if this would cause numeric -/// overflow. -pub fn add_bytes_to_bits<T: Int + CheckedAdd + ToBits>(bits: T, bytes: T) -> T { - let (new_high_bits, new_low_bits) = bytes.to_bits(); - - if new_high_bits > Zero::zero() { - fail!("Numeric overflow occured.") - } - - match bits.checked_add(&new_low_bits) { - Some(x) => return x, - None => fail!("Numeric overflow occured.") - } -} - - -/// 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, process 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; -} - - -/// 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 FixedBuffer for FixedBuffer64 { - fn input(&mut self, input: &[u8], func: &fn(&[u8])) { - let mut i = 0; - - // FIXME: #6304 - This local variable shouldn't be necessary. - let size = 64; - - // 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 == 64); - self.buffer_idx = 0; - return self.buffer.slice_to(64); - } - - fn position(&self) -> uint { self.buffer_idx } - - fn remaining(&self) -> uint { 64 - self.buffer_idx } - - fn size(&self) -> uint { 64 } -} - - -/// 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)] -pub mod test { - use std::rand::{IsaacRng, Rng}; - use std::vec; - use extra::hex::FromHex; - - use cryptoutil::add_bytes_to_bits; - 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_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(); - let result_bytes = digest.result_bytes(); - - assert_eq!(expected, result_str.as_slice()); - assert_eq!(expected.from_hex().unwrap(), result_bytes); - } - - // A normal addition - no overflow occurs - #[test] - fn test_add_bytes_to_bits_ok() { - assert!(add_bytes_to_bits::<u64>(100, 10) == 180); - } - - // A simple failure case - adding 1 to the max value - #[test] - #[should_fail] - fn test_add_bytes_to_bits_overflow() { - add_bytes_to_bits::<u64>(Bounded::max_value(), 1); - } -} diff --git a/src/librustpkg/digest.rs b/src/librustpkg/digest.rs deleted file mode 100644 index f0dccf7c2e2..00000000000 --- a/src/librustpkg/digest.rs +++ /dev/null @@ -1,81 +0,0 @@ -// 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. - -//! Common functionality related to cryptographic digest functions - -use std::vec; - -use extra::hex::ToHex; - - -/** - * The Digest trait specifies an interface common to digest functions, such as SHA-1 and the SHA-2 - * family of digest functions. - */ -pub trait Digest { - /** - * Provide message data. - * - * # Arguments - * - * * input - A vector of message data - */ - fn input(&mut self, input: &[u8]); - - /** - * 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]); - - /** - * Reset the digest. This method must be called after result() and before supplying more - * data. - */ - fn reset(&mut self); - - /** - * Get the output size in bits. - */ - fn output_bits(&self) -> uint; - - /** - * Convenience function that feeds a string into a digest. - * - * # Arguments - * - * * `input` The string to feed into the digest - */ - fn input_str(&mut self, input: &str) { - self.input(input.as_bytes()); - } - - /** - * Convenience function that retrieves the result of a digest as a - * newly allocated vec of bytes. - */ - fn result_bytes(&mut self) -> ~[u8] { - let mut buf = vec::from_elem((self.output_bits()+7)/8, 0u8); - self.result(buf); - buf - } - - /** - * Convenience function that retrieves the result of a digest as a - * ~str in hexadecimal format. - */ - fn result_str(&mut self) -> ~str { - self.result_bytes().to_hex() - } -} - diff --git a/src/librustpkg/rustpkg.rs b/src/librustpkg/rustpkg.rs index 229eecffbea..95a2c5b1702 100644 --- a/src/librustpkg/rustpkg.rs +++ b/src/librustpkg/rustpkg.rs @@ -55,8 +55,6 @@ pub mod api; mod conditions; pub mod context; mod crate; -mod cryptoutil; -mod digest; pub mod exit_codes; mod installed_packages; mod messages; diff --git a/src/librustpkg/sha1.rs b/src/librustpkg/sha1.rs index 04efbfffe15..d955fd1aa97 100644 --- a/src/librustpkg/sha1.rs +++ b/src/librustpkg/sha1.rs @@ -26,10 +26,278 @@ * discouraged. */ +use std::num::Zero; +use std::vec; +use std::vec::bytes::{MutableByteVector, copy_memory}; +use extra::hex::ToHex; + +/// Write a u32 into a vector, which must be 4 bytes long. The value is written in big-endian +/// format. +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 u32s. The values are read in big-endian format. +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); + } + } +} + +trait ToBits { + /// Convert the value in bytes to the number of bits, a tuple where the 1st item is the + /// high-order value and the 2nd item is the low order value. + fn to_bits(self) -> (Self, Self); +} + +impl ToBits for u64 { + fn to_bits(self) -> (u64, u64) { + return (self >> 61, self << 3); + } +} + +/// Adds the specified number of bytes to the bit count. fail!() if this would cause numeric +/// overflow. +fn add_bytes_to_bits<T: Int + CheckedAdd + ToBits>(bits: T, bytes: T) -> T { + let (new_high_bits, new_low_bits) = bytes.to_bits(); + + if new_high_bits > Zero::zero() { + fail!("Numeric overflow occured.") + } + + match bits.checked_add(&new_low_bits) { + Some(x) => return x, + None => fail!("Numeric overflow occured.") + } +} + +/// 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. +trait FixedBuffer { + /// Input a vector of bytes. If the buffer becomes full, process 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]; -use cryptoutil::{write_u32_be, read_u32v_be, add_bytes_to_bits, FixedBuffer, FixedBuffer64, - StandardPadding}; -use digest::Digest; + /// 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; +} + +/// A fixed size buffer of 64 bytes useful for cryptographic operations. +struct FixedBuffer64 { + priv buffer: [u8, ..64], + priv buffer_idx: uint, +} + +impl FixedBuffer64 { + /// Create a new buffer + fn new() -> FixedBuffer64 { + return FixedBuffer64 { + buffer: [0u8, ..64], + buffer_idx: 0 + }; + } +} + +impl FixedBuffer for FixedBuffer64 { + fn input(&mut self, input: &[u8], func: &fn(&[u8])) { + let mut i = 0; + + let size = 64; + + // 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 == 64); + self.buffer_idx = 0; + return self.buffer.slice_to(64); + } + + fn position(&self) -> uint { self.buffer_idx } + + fn remaining(&self) -> uint { 64 - self.buffer_idx } + + fn size(&self) -> uint { 64 } +} + +/// The StandardPadding trait adds a method useful for various hash algorithms to a FixedBuffer +/// struct. +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); + } +} + +/** + * The Digest trait specifies an interface common to digest functions, such as SHA-1 and the SHA-2 + * family of digest functions. + */ +pub trait Digest { + /** + * Provide message data. + * + * # Arguments + * + * * input - A vector of message data + */ + fn input(&mut self, input: &[u8]); + + /** + * 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]); + + /** + * Reset the digest. This method must be called after result() and before supplying more + * data. + */ + fn reset(&mut self); + + /** + * Get the output size in bits. + */ + fn output_bits(&self) -> uint; + + /** + * Convenience function that feeds a string into a digest. + * + * # Arguments + * + * * `input` The string to feed into the digest + */ + fn input_str(&mut self, input: &str) { + self.input(input.as_bytes()); + } + + /** + * Convenience function that retrieves the result of a digest as a + * newly allocated vec of bytes. + */ + fn result_bytes(&mut self) -> ~[u8] { + let mut buf = vec::from_elem((self.output_bits()+7)/8, 0u8); + self.result(buf); + buf + } + + /** + * Convenience function that retrieves the result of a digest as a + * ~str in hexadecimal format. + */ + fn result_str(&mut self) -> ~str { + self.result_bytes().to_hex() + } +} /* * A SHA-1 implementation derived from Paul E. Jones's reference @@ -180,9 +448,10 @@ impl Digest for Sha1 { #[cfg(test)] mod tests { - use cryptoutil::test::test_digest_1million_random; - use digest::Digest; - use sha1::Sha1; + use std::rand::{IsaacRng, Rng}; + use std::vec; + use extra::hex::FromHex; + use super::{Digest, Sha1, add_bytes_to_bits}; #[deriving(Clone)] struct Test { @@ -287,6 +556,31 @@ mod tests { } } + /// Feed 1,000,000 'a's into the digest with varying input sizes and check that the result is + /// correct. + 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_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(); + let result_bytes = digest.result_bytes(); + + assert_eq!(expected, result_str.as_slice()); + assert_eq!(expected.from_hex().unwrap(), result_bytes); + } + #[test] fn test_1million_random_sha1() { let mut sh = Sha1::new(); @@ -295,13 +589,25 @@ mod tests { 64, "34aa973cd4c4daa4f61eeb2bdbad27316534016f"); } + + // A normal addition - no overflow occurs + #[test] + fn test_add_bytes_to_bits_ok() { + assert!(add_bytes_to_bits::<u64>(100, 10) == 180); + } + + // A simple failure case - adding 1 to the max value + #[test] + #[should_fail] + fn test_add_bytes_to_bits_overflow() { + add_bytes_to_bits::<u64>(Bounded::max_value(), 1); + } } #[cfg(test)] mod bench { use extra::test::BenchHarness; - - use sha1::Sha1; + use super::Sha1; #[bench] pub fn sha1_10(bh: & mut BenchHarness) { @@ -332,5 +638,4 @@ mod bench { } bh.bytes = bytes.len() as u64; } - } diff --git a/src/librustpkg/workcache_support.rs b/src/librustpkg/workcache_support.rs index 1cdaefd592b..3adb33ec2f4 100644 --- a/src/librustpkg/workcache_support.rs +++ b/src/librustpkg/workcache_support.rs @@ -12,8 +12,7 @@ use std::rt::io; use std::rt::io::extensions::ReaderUtil; use std::rt::io::file::FileInfo; use extra::workcache; -use sha1::Sha1; -use digest::Digest; +use sha1::{Digest, Sha1}; /// Hashes the file contents along with the last-modified time pub fn digest_file_with_date(path: &Path) -> ~str { |
