Loading openssl-sys/src/lib.rs +2 −0 Original line number Diff line number Diff line Loading @@ -370,6 +370,7 @@ extern "C" { pub fn EVP_DigestFinal_ex(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32) -> c_int; pub fn EVP_MD_CTX_create() -> *mut EVP_MD_CTX; pub fn EVP_MD_CTX_copy_ex(dst: *mut EVP_MD_CTX, src: *const EVP_MD_CTX) -> c_int; pub fn EVP_MD_CTX_destroy(ctx: *mut EVP_MD_CTX); pub fn EVP_PKEY_new() -> *mut EVP_PKEY; Loading @@ -383,6 +384,7 @@ extern "C" { pub fn HMAC_Final(ctx: *mut HMAC_CTX, output: *mut u8, len: *mut c_uint) -> c_int; pub fn HMAC_Update(ctx: *mut HMAC_CTX, input: *const u8, len: c_uint) -> c_int; pub fn HMAC_CTX_cleanup(ctx: *mut HMAC_CTX); pub fn HMAC_CTX_copy(dst: *mut HMAC_CTX, src: *const HMAC_CTX) -> c_int; pub fn PEM_read_bio_X509(bio: *mut BIO, out: *mut *mut X509, callback: Option<PasswordCallback>, Loading src/crypto/hash.rs +237 −138 Original line number Diff line number Diff line use libc::c_uint; use std::ptr; use std::old_io; use std::iter::repeat; use std::old_io::{IoError, Writer}; use ffi; /// Message digest (hash) type. #[derive(Copy)] pub enum HashType { pub enum Type { MD5, SHA1, SHA224, Loading @@ -16,219 +16,318 @@ pub enum HashType { RIPEMD160 } pub fn evpmd(t: HashType) -> (*const ffi::EVP_MD, u32) { unsafe { match t { HashType::MD5 => (ffi::EVP_md5(), 16), HashType::SHA1 => (ffi::EVP_sha1(), 20), HashType::SHA224 => (ffi::EVP_sha224(), 28), HashType::SHA256 => (ffi::EVP_sha256(), 32), HashType::SHA384 => (ffi::EVP_sha384(), 48), HashType::SHA512 => (ffi::EVP_sha512(), 64), HashType::RIPEMD160 => (ffi::EVP_ripemd160(), 20), } impl Type { /// Returns the length of the message digest. #[inline] pub fn md_len(&self) -> usize { use self::Type::*; match *self { MD5 => 16, SHA1 => 20, SHA224 => 28, SHA256 => 32, SHA384 => 48, SHA512 => 64, RIPEMD160 => 20, } } pub struct HasherContext { ptr: *mut ffi::EVP_MD_CTX /// Internal interface subject to removal. #[inline] pub fn evp_md(&self) -> *const ffi::EVP_MD { unsafe { use self::Type::*; match *self { MD5 => ffi::EVP_md5(), SHA1 => ffi::EVP_sha1(), SHA224 => ffi::EVP_sha224(), SHA256 => ffi::EVP_sha256(), SHA384 => ffi::EVP_sha384(), SHA512 => ffi::EVP_sha512(), RIPEMD160 => ffi::EVP_ripemd160(), } } } } #[derive(PartialEq, Copy)] enum State { Reset, Updated, Finalized, } use self::State::*; /// Provides message digest (hash) computation. /// /// # Examples /// /// Calculate a hash in one go. /// /// ``` /// use openssl::crypto::hash::{hash, Type}; /// let data = b"\x42\xF4\x97\xE0"; /// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2"; /// let res = hash(Type::MD5, data); /// assert_eq!(res, spec); /// ``` /// /// Use the `Writer` trait to supply the input in chunks. /// /// ``` /// use std::old_io::Writer; /// use openssl::crypto::hash::{Hasher, Type}; /// let data = [b"\x42\xF4", b"\x97\xE0"]; /// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2"; /// let mut h = Hasher::new(Type::MD5); /// h.write_all(data[0]); /// h.write_all(data[1]); /// let res = h.finish(); /// assert_eq!(res, spec); /// ``` /// /// # Warning /// /// Don't actually use MD5 and SHA-1 hashes, they're not secure anymore. /// /// Don't ever hash passwords, use `crypto::pkcs5` or bcrypt/scrypt instead. pub struct Hasher { ctx: *mut ffi::EVP_MD_CTX, md: *const ffi::EVP_MD, type_: Type, state: State, } impl HasherContext { pub fn new() -> HasherContext { impl Hasher { /// Creates a new `Hasher` with the specified hash type. pub fn new(ty: Type) -> Hasher { ffi::init(); unsafe { HasherContext { ptr: ffi::EVP_MD_CTX_create() } } } let ctx = unsafe { let r = ffi::EVP_MD_CTX_create(); assert!(!r.is_null()); r }; let md = ty.evp_md(); let mut h = Hasher { ctx: ctx, md: md, type_: ty, state: Finalized }; h.init(); h } impl Drop for HasherContext { fn drop(&mut self) { unsafe { ffi::EVP_MD_CTX_destroy(self.ptr); #[inline] fn init(&mut self) { match self.state { Reset => return, Updated => { self.finalize(); }, Finalized => (), } unsafe { let r = ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *const _); assert_eq!(r, 1); } self.state = Reset; } #[allow(dead_code)] pub struct Hasher { evp: *const ffi::EVP_MD, ctx: HasherContext, len: u32, #[inline] fn update(&mut self, data: &[u8]) { if self.state == Finalized { self.init(); } impl old_io::Writer for Hasher { fn write_all(&mut self, buf: &[u8]) -> old_io::IoResult<()> { self.update(buf); Ok(()) unsafe { let r = ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), data.len() as c_uint); assert_eq!(r, 1); } self.state = Updated; } impl Hasher { pub fn new(ht: HashType) -> Hasher { let ctx = HasherContext::new(); Hasher::with_context(ctx, ht) #[inline] fn finalize(&mut self) -> Vec<u8> { if self.state == Finalized { self.init(); } pub fn with_context(ctx: HasherContext, ht: HashType) -> Hasher { let (evp, mdlen) = evpmd(ht); let md_len = self.type_.md_len(); let mut res: Vec<u8> = repeat(0).take(md_len).collect(); unsafe { ffi::EVP_DigestInit_ex(ctx.ptr, evp, 0 as *const _); let mut len = 0; let r = ffi::EVP_DigestFinal_ex(self.ctx, res.as_mut_ptr(), &mut len); assert_eq!(len as usize, md_len); assert_eq!(r, 1); } self.state = Finalized; res } Hasher { evp: evp, ctx: ctx, len: mdlen } /// Returns the hash of the data written since creation or /// the last `finish` and resets the hasher. #[inline] pub fn finish(&mut self) -> Vec<u8> { self.finalize() } } /// Update this hasher with more input bytes pub fn update(&mut self, data: &[u8]) { unsafe { ffi::EVP_DigestUpdate(self.ctx.ptr, data.as_ptr(), data.len() as c_uint); impl Writer for Hasher { #[inline] fn write_all(&mut self, buf: &[u8]) -> Result<(), IoError> { self.update(buf); Ok(()) } } /** * Return the digest of all bytes added to this hasher since its last * initialization */ pub fn finalize(self) -> Vec<u8> { let (res, _) = self.finalize_reuse(); res impl Clone for Hasher { fn clone(&self) -> Hasher { let ctx = unsafe { let ctx = ffi::EVP_MD_CTX_create(); assert!(!ctx.is_null()); let r = ffi::EVP_MD_CTX_copy_ex(ctx, self.ctx); assert_eq!(r, 1); ctx }; Hasher { ctx: ctx, md: self.md, type_: self.type_, state: self.state } } } /** * Return the digest of all bytes added to this hasher since its last * initialization and its context for reuse */ pub fn finalize_reuse(self) -> (Vec<u8>, HasherContext) { let mut res = repeat(0u8).take(self.len as usize).collect::<Vec<_>>(); impl Drop for Hasher { fn drop(&mut self) { unsafe { ffi::EVP_DigestFinal_ex(self.ctx.ptr, res.as_mut_ptr(), ptr::null_mut()) }; (res, self.ctx) if self.state != Finalized { let mut buf: Vec<u8> = repeat(0).take(self.type_.md_len()).collect(); let mut len = 0; ffi::EVP_DigestFinal_ex(self.ctx, buf.as_mut_ptr(), &mut len); } ffi::EVP_MD_CTX_destroy(self.ctx); } } } /** * Hashes the supplied input data using hash t, returning the resulting hash * value */ pub fn hash(t: HashType, data: &[u8]) -> Vec<u8> { /// Computes the hash of the `data` with the hash `t`. pub fn hash(t: Type, data: &[u8]) -> Vec<u8> { let mut h = Hasher::new(t); h.update(data); h.finalize() let _ = h.write_all(data); h.finish() } #[cfg(test)] mod tests { use serialize::hex::{FromHex, ToHex}; use super::{hash, Hasher, Type}; use std::old_io::Writer; struct HashTest { input: Vec<u8>, expected_output: String fn hash_test(hashtype: Type, hashtest: &(&str, &str)) { let res = hash(hashtype, &*hashtest.0.from_hex().unwrap()); assert_eq!(res.to_hex(), hashtest.1); } #[allow(non_snake_case)] fn HashTest(input: &str, output: &str) -> HashTest { HashTest { input: input.from_hex().unwrap(), expected_output: output.to_string() } fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) { let _ = h.write_all(&*hashtest.0.from_hex().unwrap()); let res = h.finish(); assert_eq!(res.to_hex(), hashtest.1); } fn compare(calced_raw: Vec<u8>, hashtest: &HashTest) { let calced = calced_raw.as_slice().to_hex().to_string(); // Test vectors from http://www.nsrl.nist.gov/testdata/ #[allow(non_upper_case_globals)] const md5_tests: [(&'static str, &'static str); 13] = [ ("", "d41d8cd98f00b204e9800998ecf8427e"), ("7F", "83acb6e67e50e31db6ed341dd2de1595"), ("EC9C", "0b07f0d4ca797d8ac58874f887cb0b68"), ("FEE57A", "e0d583171eb06d56198fc0ef22173907"), ("42F497E0", "7c430f178aefdf1487fee7144e9641e2"), ("C53B777F1C", "75ef141d64cb37ec423da2d9d440c925"), ("89D5B576327B", "ebbaf15eb0ed784c6faa9dc32831bf33"), ("5D4CCE781EB190", "ce175c4b08172019f05e6b5279889f2c"), ("81901FE94932D7B9", "cd4d2f62b8cdb3a0cf968a735a239281"), ("C9FFDEE7788EFB4EC9", "e0841a231ab698db30c6c0f3f246c014"), ("66AC4B7EBA95E53DC10B", "a3b3cea71910d9af56742aa0bb2fe329"), ("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"), ("AAED18DBE8938C19ED734A8D", "6f80fb775f27e0a4ce5c2f42fc72c5f1") ]; if calced != hashtest.expected_output { println!("Test failed - {} != {}", calced, hashtest.expected_output); #[test] fn test_md5() { for test in md5_tests.iter() { hash_test(Type::MD5, test); } assert!(calced == hashtest.expected_output); } fn hash_test(hashtype: super::HashType, hashtest: &HashTest) { let calced_raw = super::hash(hashtype, hashtest.input.as_slice()); compare(calced_raw, hashtest); #[test] fn test_md5_recycle() { let mut h = Hasher::new(Type::MD5); for test in md5_tests.iter() { hash_recycle_test(&mut h, test); } fn hash_reuse_test(ctx: super::HasherContext, hashtype: super::HashType, hashtest: &HashTest) -> super::HasherContext { let mut h = super::Hasher::with_context(ctx, hashtype); h.update(hashtest.input.as_slice()); let (calced_raw, ctx) = h.finalize_reuse(); compare(calced_raw, hashtest); ctx } pub fn hash_writer(t: super::HashType, data: &[u8]) -> Vec<u8> { let mut h = super::Hasher::new(t); h.write_all(data).unwrap(); h.finalize() #[test] fn test_finish_twice() { let mut h = Hasher::new(Type::MD5); let _ = h.write_all(&*md5_tests[6].0.from_hex().unwrap()); let _ = h.finish(); let res = h.finish(); let null = hash(Type::MD5, &[]); assert_eq!(res, null); } // Test vectors from http://www.nsrl.nist.gov/testdata/ #[test] fn test_md5() { let tests = [ HashTest("", "d41d8cd98f00b204e9800998ecf8427e"), HashTest("7F", "83acb6e67e50e31db6ed341dd2de1595"), HashTest("EC9C", "0b07f0d4ca797d8ac58874f887cb0b68"), HashTest("FEE57A", "e0d583171eb06d56198fc0ef22173907"), HashTest("42F497E0", "7c430f178aefdf1487fee7144e9641e2"), HashTest("C53B777F1C", "75ef141d64cb37ec423da2d9d440c925"), HashTest("89D5B576327B", "ebbaf15eb0ed784c6faa9dc32831bf33"), HashTest("5D4CCE781EB190", "ce175c4b08172019f05e6b5279889f2c"), HashTest("81901FE94932D7B9", "cd4d2f62b8cdb3a0cf968a735a239281"), HashTest("C9FFDEE7788EFB4EC9", "e0841a231ab698db30c6c0f3f246c014"), HashTest("66AC4B7EBA95E53DC10B", "a3b3cea71910d9af56742aa0bb2fe329"), HashTest("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"), HashTest("AAED18DBE8938C19ED734A8D", "6f80fb775f27e0a4ce5c2f42fc72c5f1")]; let mut ctx = super::HasherContext::new(); for test in tests.iter() { ctx = hash_reuse_test(ctx, super::HashType::MD5, test); } fn test_clone() { let i = 7; let inp = md5_tests[i].0.from_hex().unwrap(); assert!(inp.len() > 2); let p = inp.len() / 2; let h0 = Hasher::new(Type::MD5); println!("Clone a new hasher"); let mut h1 = h0.clone(); let _ = h1.write_all(&inp[..p]); { println!("Clone an updated hasher"); let mut h2 = h1.clone(); let _ = h2.write_all(&inp[p..]); let res = h2.finish(); assert_eq!(res.to_hex(), md5_tests[i].1); } let _ = h1.write_all(&inp[p..]); let res = h1.finish(); assert_eq!(res.to_hex(), md5_tests[i].1); println!("Clone a finished hasher"); let mut h3 = h1.clone(); let _ = h3.write_all(&*md5_tests[i + 1].0.from_hex().unwrap()); let res = h3.finish(); assert_eq!(res.to_hex(), md5_tests[i + 1].1); } #[test] fn test_sha1() { let tests = [ HashTest("616263", "a9993e364706816aba3e25717850c26c9cd0d89d"), ("616263", "a9993e364706816aba3e25717850c26c9cd0d89d"), ]; for test in tests.iter() { hash_test(super::HashType::SHA1, test); hash_test(Type::SHA1, test); } } #[test] fn test_sha256() { let tests = [ HashTest("616263", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad") ("616263", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad") ]; for test in tests.iter() { hash_test(super::HashType::SHA256, test); hash_test(Type::SHA256, test); } } #[test] fn test_ripemd160() { let tests = [ HashTest("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc") ("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc") ]; for test in tests.iter() { hash_test(super::HashType::RIPEMD160, test); hash_test(Type::RIPEMD160, test); } } #[test] fn test_writer() { let tv = "rust-openssl".as_bytes(); let ht = super::HashType::RIPEMD160; assert!(hash_writer(ht, tv) == super::hash(ht, tv)); } } src/crypto/hmac.rs +260 −37 File changed.Preview size limit exceeded, changes collapsed. Show changes src/crypto/pkey.rs +5 −4 Original line number Diff line number Diff line Loading @@ -3,7 +3,8 @@ use std::iter::repeat; use std::mem; use std::ptr; use bio::{MemBio}; use crypto::hash::HashType; use crypto::hash; use crypto::hash::Type as HashType; use ffi; use ssl::error::{SslError, StreamError}; Loading Loading @@ -276,7 +277,7 @@ impl PKey { */ pub fn verify(&self, m: &[u8], s: &[u8]) -> bool { self.verify_with_hash(m, s, HashType::SHA256) } pub fn sign_with_hash(&self, s: &[u8], hash: HashType) -> Vec<u8> { pub fn sign_with_hash(&self, s: &[u8], hash: hash::Type) -> Vec<u8> { unsafe { let rsa = ffi::EVP_PKEY_get1_RSA(self.evp); let len = ffi::RSA_size(rsa); Loading @@ -300,7 +301,7 @@ impl PKey { } } pub fn verify_with_hash(&self, m: &[u8], s: &[u8], hash: HashType) -> bool { pub fn verify_with_hash(&self, m: &[u8], s: &[u8], hash: hash::Type) -> bool { unsafe { let rsa = ffi::EVP_PKEY_get1_RSA(self.evp); Loading Loading @@ -332,7 +333,7 @@ impl Drop for PKey { #[cfg(test)] mod tests { use crypto::hash::HashType::{MD5, SHA1}; use crypto::hash::Type::{MD5, SHA1}; #[test] fn test_gen_pub() { Loading src/ssl/tests.rs +1 −1 Original line number Diff line number Diff line Loading @@ -3,7 +3,7 @@ use std::old_io::net::tcp::TcpStream; use std::old_io::{Writer}; use std::thread::Thread; use crypto::hash::HashType::{SHA256}; use crypto::hash::Type::{SHA256}; use ssl::SslMethod::Sslv23; use ssl::{SslContext, SslStream, VerifyCallback}; use ssl::SslVerifyMode::SslVerifyPeer; Loading Loading
openssl-sys/src/lib.rs +2 −0 Original line number Diff line number Diff line Loading @@ -370,6 +370,7 @@ extern "C" { pub fn EVP_DigestFinal_ex(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32) -> c_int; pub fn EVP_MD_CTX_create() -> *mut EVP_MD_CTX; pub fn EVP_MD_CTX_copy_ex(dst: *mut EVP_MD_CTX, src: *const EVP_MD_CTX) -> c_int; pub fn EVP_MD_CTX_destroy(ctx: *mut EVP_MD_CTX); pub fn EVP_PKEY_new() -> *mut EVP_PKEY; Loading @@ -383,6 +384,7 @@ extern "C" { pub fn HMAC_Final(ctx: *mut HMAC_CTX, output: *mut u8, len: *mut c_uint) -> c_int; pub fn HMAC_Update(ctx: *mut HMAC_CTX, input: *const u8, len: c_uint) -> c_int; pub fn HMAC_CTX_cleanup(ctx: *mut HMAC_CTX); pub fn HMAC_CTX_copy(dst: *mut HMAC_CTX, src: *const HMAC_CTX) -> c_int; pub fn PEM_read_bio_X509(bio: *mut BIO, out: *mut *mut X509, callback: Option<PasswordCallback>, Loading
src/crypto/hash.rs +237 −138 Original line number Diff line number Diff line use libc::c_uint; use std::ptr; use std::old_io; use std::iter::repeat; use std::old_io::{IoError, Writer}; use ffi; /// Message digest (hash) type. #[derive(Copy)] pub enum HashType { pub enum Type { MD5, SHA1, SHA224, Loading @@ -16,219 +16,318 @@ pub enum HashType { RIPEMD160 } pub fn evpmd(t: HashType) -> (*const ffi::EVP_MD, u32) { unsafe { match t { HashType::MD5 => (ffi::EVP_md5(), 16), HashType::SHA1 => (ffi::EVP_sha1(), 20), HashType::SHA224 => (ffi::EVP_sha224(), 28), HashType::SHA256 => (ffi::EVP_sha256(), 32), HashType::SHA384 => (ffi::EVP_sha384(), 48), HashType::SHA512 => (ffi::EVP_sha512(), 64), HashType::RIPEMD160 => (ffi::EVP_ripemd160(), 20), } impl Type { /// Returns the length of the message digest. #[inline] pub fn md_len(&self) -> usize { use self::Type::*; match *self { MD5 => 16, SHA1 => 20, SHA224 => 28, SHA256 => 32, SHA384 => 48, SHA512 => 64, RIPEMD160 => 20, } } pub struct HasherContext { ptr: *mut ffi::EVP_MD_CTX /// Internal interface subject to removal. #[inline] pub fn evp_md(&self) -> *const ffi::EVP_MD { unsafe { use self::Type::*; match *self { MD5 => ffi::EVP_md5(), SHA1 => ffi::EVP_sha1(), SHA224 => ffi::EVP_sha224(), SHA256 => ffi::EVP_sha256(), SHA384 => ffi::EVP_sha384(), SHA512 => ffi::EVP_sha512(), RIPEMD160 => ffi::EVP_ripemd160(), } } } } #[derive(PartialEq, Copy)] enum State { Reset, Updated, Finalized, } use self::State::*; /// Provides message digest (hash) computation. /// /// # Examples /// /// Calculate a hash in one go. /// /// ``` /// use openssl::crypto::hash::{hash, Type}; /// let data = b"\x42\xF4\x97\xE0"; /// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2"; /// let res = hash(Type::MD5, data); /// assert_eq!(res, spec); /// ``` /// /// Use the `Writer` trait to supply the input in chunks. /// /// ``` /// use std::old_io::Writer; /// use openssl::crypto::hash::{Hasher, Type}; /// let data = [b"\x42\xF4", b"\x97\xE0"]; /// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2"; /// let mut h = Hasher::new(Type::MD5); /// h.write_all(data[0]); /// h.write_all(data[1]); /// let res = h.finish(); /// assert_eq!(res, spec); /// ``` /// /// # Warning /// /// Don't actually use MD5 and SHA-1 hashes, they're not secure anymore. /// /// Don't ever hash passwords, use `crypto::pkcs5` or bcrypt/scrypt instead. pub struct Hasher { ctx: *mut ffi::EVP_MD_CTX, md: *const ffi::EVP_MD, type_: Type, state: State, } impl HasherContext { pub fn new() -> HasherContext { impl Hasher { /// Creates a new `Hasher` with the specified hash type. pub fn new(ty: Type) -> Hasher { ffi::init(); unsafe { HasherContext { ptr: ffi::EVP_MD_CTX_create() } } } let ctx = unsafe { let r = ffi::EVP_MD_CTX_create(); assert!(!r.is_null()); r }; let md = ty.evp_md(); let mut h = Hasher { ctx: ctx, md: md, type_: ty, state: Finalized }; h.init(); h } impl Drop for HasherContext { fn drop(&mut self) { unsafe { ffi::EVP_MD_CTX_destroy(self.ptr); #[inline] fn init(&mut self) { match self.state { Reset => return, Updated => { self.finalize(); }, Finalized => (), } unsafe { let r = ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *const _); assert_eq!(r, 1); } self.state = Reset; } #[allow(dead_code)] pub struct Hasher { evp: *const ffi::EVP_MD, ctx: HasherContext, len: u32, #[inline] fn update(&mut self, data: &[u8]) { if self.state == Finalized { self.init(); } impl old_io::Writer for Hasher { fn write_all(&mut self, buf: &[u8]) -> old_io::IoResult<()> { self.update(buf); Ok(()) unsafe { let r = ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), data.len() as c_uint); assert_eq!(r, 1); } self.state = Updated; } impl Hasher { pub fn new(ht: HashType) -> Hasher { let ctx = HasherContext::new(); Hasher::with_context(ctx, ht) #[inline] fn finalize(&mut self) -> Vec<u8> { if self.state == Finalized { self.init(); } pub fn with_context(ctx: HasherContext, ht: HashType) -> Hasher { let (evp, mdlen) = evpmd(ht); let md_len = self.type_.md_len(); let mut res: Vec<u8> = repeat(0).take(md_len).collect(); unsafe { ffi::EVP_DigestInit_ex(ctx.ptr, evp, 0 as *const _); let mut len = 0; let r = ffi::EVP_DigestFinal_ex(self.ctx, res.as_mut_ptr(), &mut len); assert_eq!(len as usize, md_len); assert_eq!(r, 1); } self.state = Finalized; res } Hasher { evp: evp, ctx: ctx, len: mdlen } /// Returns the hash of the data written since creation or /// the last `finish` and resets the hasher. #[inline] pub fn finish(&mut self) -> Vec<u8> { self.finalize() } } /// Update this hasher with more input bytes pub fn update(&mut self, data: &[u8]) { unsafe { ffi::EVP_DigestUpdate(self.ctx.ptr, data.as_ptr(), data.len() as c_uint); impl Writer for Hasher { #[inline] fn write_all(&mut self, buf: &[u8]) -> Result<(), IoError> { self.update(buf); Ok(()) } } /** * Return the digest of all bytes added to this hasher since its last * initialization */ pub fn finalize(self) -> Vec<u8> { let (res, _) = self.finalize_reuse(); res impl Clone for Hasher { fn clone(&self) -> Hasher { let ctx = unsafe { let ctx = ffi::EVP_MD_CTX_create(); assert!(!ctx.is_null()); let r = ffi::EVP_MD_CTX_copy_ex(ctx, self.ctx); assert_eq!(r, 1); ctx }; Hasher { ctx: ctx, md: self.md, type_: self.type_, state: self.state } } } /** * Return the digest of all bytes added to this hasher since its last * initialization and its context for reuse */ pub fn finalize_reuse(self) -> (Vec<u8>, HasherContext) { let mut res = repeat(0u8).take(self.len as usize).collect::<Vec<_>>(); impl Drop for Hasher { fn drop(&mut self) { unsafe { ffi::EVP_DigestFinal_ex(self.ctx.ptr, res.as_mut_ptr(), ptr::null_mut()) }; (res, self.ctx) if self.state != Finalized { let mut buf: Vec<u8> = repeat(0).take(self.type_.md_len()).collect(); let mut len = 0; ffi::EVP_DigestFinal_ex(self.ctx, buf.as_mut_ptr(), &mut len); } ffi::EVP_MD_CTX_destroy(self.ctx); } } } /** * Hashes the supplied input data using hash t, returning the resulting hash * value */ pub fn hash(t: HashType, data: &[u8]) -> Vec<u8> { /// Computes the hash of the `data` with the hash `t`. pub fn hash(t: Type, data: &[u8]) -> Vec<u8> { let mut h = Hasher::new(t); h.update(data); h.finalize() let _ = h.write_all(data); h.finish() } #[cfg(test)] mod tests { use serialize::hex::{FromHex, ToHex}; use super::{hash, Hasher, Type}; use std::old_io::Writer; struct HashTest { input: Vec<u8>, expected_output: String fn hash_test(hashtype: Type, hashtest: &(&str, &str)) { let res = hash(hashtype, &*hashtest.0.from_hex().unwrap()); assert_eq!(res.to_hex(), hashtest.1); } #[allow(non_snake_case)] fn HashTest(input: &str, output: &str) -> HashTest { HashTest { input: input.from_hex().unwrap(), expected_output: output.to_string() } fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) { let _ = h.write_all(&*hashtest.0.from_hex().unwrap()); let res = h.finish(); assert_eq!(res.to_hex(), hashtest.1); } fn compare(calced_raw: Vec<u8>, hashtest: &HashTest) { let calced = calced_raw.as_slice().to_hex().to_string(); // Test vectors from http://www.nsrl.nist.gov/testdata/ #[allow(non_upper_case_globals)] const md5_tests: [(&'static str, &'static str); 13] = [ ("", "d41d8cd98f00b204e9800998ecf8427e"), ("7F", "83acb6e67e50e31db6ed341dd2de1595"), ("EC9C", "0b07f0d4ca797d8ac58874f887cb0b68"), ("FEE57A", "e0d583171eb06d56198fc0ef22173907"), ("42F497E0", "7c430f178aefdf1487fee7144e9641e2"), ("C53B777F1C", "75ef141d64cb37ec423da2d9d440c925"), ("89D5B576327B", "ebbaf15eb0ed784c6faa9dc32831bf33"), ("5D4CCE781EB190", "ce175c4b08172019f05e6b5279889f2c"), ("81901FE94932D7B9", "cd4d2f62b8cdb3a0cf968a735a239281"), ("C9FFDEE7788EFB4EC9", "e0841a231ab698db30c6c0f3f246c014"), ("66AC4B7EBA95E53DC10B", "a3b3cea71910d9af56742aa0bb2fe329"), ("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"), ("AAED18DBE8938C19ED734A8D", "6f80fb775f27e0a4ce5c2f42fc72c5f1") ]; if calced != hashtest.expected_output { println!("Test failed - {} != {}", calced, hashtest.expected_output); #[test] fn test_md5() { for test in md5_tests.iter() { hash_test(Type::MD5, test); } assert!(calced == hashtest.expected_output); } fn hash_test(hashtype: super::HashType, hashtest: &HashTest) { let calced_raw = super::hash(hashtype, hashtest.input.as_slice()); compare(calced_raw, hashtest); #[test] fn test_md5_recycle() { let mut h = Hasher::new(Type::MD5); for test in md5_tests.iter() { hash_recycle_test(&mut h, test); } fn hash_reuse_test(ctx: super::HasherContext, hashtype: super::HashType, hashtest: &HashTest) -> super::HasherContext { let mut h = super::Hasher::with_context(ctx, hashtype); h.update(hashtest.input.as_slice()); let (calced_raw, ctx) = h.finalize_reuse(); compare(calced_raw, hashtest); ctx } pub fn hash_writer(t: super::HashType, data: &[u8]) -> Vec<u8> { let mut h = super::Hasher::new(t); h.write_all(data).unwrap(); h.finalize() #[test] fn test_finish_twice() { let mut h = Hasher::new(Type::MD5); let _ = h.write_all(&*md5_tests[6].0.from_hex().unwrap()); let _ = h.finish(); let res = h.finish(); let null = hash(Type::MD5, &[]); assert_eq!(res, null); } // Test vectors from http://www.nsrl.nist.gov/testdata/ #[test] fn test_md5() { let tests = [ HashTest("", "d41d8cd98f00b204e9800998ecf8427e"), HashTest("7F", "83acb6e67e50e31db6ed341dd2de1595"), HashTest("EC9C", "0b07f0d4ca797d8ac58874f887cb0b68"), HashTest("FEE57A", "e0d583171eb06d56198fc0ef22173907"), HashTest("42F497E0", "7c430f178aefdf1487fee7144e9641e2"), HashTest("C53B777F1C", "75ef141d64cb37ec423da2d9d440c925"), HashTest("89D5B576327B", "ebbaf15eb0ed784c6faa9dc32831bf33"), HashTest("5D4CCE781EB190", "ce175c4b08172019f05e6b5279889f2c"), HashTest("81901FE94932D7B9", "cd4d2f62b8cdb3a0cf968a735a239281"), HashTest("C9FFDEE7788EFB4EC9", "e0841a231ab698db30c6c0f3f246c014"), HashTest("66AC4B7EBA95E53DC10B", "a3b3cea71910d9af56742aa0bb2fe329"), HashTest("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"), HashTest("AAED18DBE8938C19ED734A8D", "6f80fb775f27e0a4ce5c2f42fc72c5f1")]; let mut ctx = super::HasherContext::new(); for test in tests.iter() { ctx = hash_reuse_test(ctx, super::HashType::MD5, test); } fn test_clone() { let i = 7; let inp = md5_tests[i].0.from_hex().unwrap(); assert!(inp.len() > 2); let p = inp.len() / 2; let h0 = Hasher::new(Type::MD5); println!("Clone a new hasher"); let mut h1 = h0.clone(); let _ = h1.write_all(&inp[..p]); { println!("Clone an updated hasher"); let mut h2 = h1.clone(); let _ = h2.write_all(&inp[p..]); let res = h2.finish(); assert_eq!(res.to_hex(), md5_tests[i].1); } let _ = h1.write_all(&inp[p..]); let res = h1.finish(); assert_eq!(res.to_hex(), md5_tests[i].1); println!("Clone a finished hasher"); let mut h3 = h1.clone(); let _ = h3.write_all(&*md5_tests[i + 1].0.from_hex().unwrap()); let res = h3.finish(); assert_eq!(res.to_hex(), md5_tests[i + 1].1); } #[test] fn test_sha1() { let tests = [ HashTest("616263", "a9993e364706816aba3e25717850c26c9cd0d89d"), ("616263", "a9993e364706816aba3e25717850c26c9cd0d89d"), ]; for test in tests.iter() { hash_test(super::HashType::SHA1, test); hash_test(Type::SHA1, test); } } #[test] fn test_sha256() { let tests = [ HashTest("616263", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad") ("616263", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad") ]; for test in tests.iter() { hash_test(super::HashType::SHA256, test); hash_test(Type::SHA256, test); } } #[test] fn test_ripemd160() { let tests = [ HashTest("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc") ("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc") ]; for test in tests.iter() { hash_test(super::HashType::RIPEMD160, test); hash_test(Type::RIPEMD160, test); } } #[test] fn test_writer() { let tv = "rust-openssl".as_bytes(); let ht = super::HashType::RIPEMD160; assert!(hash_writer(ht, tv) == super::hash(ht, tv)); } }
src/crypto/hmac.rs +260 −37 File changed.Preview size limit exceeded, changes collapsed. Show changes
src/crypto/pkey.rs +5 −4 Original line number Diff line number Diff line Loading @@ -3,7 +3,8 @@ use std::iter::repeat; use std::mem; use std::ptr; use bio::{MemBio}; use crypto::hash::HashType; use crypto::hash; use crypto::hash::Type as HashType; use ffi; use ssl::error::{SslError, StreamError}; Loading Loading @@ -276,7 +277,7 @@ impl PKey { */ pub fn verify(&self, m: &[u8], s: &[u8]) -> bool { self.verify_with_hash(m, s, HashType::SHA256) } pub fn sign_with_hash(&self, s: &[u8], hash: HashType) -> Vec<u8> { pub fn sign_with_hash(&self, s: &[u8], hash: hash::Type) -> Vec<u8> { unsafe { let rsa = ffi::EVP_PKEY_get1_RSA(self.evp); let len = ffi::RSA_size(rsa); Loading @@ -300,7 +301,7 @@ impl PKey { } } pub fn verify_with_hash(&self, m: &[u8], s: &[u8], hash: HashType) -> bool { pub fn verify_with_hash(&self, m: &[u8], s: &[u8], hash: hash::Type) -> bool { unsafe { let rsa = ffi::EVP_PKEY_get1_RSA(self.evp); Loading Loading @@ -332,7 +333,7 @@ impl Drop for PKey { #[cfg(test)] mod tests { use crypto::hash::HashType::{MD5, SHA1}; use crypto::hash::Type::{MD5, SHA1}; #[test] fn test_gen_pub() { Loading
src/ssl/tests.rs +1 −1 Original line number Diff line number Diff line Loading @@ -3,7 +3,7 @@ use std::old_io::net::tcp::TcpStream; use std::old_io::{Writer}; use std::thread::Thread; use crypto::hash::HashType::{SHA256}; use crypto::hash::Type::{SHA256}; use ssl::SslMethod::Sslv23; use ssl::{SslContext, SslStream, VerifyCallback}; use ssl::SslVerifyMode::SslVerifyPeer; Loading