(index<- )        ./libextra/crypto/sha1.rs

   1  // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  /*!
  12   * An implementation of the SHA-1 cryptographic hash.
  13   *
  14   * First create a `sha1` object using the `sha1` constructor, then
  15   * feed it input using the `input` or `input_str` methods, which may be
  16   * called any number of times.
  17   *
  18   * After the entire input has been fed to the hash read the result using
  19   * the `result` or `result_str` methods.
  20   *
  21   * The `sha1` object may be reused to create multiple hashes by calling
  22   * the `reset` method.
  23   */
  24  
  25  
  26  use cryptoutil::{write_u32_be, read_u32v_be, add_bytes_to_bits, FixedBuffer, FixedBuffer64,
  27      StandardPadding};
  28  use digest::Digest;
  29  
  30  /*
  31   * A SHA-1 implementation derived from Paul E. Jones's reference
  32   * implementation, which is written for clarity, not speed. At some
  33   * point this will want to be rewritten.
  34   */
  35  
  36  // Some unexported constants
  37  static DIGEST_BUF_LEN: uint = 5u;
  38  static WORK_BUF_LEN: uint = 80u;
  39  static K0: u32 = 0x5A827999u32;
  40  static K1: u32 = 0x6ED9EBA1u32;
  41  static K2: u32 = 0x8F1BBCDCu32;
  42  static K3: u32 = 0xCA62C1D6u32;
  43  
  44  /// Structure representing the state of a Sha1 computation
  45  pub struct Sha1 {
  46      priv h: [u32, ..DIGEST_BUF_LEN],
  47      priv length_bits: u64,
  48      priv buffer: FixedBuffer64,
  49      priv computed: bool,
  50  }
  51  
  52  fn add_input(st&mut Sha1, msg&[u8]) {
  53      assert!((!st.computed));
  54      // Assumes that msg.len() can be converted to u64 without overflow
  55      st.length_bits = add_bytes_to_bits(st.length_bits, msg.len() as u64);
  56      st.buffer.input(msg, |d&[u8]{ process_msg_block(d, &mut st.h); });
  57  }
  58  
  59  fn process_msg_block(data&[u8], h&mut [u32, ..DIGEST_BUF_LEN]) {
  60      let mut tint; // Loop counter
  61  
  62      let mut w = [0u32, ..WORK_BUF_LEN];
  63  
  64      // Initialize the first 16 words of the vector w
  65      read_u32v_be(w.mut_slice(0, 16), data);
  66  
  67      // Initialize the rest of vector w
  68      t = 16;
  69      while t < 80 {
  70          let val = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16];
  71          w[t] = circular_shift(1, val);
  72          t += 1;
  73      }
  74      let mut a = h[0];
  75      let mut b = h[1];
  76      let mut c = h[2];
  77      let mut d = h[3];
  78      let mut e = h[4];
  79      let mut tempu32;
  80      t = 0;
  81      while t < 20 {
  82          temp = circular_shift(5, a) + (b & c | !b & d) + e + w[t] + K0;
  83          e = d;
  84          d = c;
  85          c = circular_shift(30, b);
  86          b = a;
  87          a = temp;
  88          t += 1;
  89      }
  90      while t < 40 {
  91          temp = circular_shift(5, a) + (b ^ c ^ d) + e + w[t] + K1;
  92          e = d;
  93          d = c;
  94          c = circular_shift(30, b);
  95          b = a;
  96          a = temp;
  97          t += 1;
  98      }
  99      while t < 60 {
 100          temp =
 101              circular_shift(5, a) + (b & c | b & d | c & d) + e + w[t] +
 102                  K2;
 103          e = d;
 104          d = c;
 105          c = circular_shift(30, b);
 106          b = a;
 107          a = temp;
 108          t += 1;
 109      }
 110      while t < 80 {
 111          temp = circular_shift(5, a) + (b ^ c ^ d) + e + w[t] + K3;
 112          e = d;
 113          d = c;
 114          c = circular_shift(30, b);
 115          b = a;
 116          a = temp;
 117          t += 1;
 118      }
 119      h[0] += a;
 120      h[1] += b;
 121      h[2] += c;
 122      h[3] += d;
 123      h[4] += e;
 124  }
 125  
 126  fn circular_shift(bitsu32, wordu32) -> u32 {
 127      return word << bits | word >> 32u32 - bits;
 128  }
 129  
 130  fn mk_result(st&mut Sha1, rs&mut [u8]) {
 131      if !st.computed {
 132          st.buffer.standard_padding(8, |d&[u8]{ process_msg_block(d, &mut st.h) });
 133          write_u32_be(st.buffer.next(4), (st.length_bits >> 32) as u32 );
 134          write_u32_be(st.buffer.next(4), st.length_bits as u32);
 135          process_msg_block(st.buffer.full_buffer(), &mut st.h);
 136  
 137          st.computed = true;
 138      }
 139  
 140      write_u32_be(rs.mut_slice(0, 4), st.h[0]);
 141      write_u32_be(rs.mut_slice(4, 8), st.h[1]);
 142      write_u32_be(rs.mut_slice(8, 12), st.h[2]);
 143      write_u32_be(rs.mut_slice(12, 16), st.h[3]);
 144      write_u32_be(rs.mut_slice(16, 20), st.h[4]);
 145  }
 146  
 147  impl Sha1 {
 148      /// Construct a `sha` object
 149      pub fn new() -> Sha1 {
 150          let mut st = Sha1 {
 151              h: [0u32, ..DIGEST_BUF_LEN],
 152              length_bits: 0u64,
 153              buffer: FixedBuffer64::new(),
 154              computed: false,
 155          };
 156          st.reset();
 157          return st;
 158      }
 159  }
 160  
 161  impl Digest for Sha1 {
 162      fn reset(&mut self) {
 163          self.length_bits = 0;
 164          self.h[0] = 0x67452301u32;
 165          self.h[1] = 0xEFCDAB89u32;
 166          self.h[2] = 0x98BADCFEu32;
 167          self.h[3] = 0x10325476u32;
 168          self.h[4] = 0xC3D2E1F0u32;
 169          self.buffer.reset();
 170          self.computed = false;
 171      }
 172      fn input(&mut self, msg&[u8]) { add_input(self, msg); }
 173      fn result(&mut self, out&mut [u8]) { return mk_result(self, out); }
 174      fn output_bits(&self) -> uint { 160 }
 175  }
 176  
 177  #[cfg(test)]
 178  mod tests {
 179      use cryptoutil::test::test_digest_1million_random;
 180      use digest::Digest;
 181      use sha1::Sha1;
 182  
 183      #[deriving(Clone)]
 184      struct Test {
 185          input: ~str,
 186          output: ~[u8],
 187          output_str: ~str,
 188      }
 189  
 190      #[test]
 191      fn test() {
 192          // Test messages from FIPS 180-1
 193  
 194          let fips_180_1_tests = ~[
 195              Test {
 196                  input: ~"abc",
 197                  output: ~[
 198                      0xA9u8, 0x99u8, 0x3Eu8, 0x36u8,
 199                      0x47u8, 0x06u8, 0x81u8, 0x6Au8,
 200                      0xBAu8, 0x3Eu8, 0x25u8, 0x71u8,
 201                      0x78u8, 0x50u8, 0xC2u8, 0x6Cu8,
 202                      0x9Cu8, 0xD0u8, 0xD8u8, 0x9Du8,
 203                  ],
 204                  output_str: ~"a9993e364706816aba3e25717850c26c9cd0d89d"
 205              },
 206              Test {
 207                  input:
 208                       ~"abcdbcdecdefdefgefghfghighij" +
 209                       "hijkijkljklmklmnlmnomnopnopq",
 210                  output: ~[
 211                      0x84u8, 0x98u8, 0x3Eu8, 0x44u8,
 212                      0x1Cu8, 0x3Bu8, 0xD2u8, 0x6Eu8,
 213                      0xBAu8, 0xAEu8, 0x4Au8, 0xA1u8,
 214                      0xF9u8, 0x51u8, 0x29u8, 0xE5u8,
 215                      0xE5u8, 0x46u8, 0x70u8, 0xF1u8,
 216                  ],
 217                  output_str: ~"84983e441c3bd26ebaae4aa1f95129e5e54670f1"
 218              },
 219          ];
 220          // Examples from wikipedia
 221  
 222          let wikipedia_tests = ~[
 223              Test {
 224                  input: ~"The quick brown fox jumps over the lazy dog",
 225                  output: ~[
 226                      0x2fu8, 0xd4u8, 0xe1u8, 0xc6u8,
 227                      0x7au8, 0x2du8, 0x28u8, 0xfcu8,
 228                      0xedu8, 0x84u8, 0x9eu8, 0xe1u8,
 229                      0xbbu8, 0x76u8, 0xe7u8, 0x39u8,
 230                      0x1bu8, 0x93u8, 0xebu8, 0x12u8,
 231                  ],
 232                  output_str: ~"2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
 233              },
 234              Test {
 235                  input: ~"The quick brown fox jumps over the lazy cog",
 236                  output: ~[
 237                      0xdeu8, 0x9fu8, 0x2cu8, 0x7fu8,
 238                      0xd2u8, 0x5eu8, 0x1bu8, 0x3au8,
 239                      0xfau8, 0xd3u8, 0xe8u8, 0x5au8,
 240                      0x0bu8, 0xd1u8, 0x7du8, 0x9bu8,
 241                      0x10u8, 0x0du8, 0xb4u8, 0xb3u8,
 242                  ],
 243                  output_str: ~"de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3",
 244              },
 245          ];
 246          let tests = fips_180_1_tests + wikipedia_tests;
 247  
 248          // Test that it works when accepting the message all at once
 249  
 250          let mut out = [0u8, ..20];
 251  
 252          let mut sh = ~Sha1::new();
 253          for t in tests.iter() {
 254              (*sh).input_str(t.input);
 255              sh.result(out);
 256              assert!(t.output.as_slice() == out);
 257  
 258              let out_str = (*sh).result_str();
 259              assert_eq!(out_str.len(), 40);
 260              assert!(out_str == t.output_str);
 261  
 262              sh.reset();
 263          }
 264  
 265  
 266          // Test that it works when accepting the message in pieces
 267          for t in tests.iter() {
 268              let len = t.input.len();
 269              let mut left = len;
 270              while left > 0u {
 271                  let take = (left + 1u) / 2u;
 272                  (*sh).input_str(t.input.slice(len - left, take + len - left));
 273                  left = left - take;
 274              }
 275              sh.result(out);
 276              assert!(t.output.as_slice() == out);
 277  
 278              let out_str = (*sh).result_str();
 279              assert_eq!(out_str.len(), 40);
 280              assert!(out_str == t.output_str);
 281  
 282              sh.reset();
 283          }
 284      }
 285  
 286      #[test]
 287      fn test_1million_random_sha1() {
 288          let mut sh = Sha1::new();
 289          test_digest_1million_random(
 290              &mut sh,
 291              64,
 292              "34aa973cd4c4daa4f61eeb2bdbad27316534016f");
 293      }
 294  }
 295  
 296  #[cfg(test)]
 297  mod bench {
 298  
 299      use sha1::Sha1;
 300      use test::BenchHarness;
 301  
 302      #[bench]
 303      pub fn sha1_10(bh: & mut BenchHarness) {
 304          let mut sh = Sha1::new();
 305          let bytes = [1u8, ..10];
 306          do bh.iter {
 307              sh.input(bytes);
 308          }
 309          bh.bytes = bytes.len() as u64;
 310      }
 311  
 312      #[bench]
 313      pub fn sha1_1k(bh: & mut BenchHarness) {
 314          let mut sh = Sha1::new();
 315          let bytes = [1u8, ..1024];
 316          do bh.iter {
 317              sh.input(bytes);
 318          }
 319          bh.bytes = bytes.len() as u64;
 320      }
 321  
 322      #[bench]
 323      pub fn sha1_64k(bh: & mut BenchHarness) {
 324          let mut sh = Sha1::new();
 325          let bytes = [1u8, ..65536];
 326          do bh.iter {
 327              sh.input(bytes);
 328          }
 329          bh.bytes = bytes.len() as u64;
 330      }
 331  
 332  }

