(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 t: int; // 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 temp: u32;
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(bits: u32, word: u32) -> 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); }