(index<- ) ./libextra/crypto/cryptoutil.rs
1 // Copyright 2012-2013 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 use std::num::{One, Zero, CheckedAdd};
12 use std::vec::bytes::{MutableByteVector, copy_memory};
13
14
15 /// Write a u64 into a vector, which must be 8 bytes long. The value is written in big-endian
16 /// format.
17 pub fn write_u64_be(dst: &mut[u8], input: u64) {
18 use std::cast::transmute;
19 use std::unstable::intrinsics::to_be64;
20 assert!(dst.len() == 8);
21 unsafe {
22 let x: *mut i64 = transmute(dst.unsafe_mut_ref(0));
23 *x = to_be64(input as i64);
24 }
25 }
26
27 /// Write a u32 into a vector, which must be 4 bytes long. The value is written in big-endian
28 /// format.
29 pub fn write_u32_be(dst: &mut[u8], input: u32) {
30 use std::cast::transmute;
31 use std::unstable::intrinsics::to_be32;
32 assert!(dst.len() == 4);
33 unsafe {
34 let x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
35 *x = to_be32(input as i32);
36 }
37 }
38
39 /// Write a u32 into a vector, which must be 4 bytes long. The value is written in little-endian
40 /// format.
41 pub fn write_u32_le(dst: &mut[u8], input: u32) {
42 use std::cast::transmute;
43 use std::unstable::intrinsics::to_le32;
44 assert!(dst.len() == 4);
45 unsafe {
46 let x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
47 *x = to_le32(input as i32);
48 }
49 }
50
51 /// Read a vector of bytes into a vector of u64s. The values are read in big-endian format.
52 pub fn read_u64v_be(dst: &mut[u64], input: &[u8]) {
53 use std::cast::transmute;
54 use std::unstable::intrinsics::to_be64;
55 assert!(dst.len() * 8 == input.len());
56 unsafe {
57 let mut x: *mut i64 = transmute(dst.unsafe_mut_ref(0));
58 let mut y: *i64 = transmute(input.unsafe_ref(0));
59 do dst.len().times() {
60 *x = to_be64(*y);
61 x = x.offset(1);
62 y = y.offset(1);
63 }
64 }
65 }
66
67 /// Read a vector of bytes into a vector of u32s. The values are read in big-endian format.
68 pub fn read_u32v_be(dst: &mut[u32], input: &[u8]) {
69 use std::cast::transmute;
70 use std::unstable::intrinsics::to_be32;
71 assert!(dst.len() * 4 == input.len());
72 unsafe {
73 let mut x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
74 let mut y: *i32 = transmute(input.unsafe_ref(0));
75 do dst.len().times() {
76 *x = to_be32(*y);
77 x = x.offset(1);
78 y = y.offset(1);
79 }
80 }
81 }
82
83 /// Read a vector of bytes into a vector of u32s. The values are read in little-endian format.
84 pub fn read_u32v_le(dst: &mut[u32], input: &[u8]) {
85 use std::cast::transmute;
86 use std::unstable::intrinsics::to_le32;
87 assert!(dst.len() * 4 == input.len());
88 unsafe {
89 let mut x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
90 let mut y: *i32 = transmute(input.unsafe_ref(0));
91 do dst.len().times() {
92 *x = to_le32(*y);
93 x = x.offset(1);
94 y = y.offset(1);
95 }
96 }
97 }
98
99
100 trait ToBits {
101 /// Convert the value in bytes to the number of bits, a tuple where the 1st item is the
102 /// high-order value and the 2nd item is the low order value.
103 fn to_bits(self) -> (Self, Self);
104 }
105
106 impl ToBits for u64 {
107 fn to_bits(self) -> (u64, u64) {
108 return (self >> 61, self << 3);
109 }
110 }
111
112 /// Adds the specified number of bytes to the bit count. fail!() if this would cause numeric
113 /// overflow.
114 pub fn add_bytes_to_bits<T: Int + CheckedAdd + ToBits>(bits: T, bytes: T) -> T {
115 let (new_high_bits, new_low_bits) = bytes.to_bits();
116
117 if new_high_bits > Zero::zero() {
118 fail!("Numeric overflow occured.")
119 }
120
121 match bits.checked_add(&new_low_bits) {
122 Some(x) => return x,
123 None => fail!("Numeric overflow occured.")
124 }
125 }
126
127 /// Adds the specified number of bytes to the bit count, which is a tuple where the first element is
128 /// the high order value. fail!() if this would cause numeric overflow.
129 pub fn add_bytes_to_bits_tuple
130 <T: Int + Unsigned + CheckedAdd + ToBits>
131 (bits: (T, T), bytes: T) -> (T, T) {
132 let (new_high_bits, new_low_bits) = bytes.to_bits();
133 let (hi, low) = bits;
134
135 // Add the low order value - if there is no overflow, then add the high order values
136 // If the addition of the low order values causes overflow, add one to the high order values
137 // before adding them.
138 match low.checked_add(&new_low_bits) {
139 Some(x) => {
140 if new_high_bits == Zero::zero() {
141 // This is the fast path - every other alternative will rarely occur in practice
142 // considering how large an input would need to be for those paths to be used.
143 return (hi, x);
144 } else {
145 match hi.checked_add(&new_high_bits) {
146 Some(y) => return (y, x),
147 None => fail!("Numeric overflow occured.")
148 }
149 }
150 },
151 None => {
152 let one: T = One::one();
153 let z = match new_high_bits.checked_add(&one) {
154 Some(w) => w,
155 None => fail!("Numeric overflow occured.")
156 };
157 match hi.checked_add(&z) {
158 // This re-executes the addition that was already performed earlier when overflow
159 // occured, this time allowing the overflow to happen. Technically, this could be
160 // avoided by using the checked add intrinsic directly, but that involves using
161 // unsafe code and is not really worthwhile considering how infrequently code will
162 // run in practice. This is the reason that this function requires that the type T
163 // be Unsigned - overflow is not defined for Signed types. This function could be
164 // implemented for signed types as well if that were needed.
165 Some(y) => return (y, low + new_low_bits),
166 None => fail!("Numeric overflow occured.")
167 }
168 }
169 }
170 }
171
172
173 /// A FixedBuffer, likes its name implies, is a fixed size buffer. When the buffer becomes full, it
174 /// must be processed. The input() method takes care of processing and then clearing the buffer
175 /// automatically. However, other methods do not and require the caller to process the buffer. Any
176 /// method that modifies the buffer directory or provides the caller with bytes that can be modifies
177 /// results in those bytes being marked as used by the buffer.
178 pub trait FixedBuffer {
179 /// Input a vector of bytes. If the buffer becomes full, process it with the provided
180 /// function and then clear the buffer.
181 fn input(&mut self, input: &[u8], func: &fn(&[u8]));
182
183 /// Reset the buffer.
184 fn reset(&mut self);
185
186 /// Zero the buffer up until the specified index. The buffer position currently must not be
187 /// greater than that index.
188 fn zero_until(&mut self, idx: uint);
189
190 /// Get a slice of the buffer of the specified size. There must be at least that many bytes
191 /// remaining in the buffer.
192 fn next<'s>(&'s mut self, len: uint) -> &'s mut [u8];
193
194 /// Get the current buffer. The buffer must already be full. This clears the buffer as well.
195 fn full_buffer<'s>(&'s mut self) -> &'s [u8];
196
197 /// Get the current position of the buffer.
198 fn position(&self) -> uint;
199
200 /// Get the number of bytes remaining in the buffer until it is full.
201 fn remaining(&self) -> uint;
202
203 /// Get the size of the buffer
204 fn size(&self) -> uint;
205 }
206
207 macro_rules! impl_fixed_buffer( ($name:ident, $size:expr) => (
208 impl FixedBuffer for $name {
209 fn input(&mut self, input: &[u8], func: &fn(&[u8])) {
210 let mut i = 0;
211
212 // FIXME: #6304 - This local variable shouldn't be necessary.
213 let size = $size;
214
215 // If there is already data in the buffer, copy as much as we can into it and process
216 // the data if the buffer becomes full.
217 if self.buffer_idx != 0 {
218 let buffer_remaining = size - self.buffer_idx;
219 if input.len() >= buffer_remaining {
220 copy_memory(
221 self.buffer.mut_slice(self.buffer_idx, size),
222 input.slice_to(buffer_remaining),
223 buffer_remaining);
224 self.buffer_idx = 0;
225 func(self.buffer);
226 i += buffer_remaining;
227 } else {
228 copy_memory(
229 self.buffer.mut_slice(self.buffer_idx, self.buffer_idx + input.len()),
230 input,
231 input.len());
232 self.buffer_idx += input.len();
233 return;
234 }
235 }
236
237 // While we have at least a full buffer size chunks's worth of data, process that data
238 // without copying it into the buffer
239 while input.len() - i >= size {
240 func(input.slice(i, i + size));
241 i += size;
242 }
243
244 // Copy any input data into the buffer. At this point in the method, the ammount of
245 // data left in the input vector will be less than the buffer size and the buffer will
246 // be empty.
247 let input_remaining = input.len() - i;
248 copy_memory(
249 self.buffer.mut_slice(0, input_remaining),
250 input.slice_from(i),
251 input.len() - i);
252 self.buffer_idx += input_remaining;
253 }
254
255 fn reset(&mut self) {
256 self.buffer_idx = 0;
257 }
258
259 fn zero_until(&mut self, idx: uint) {
260 assert!(idx >= self.buffer_idx);
261 self.buffer.mut_slice(self.buffer_idx, idx).set_memory(0);
262 self.buffer_idx = idx;
263 }
264
265 fn next<'s>(&'s mut self, len: uint) -> &'s mut [u8] {
266 self.buffer_idx += len;
267 return self.buffer.mut_slice(self.buffer_idx - len, self.buffer_idx);
268 }
269
270 fn full_buffer<'s>(&'s mut self) -> &'s [u8] {
271 assert!(self.buffer_idx == $size);
272 self.buffer_idx = 0;
273 return self.buffer.slice_to($size);
274 }
275
276 fn position(&self) -> uint { self.buffer_idx }
277
278 fn remaining(&self) -> uint { $size - self.buffer_idx }
279
280 fn size(&self) -> uint { $size }
281 }
282 ))
283
284
285 /// A fixed size buffer of 64 bytes useful for cryptographic operations.
286 pub struct FixedBuffer64 {
287 priv buffer: [u8, ..64],
288 priv buffer_idx: uint,
289 }
290
291 impl FixedBuffer64 {
292 /// Create a new buffer
293 pub fn new() -> FixedBuffer64 {
294 return FixedBuffer64 {
295 buffer: [0u8, ..64],
296 buffer_idx: 0
297 };
298 }
299 }
300
301 impl_fixed_buffer!(FixedBuffer64, 64)
302
303 /// A fixed size buffer of 128 bytes useful for cryptographic operations.
304 pub struct FixedBuffer128 {
305 priv buffer: [u8, ..128],
306 priv buffer_idx: uint,
307 }
308
309 impl FixedBuffer128 {
310 /// Create a new buffer
311 pub fn new() -> FixedBuffer128 {
312 return FixedBuffer128 {
313 buffer: [0u8, ..128],
314 buffer_idx: 0
315 };
316 }
317 }
318
319 impl_fixed_buffer!(FixedBuffer128, 128)
320
321
322 /// The StandardPadding trait adds a method useful for various hash algorithms to a FixedBuffer
323 /// struct.
324 pub trait StandardPadding {
325 /// Add standard padding to the buffer. The buffer must not be full when this method is called
326 /// and is guaranteed to have exactly rem remaining bytes when it returns. If there are not at
327 /// least rem bytes available, the buffer will be zero padded, processed, cleared, and then
328 /// filled with zeros again until only rem bytes are remaining.
329 fn standard_padding(&mut self, rem: uint, func: &fn(&[u8]));
330 }
331
332 impl <T: FixedBuffer> StandardPadding for T {
333 fn standard_padding(&mut self, rem: uint, func: &fn(&[u8])) {
334 let size = self.size();
335
336 self.next(1)[0] = 128;
337
338 if self.remaining() < rem {
339 self.zero_until(size);
340 func(self.full_buffer());
341 }
342
343 self.zero_until(size - rem);
344 }
345 }
346
347
348 #[cfg(test)]
349 mod test {
350 use std::rand::{IsaacRng, Rng};
351 use std::vec;
352
353 use cryptoutil::{add_bytes_to_bits, add_bytes_to_bits_tuple};
354 use digest::Digest;
355
356 /// Feed 1,000,000 'a's into the digest with varying input sizes and check that the result is
357 /// correct.
358 pub fn test_digest_1million_random<D: Digest>(digest: &mut D, blocksize: uint, expected: &str) {
359 let total_size = 1000000;
360 let buffer = vec::from_elem(blocksize * 2, 'a' as u8);
361 let mut rng = IsaacRng::new_unseeded();
362 let mut count = 0;
363
364 digest.reset();
365
366 while count < total_size {
367 let next: uint = rng.gen_integer_range(0, 2 * blocksize + 1);
368 let remaining = total_size - count;
369 let size = if next > remaining { remaining } else { next };
370 digest.input(buffer.slice_to(size));
371 count += size;
372 }
373
374 let result_str = digest.result_str();
375
376 assert!(expected == result_str);
377 }
378
379 // A normal addition - no overflow occurs
380 #[test]
381 fn test_add_bytes_to_bits_ok() {
382 assert!(add_bytes_to_bits::<u64>(100, 10) == 180);
383 }
384
385 // A simple failure case - adding 1 to the max value
386 #[test]
387 #[should_fail]
388 fn test_add_bytes_to_bits_overflow() {
389 add_bytes_to_bits::<u64>(Bounded::max_value(), 1);
390 }
391
392 // A normal addition - no overflow occurs (fast path)
393 #[test]
394 fn test_add_bytes_to_bits_tuple_ok() {
395 assert!(add_bytes_to_bits_tuple::<u64>((5, 100), 10) == (5, 180));
396 }
397
398 // The low order value overflows into the high order value
399 #[test]
400 fn test_add_bytes_to_bits_tuple_ok2() {
401 assert!(add_bytes_to_bits_tuple::<u64>((5, Bounded::max_value()), 1) == (6, 7));
402 }
403
404 // The value to add is too large to be converted into bits without overflowing its type
405 #[test]
406 fn test_add_bytes_to_bits_tuple_ok3() {
407 assert!(add_bytes_to_bits_tuple::<u64>((5, 0), 0x4000000000000001) == (7, 8));
408 }
409
410 // A simple failure case - adding 1 to the max value
411 #[test]
412 #[should_fail]
413 fn test_add_bytes_to_bits_tuple_overflow() {
414 add_bytes_to_bits_tuple::<u64>((Bounded::max_value(), Bounded::max_value()), 1);
415 }
416
417 // The value to add is too large to convert to bytes without overflowing its type, but the high
418 // order value from this conversion overflows when added to the existing high order value
419 #[test]
420 #[should_fail]
421 fn test_add_bytes_to_bits_tuple_overflow2() {
422 let value: u64 = Bounded::max_value();
423 add_bytes_to_bits_tuple::<u64>((value - 1, 0), 0x8000000000000000);
424 }
425 }
libextra/crypto/cryptoutil.rs:51:92-51:92 -fn- definition:
/// 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]) {
references:-libextra/crypto/sha2.rs:
110: read_u64v_be(W.mut_slice(0, 16), data);
libextra/crypto/cryptoutil.rs:285:73-285:73 -struct- definition:
/// A fixed size buffer of 64 bytes useful for cryptographic operations.
pub struct FixedBuffer64 {
references:-294: return FixedBuffer64 {
293: pub fn new() -> FixedBuffer64 {
208: impl FixedBuffer for $name {
291: impl FixedBuffer64 {
libextra/crypto/md5.rs:
161: priv buffer: FixedBuffer64,
libextra/crypto/sha1.rs:
48: priv buffer: FixedBuffer64,
libextra/crypto/sha2.rs:
594: buffer: FixedBuffer64,
libextra/crypto/cryptoutil.rs:28:12-28:12 -fn- definition:
/// format.
pub fn write_u32_be(dst: &mut[u8], input: u32) {
references:-libextra/crypto/sha1.rs:
134: write_u32_be(st.buffer.next(4), st.length_bits as u32);
143: write_u32_be(rs.mut_slice(12, 16), st.h[3]);
133: write_u32_be(st.buffer.next(4), (st.length_bits >> 32) as u32 );
142: write_u32_be(rs.mut_slice(8, 12), st.h[2]);
144: write_u32_be(rs.mut_slice(16, 20), st.h[4]);
140: write_u32_be(rs.mut_slice(0, 4), st.h[0]);
141: write_u32_be(rs.mut_slice(4, 8), st.h[1]);
libextra/crypto/sha2.rs:
664: write_u32_be(out.mut_slice(12, 16), self.engine.state.H3);
661: write_u32_be(out.mut_slice(0, 4), self.engine.state.H0);
667: write_u32_be(out.mut_slice(24, 28), self.engine.state.H6);
662: write_u32_be(out.mut_slice(4, 8), self.engine.state.H1);
717: write_u32_be(out.mut_slice(20, 24), self.engine.state.H5);
718: write_u32_be(out.mut_slice(24, 28), self.engine.state.H6);
712: write_u32_be(out.mut_slice(0, 4), self.engine.state.H0);
716: write_u32_be(out.mut_slice(16, 20), self.engine.state.H4);
630: write_u32_be(self.buffer.next(4), self.length_bits as u32);
629: write_u32_be(self.buffer.next(4), (self.length_bits >> 32) as u32 );
668: write_u32_be(out.mut_slice(28, 32), self.engine.state.H7);
409: write_u32_be(out.mut_slice(24, 28), (self.engine.state.H3 >> 32) as u32);
713: write_u32_be(out.mut_slice(4, 8), self.engine.state.H1);
714: write_u32_be(out.mut_slice(8, 12), self.engine.state.H2);
666: write_u32_be(out.mut_slice(20, 24), self.engine.state.H5);
715: write_u32_be(out.mut_slice(12, 16), self.engine.state.H3);
665: write_u32_be(out.mut_slice(16, 20), self.engine.state.H4);
663: write_u32_be(out.mut_slice(8, 12), self.engine.state.H2);
libextra/crypto/cryptoutil.rs:40:12-40:12 -fn- definition:
/// format.
pub fn write_u32_le(dst: &mut[u8], input: u32) {
references:-libextra/crypto/md5.rs:
198: write_u32_le(self.buffer.next(4), (self.length_bytes >> 29) as u32);
206: write_u32_le(out.mut_slice(12, 16), self.state.s3);
204: write_u32_le(out.mut_slice(4, 8), self.state.s1);
203: write_u32_le(out.mut_slice(0, 4), self.state.s0);
205: write_u32_le(out.mut_slice(8, 12), self.state.s2);
197: write_u32_le(self.buffer.next(4), (self.length_bytes << 3) as u32);
libextra/crypto/cryptoutil.rs:128:72-128:72 -fn- definition:
/// the high order value. fail!() if this would cause numeric overflow.
pub fn add_bytes_to_bits_tuple
references:-libextra/crypto/sha2.rs:
210: self.length_bits = add_bytes_to_bits_tuple(self.length_bits, input.len() as u64);
libextra/crypto/cryptoutil.rs:67:92-67:92 -fn- definition:
/// 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]) {
references:-libextra/crypto/sha1.rs:
65: read_u32v_be(w.mut_slice(0, 16), data);
libextra/crypto/sha2.rs:
524: read_u32v_be(W.mut_slice(0, 16), data);
libextra/crypto/cryptoutil.rs:99:1-99:1 -trait- definition:
trait ToBits {
references:-103: fn to_bits(self) -> (Self, Self);
103: fn to_bits(self) -> (Self, Self);
106: impl ToBits for u64 {
130: <T: Int + Unsigned + CheckedAdd + ToBits>
114: pub fn add_bytes_to_bits<T: Int + CheckedAdd + ToBits>(bits: T, bytes: T) -> T {
libextra/crypto/cryptoutil.rs:16:12-16:12 -fn- definition:
/// format.
pub fn write_u64_be(dst: &mut[u8], input: u64) {
references:-libextra/crypto/sha2.rs:
259: write_u64_be(out.mut_slice(24, 32), self.engine.state.H3);
260: write_u64_be(out.mut_slice(32, 40), self.engine.state.H4);
359: write_u64_be(out.mut_slice(8, 16), self.engine.state.H1);
261: write_u64_be(out.mut_slice(40, 48), self.engine.state.H5);
223: write_u64_be(self.buffer.next(8), low);
311: write_u64_be(out.mut_slice(24, 32), self.engine.state.H3);
258: write_u64_be(out.mut_slice(16, 24), self.engine.state.H2);
313: write_u64_be(out.mut_slice(40, 48), self.engine.state.H5);
257: write_u64_be(out.mut_slice(8, 16), self.engine.state.H1);
360: write_u64_be(out.mut_slice(16, 24), self.engine.state.H2);
222: write_u64_be(self.buffer.next(8), hi);
310: write_u64_be(out.mut_slice(16, 24), self.engine.state.H2);
263: write_u64_be(out.mut_slice(56, 64), self.engine.state.H7);
312: write_u64_be(out.mut_slice(32, 40), self.engine.state.H4);
256: write_u64_be(out.mut_slice(0, 8), self.engine.state.H0);
262: write_u64_be(out.mut_slice(48, 56), self.engine.state.H6);
408: write_u64_be(out.mut_slice(16, 24), self.engine.state.H2);
361: write_u64_be(out.mut_slice(24, 32), self.engine.state.H3);
407: write_u64_be(out.mut_slice(8, 16), self.engine.state.H1);
406: write_u64_be(out.mut_slice(0, 8), self.engine.state.H0);
358: write_u64_be(out.mut_slice(0, 8), self.engine.state.H0);
308: write_u64_be(out.mut_slice(0, 8), self.engine.state.H0);
309: write_u64_be(out.mut_slice(8, 16), self.engine.state.H1);
libextra/crypto/cryptoutil.rs:113:14-113:14 -fn- definition:
/// overflow.
pub fn add_bytes_to_bits<T: Int + CheckedAdd + ToBits>(bits: T, bytes: T) -> T {
references:-libextra/crypto/sha1.rs:
55: st.length_bits = add_bytes_to_bits(st.length_bits, msg.len() as u64);
libextra/crypto/sha2.rs:
619: self.length_bits = add_bytes_to_bits(self.length_bits, input.len() as u64);
libextra/crypto/cryptoutil.rs:83:95-83:95 -fn- definition:
/// Read a vector of bytes into a vector of u32s. The values are read in little-endian format.
pub fn read_u32v_le(dst: &mut[u32], input: &[u8]) {
references:-libextra/crypto/md5.rs:
86: read_u32v_le(data, input);
libextra/crypto/cryptoutil.rs:303:74-303:74 -struct- definition:
/// A fixed size buffer of 128 bytes useful for cryptographic operations.
pub struct FixedBuffer128 {
references:-311: pub fn new() -> FixedBuffer128 {
309: impl FixedBuffer128 {
208: impl FixedBuffer for $name {
312: return FixedBuffer128 {
libextra/crypto/sha2.rs:
185: buffer: FixedBuffer128,
libextra/crypto/cryptoutil.rs:323:12-323:12 -trait- definition:
/// struct.
pub trait StandardPadding {
references:-332: impl <T: FixedBuffer> StandardPadding for T {
libextra/crypto/cryptoutil.rs:177:63-177:63 -trait- definition:
/// results in those bytes being marked as used by the buffer.
pub trait FixedBuffer {
references:-208: impl FixedBuffer for $name {
208: impl FixedBuffer for $name {
332: impl <T: FixedBuffer> StandardPadding for T {