]> git.proxmox.com Git - cargo.git/blame - vendor/openssl-0.9.15/src/hash.rs
New upstream version 0.22.0
[cargo.git] / vendor / openssl-0.9.15 / src / hash.rs
CommitLineData
d76f7d0b
XL
1use std::io::prelude::*;
2use std::io;
3ee932bc
VK
3use std::ops::{Deref, DerefMut};
4use std::fmt;
d76f7d0b
XL
5use ffi;
6
7#[cfg(ossl110)]
8use ffi::{EVP_MD_CTX_new, EVP_MD_CTX_free};
9#[cfg(any(ossl101, ossl102))]
10use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free};
11
12use {cvt, cvt_p};
13use error::ErrorStack;
14
15#[derive(Copy, Clone)]
16pub struct MessageDigest(*const ffi::EVP_MD);
17
18impl MessageDigest {
19 pub fn md5() -> MessageDigest {
20 unsafe { MessageDigest(ffi::EVP_md5()) }
21 }
22
23 pub fn sha1() -> MessageDigest {
24 unsafe { MessageDigest(ffi::EVP_sha1()) }
25 }
26
27 pub fn sha224() -> MessageDigest {
28 unsafe { MessageDigest(ffi::EVP_sha224()) }
29 }
30
31 pub fn sha256() -> MessageDigest {
32 unsafe { MessageDigest(ffi::EVP_sha256()) }
33 }
34
35 pub fn sha384() -> MessageDigest {
36 unsafe { MessageDigest(ffi::EVP_sha384()) }
37 }
38
39 pub fn sha512() -> MessageDigest {
40 unsafe { MessageDigest(ffi::EVP_sha512()) }
41 }
42
43 pub fn ripemd160() -> MessageDigest {
44 unsafe { MessageDigest(ffi::EVP_ripemd160()) }
45 }
46
47 pub fn as_ptr(&self) -> *const ffi::EVP_MD {
48 self.0
49 }
50}
51
52#[derive(PartialEq, Copy, Clone)]
53enum State {
54 Reset,
55 Updated,
56 Finalized,
57}
58
59use self::State::*;
60
61/// Provides message digest (hash) computation.
62///
63/// # Examples
64///
65/// Calculate a hash in one go:
66///
67/// ```
68/// use openssl::hash::{hash, MessageDigest};
69///
70/// let data = b"\x42\xF4\x97\xE0";
71/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
72/// let res = hash(MessageDigest::md5(), data).unwrap();
73/// assert_eq!(res, spec);
74/// ```
75///
76/// Supply the input in chunks:
77///
78/// ```
79/// use openssl::hash::{Hasher, MessageDigest};
80///
81/// let data = [b"\x42\xF4", b"\x97\xE0"];
82/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
83/// let mut h = Hasher::new(MessageDigest::md5()).unwrap();
84/// h.update(data[0]).unwrap();
85/// h.update(data[1]).unwrap();
86/// let res = h.finish().unwrap();
87/// assert_eq!(res, spec);
88/// ```
89///
90/// # Warning
91///
92/// Don't actually use MD5 and SHA-1 hashes, they're not secure anymore.
93///
94/// Don't ever hash passwords, use the functions in the `pkcs5` module or bcrypt/scrypt instead.
95pub struct Hasher {
96 ctx: *mut ffi::EVP_MD_CTX,
97 md: *const ffi::EVP_MD,
98 type_: MessageDigest,
99 state: State,
100}
101
102impl Hasher {
103 /// Creates a new `Hasher` with the specified hash type.
104 pub fn new(ty: MessageDigest) -> Result<Hasher, ErrorStack> {
105 ffi::init();
106
107 let ctx = unsafe { try!(cvt_p(EVP_MD_CTX_new())) };
108
109 let mut h = Hasher {
110 ctx: ctx,
111 md: ty.as_ptr(),
112 type_: ty,
113 state: Finalized,
114 };
115 try!(h.init());
116 Ok(h)
117 }
118
119 fn init(&mut self) -> Result<(), ErrorStack> {
120 match self.state {
121 Reset => return Ok(()),
122 Updated => {
3ee932bc 123 try!(self.finish2());
d76f7d0b
XL
124 }
125 Finalized => (),
126 }
127 unsafe {
128 try!(cvt(ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *mut _)));
129 }
130 self.state = Reset;
131 Ok(())
132 }
133
134 /// Feeds data into the hasher.
135 pub fn update(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
136 if self.state == Finalized {
137 try!(self.init());
138 }
139 unsafe {
82fc9e21
VK
140 try!(cvt(ffi::EVP_DigestUpdate(
141 self.ctx,
142 data.as_ptr() as *mut _,
143 data.len(),
144 )));
d76f7d0b
XL
145 }
146 self.state = Updated;
147 Ok(())
148 }
149
3ee932bc 150 #[deprecated(note = "use finish2 instead", since = "0.9.11")]
d76f7d0b 151 pub fn finish(&mut self) -> Result<Vec<u8>, ErrorStack> {
3ee932bc
VK
152 self.finish2().map(|b| b.to_vec())
153 }
154
155 /// Returns the hash of the data written and resets the hasher.
156 ///
157 /// Unlike `finish`, this method does not allocate.
158 pub fn finish2(&mut self) -> Result<DigestBytes, ErrorStack> {
d76f7d0b
XL
159 if self.state == Finalized {
160 try!(self.init());
161 }
162 unsafe {
163 let mut len = ffi::EVP_MAX_MD_SIZE;
3ee932bc 164 let mut buf = [0; ffi::EVP_MAX_MD_SIZE as usize];
82fc9e21
VK
165 try!(cvt(ffi::EVP_DigestFinal_ex(
166 self.ctx,
167 buf.as_mut_ptr(),
168 &mut len,
169 )));
d76f7d0b 170 self.state = Finalized;
3ee932bc
VK
171 Ok(DigestBytes {
172 buf: buf,
173 len: len as usize,
174 })
d76f7d0b
XL
175 }
176 }
177}
178
179impl Write for Hasher {
180 #[inline]
181 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
182 try!(self.update(buf));
183 Ok(buf.len())
184 }
185
186 fn flush(&mut self) -> io::Result<()> {
187 Ok(())
188 }
189}
190
191impl Clone for Hasher {
192 fn clone(&self) -> Hasher {
193 let ctx = unsafe {
194 let ctx = EVP_MD_CTX_new();
195 assert!(!ctx.is_null());
196 let r = ffi::EVP_MD_CTX_copy_ex(ctx, self.ctx);
197 assert_eq!(r, 1);
198 ctx
199 };
200 Hasher {
201 ctx: ctx,
202 md: self.md,
203 type_: self.type_,
204 state: self.state,
205 }
206 }
207}
208
209impl Drop for Hasher {
210 fn drop(&mut self) {
211 unsafe {
212 if self.state != Finalized {
3ee932bc 213 drop(self.finish2());
d76f7d0b
XL
214 }
215 EVP_MD_CTX_free(self.ctx);
216 }
217 }
218}
219
3ee932bc
VK
220/// The resulting bytes of a digest.
221///
222/// This type derefs to a byte slice - it exists to avoid allocating memory to
223/// store the digest data.
224#[derive(Copy)]
225pub struct DigestBytes {
226 buf: [u8; ffi::EVP_MAX_MD_SIZE as usize],
227 len: usize,
228}
229
230impl Clone for DigestBytes {
231 #[inline]
232 fn clone(&self) -> DigestBytes {
233 *self
234 }
235}
236
237impl Deref for DigestBytes {
238 type Target = [u8];
239
240 #[inline]
241 fn deref(&self) -> &[u8] {
242 &self.buf[..self.len]
243 }
244}
245
246impl DerefMut for DigestBytes {
247 #[inline]
248 fn deref_mut(&mut self) -> &mut [u8] {
249 &mut self.buf[..self.len]
250 }
251}
252
253impl AsRef<[u8]> for DigestBytes {
254 #[inline]
255 fn as_ref(&self) -> &[u8] {
256 self.deref()
257 }
258}
259
260impl fmt::Debug for DigestBytes {
261 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
262 fmt::Debug::fmt(&**self, fmt)
263 }
264}
265
266#[deprecated(note = "use hash2 instead", since = "0.9.11")]
d76f7d0b 267pub fn hash(t: MessageDigest, data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
3ee932bc
VK
268 hash2(t, data).map(|b| b.to_vec())
269}
270
271/// Computes the hash of the `data` with the hash `t`.
272///
273/// Unlike `hash`, this function does not allocate the return value.
274pub fn hash2(t: MessageDigest, data: &[u8]) -> Result<DigestBytes, ErrorStack> {
d76f7d0b
XL
275 let mut h = try!(Hasher::new(t));
276 try!(h.update(data));
3ee932bc 277 h.finish2()
d76f7d0b
XL
278}
279
280#[cfg(test)]
281mod tests {
282 use hex::{FromHex, ToHex};
d76f7d0b
XL
283 use std::io::prelude::*;
284
3ee932bc
VK
285 use super::*;
286
d76f7d0b 287 fn hash_test(hashtype: MessageDigest, hashtest: &(&str, &str)) {
3ee932bc 288 let res = hash2(hashtype, &Vec::from_hex(hashtest.0).unwrap()).unwrap();
d76f7d0b
XL
289 assert_eq!(res.to_hex(), hashtest.1);
290 }
291
292 fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) {
293 let _ = h.write_all(&Vec::from_hex(hashtest.0).unwrap()).unwrap();
3ee932bc 294 let res = h.finish2().unwrap();
d76f7d0b
XL
295 assert_eq!(res.to_hex(), hashtest.1);
296 }
297
298 // Test vectors from http://www.nsrl.nist.gov/testdata/
299 #[allow(non_upper_case_globals)]
300 const md5_tests: [(&'static str, &'static str); 13] =
82fc9e21
VK
301 [
302 ("", "d41d8cd98f00b204e9800998ecf8427e"),
303 ("7F", "83acb6e67e50e31db6ed341dd2de1595"),
304 ("EC9C", "0b07f0d4ca797d8ac58874f887cb0b68"),
305 ("FEE57A", "e0d583171eb06d56198fc0ef22173907"),
306 ("42F497E0", "7c430f178aefdf1487fee7144e9641e2"),
307 ("C53B777F1C", "75ef141d64cb37ec423da2d9d440c925"),
308 ("89D5B576327B", "ebbaf15eb0ed784c6faa9dc32831bf33"),
309 ("5D4CCE781EB190", "ce175c4b08172019f05e6b5279889f2c"),
310 ("81901FE94932D7B9", "cd4d2f62b8cdb3a0cf968a735a239281"),
311 ("C9FFDEE7788EFB4EC9", "e0841a231ab698db30c6c0f3f246c014"),
312 ("66AC4B7EBA95E53DC10B", "a3b3cea71910d9af56742aa0bb2fe329"),
313 ("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"),
314 (
315 "AAED18DBE8938C19ED734A8D",
316 "6f80fb775f27e0a4ce5c2f42fc72c5f1",
317 ),
318 ];
d76f7d0b
XL
319
320 #[test]
321 fn test_md5() {
322 for test in md5_tests.iter() {
323 hash_test(MessageDigest::md5(), test);
324 }
325 }
326
327 #[test]
328 fn test_md5_recycle() {
329 let mut h = Hasher::new(MessageDigest::md5()).unwrap();
330 for test in md5_tests.iter() {
331 hash_recycle_test(&mut h, test);
332 }
333 }
334
335 #[test]
336 fn test_finish_twice() {
337 let mut h = Hasher::new(MessageDigest::md5()).unwrap();
82fc9e21
VK
338 h.write_all(&Vec::from_hex(md5_tests[6].0).unwrap())
339 .unwrap();
3ee932bc
VK
340 h.finish2().unwrap();
341 let res = h.finish2().unwrap();
342 let null = hash2(MessageDigest::md5(), &[]).unwrap();
343 assert_eq!(&*res, &*null);
d76f7d0b
XL
344 }
345
346 #[test]
347 fn test_clone() {
348 let i = 7;
349 let inp = Vec::from_hex(md5_tests[i].0).unwrap();
350 assert!(inp.len() > 2);
351 let p = inp.len() / 2;
352 let h0 = Hasher::new(MessageDigest::md5()).unwrap();
353
354 println!("Clone a new hasher");
355 let mut h1 = h0.clone();
356 h1.write_all(&inp[..p]).unwrap();
357 {
358 println!("Clone an updated hasher");
359 let mut h2 = h1.clone();
360 h2.write_all(&inp[p..]).unwrap();
3ee932bc 361 let res = h2.finish2().unwrap();
d76f7d0b
XL
362 assert_eq!(res.to_hex(), md5_tests[i].1);
363 }
364 h1.write_all(&inp[p..]).unwrap();
3ee932bc 365 let res = h1.finish2().unwrap();
d76f7d0b
XL
366 assert_eq!(res.to_hex(), md5_tests[i].1);
367
368 println!("Clone a finished hasher");
369 let mut h3 = h1.clone();
82fc9e21
VK
370 h3.write_all(&Vec::from_hex(md5_tests[i + 1].0).unwrap())
371 .unwrap();
3ee932bc 372 let res = h3.finish2().unwrap();
d76f7d0b
XL
373 assert_eq!(res.to_hex(), md5_tests[i + 1].1);
374 }
375
376 #[test]
377 fn test_sha1() {
378 let tests = [("616263", "a9993e364706816aba3e25717850c26c9cd0d89d")];
379
380 for test in tests.iter() {
381 hash_test(MessageDigest::sha1(), test);
382 }
383 }
384
385 #[test]
386 fn test_sha256() {
82fc9e21
VK
387 let tests = [
388 (
389 "616263",
390 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
391 ),
392 ];
d76f7d0b
XL
393
394 for test in tests.iter() {
395 hash_test(MessageDigest::sha256(), test);
396 }
397 }
398
399 #[test]
400 fn test_ripemd160() {
401 let tests = [("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")];
402
403 for test in tests.iter() {
404 hash_test(MessageDigest::ripemd160(), test);
405 }
406 }
407}