libextra/crypto/sha1.rs:58:1-58:1 -fn- definition:

fn process_msg_block(data: &[u8], h: &mut [u32, ..DIGEST_BUF_LEN]) {
references:-
135:         process_msg_block(st.buffer.full_buffer(), &mut st.h);
132:         st.buffer.standard_padding(8, |d: &[u8]| { process_msg_block(d, &mut st.h) });
56:     st.buffer.input(msg, |d: &[u8]| { process_msg_block(d, &mut st.h); });


libextra/crypto/sha1.rs:129:1-129:1 -fn- definition:

fn mk_result(st: &mut Sha1, rs: &mut [u8]) {
references:-
173:     fn result(&mut self, out: &mut [u8]) { return mk_result(self, out); }


libextra/crypto/sha1.rs:125:1-125:1 -fn- definition:

fn circular_shift(bits: u32, word: u32) -> u32 {
references:-
111:         temp = circular_shift(5, a) + (b ^ c ^ d) + e + w[t] + K3;
105:         c = circular_shift(30, b);
94:         c = circular_shift(30, b);
101:             circular_shift(5, a) + (b & c | b & d | c & d) + e + w[t] +
114:         c = circular_shift(30, b);
91:         temp = circular_shift(5, a) + (b ^ c ^ d) + e + w[t] + K1;
82:         temp = circular_shift(5, a) + (b & c | !b & d) + e + w[t] + K0;
71:         w[t] = circular_shift(1, val);
85:         c = circular_shift(30, b);


libextra/crypto/sha1.rs:44:59-44:59 -struct- definition:
/// Structure representing the state of a Sha1 computation
pub struct Sha1 {
references:-
147: impl Sha1 {
52: fn add_input(st: &mut Sha1, msg: &[u8]) {
149:     pub fn new() -> Sha1 {
130: fn mk_result(st: &mut Sha1, rs: &mut [u8]) {
161: impl Digest for Sha1 {
150:         let mut st = Sha1 {


libextra/crypto/sha1.rs:51:1-51:1 -fn- definition:

fn add_input(st: &mut Sha1, msg: &[u8]) {
references:-
172:     fn input(&mut self, msg: &[u8]) { add_input(self, msg); }