aboutsummaryrefslogtreecommitdiff
path: root/openssl/src
diff options
context:
space:
mode:
authorSteven Fackler <[email protected]>2017-04-13 19:37:11 -0700
committerGitHub <[email protected]>2017-04-13 19:37:11 -0700
commitfd6a1f70bdcb2a5baf5e307614be0730f06216f0 (patch)
treea3963c80dab09fabe5bde1cb84fad52a2e72e77d /openssl/src
parentMerge pull request #615 from ajroetker/issue-600/avoid_compiling_ec_code_agai... (diff)
parentDon't force allocation for message digests (diff)
downloadrust-openssl-fd6a1f70bdcb2a5baf5e307614be0730f06216f0.tar.xz
rust-openssl-fd6a1f70bdcb2a5baf5e307614be0730f06216f0.zip
Merge pull request #616 from sfackler/no-alloc
Don't force allocation for message digests
Diffstat (limited to 'openssl/src')
-rw-r--r--openssl/src/hash.rs104
-rw-r--r--openssl/src/pkcs5.rs4
2 files changed, 86 insertions, 22 deletions
diff --git a/openssl/src/hash.rs b/openssl/src/hash.rs
index 47d6dc7a..f08f2796 100644
--- a/openssl/src/hash.rs
+++ b/openssl/src/hash.rs
@@ -1,5 +1,7 @@
use std::io::prelude::*;
use std::io;
+use std::ops::{Deref, DerefMut};
+use std::fmt;
use ffi;
#[cfg(ossl110)]
@@ -118,7 +120,7 @@ impl Hasher {
match self.state {
Reset => return Ok(()),
Updated => {
- try!(self.finish());
+ try!(self.finish2());
}
Finalized => (),
}
@@ -141,19 +143,27 @@ impl Hasher {
Ok(())
}
- /// Returns the hash of the data written since creation or
- /// the last `finish` and resets the hasher.
+ #[deprecated(note = "use finish2 instead", since = "0.9.11")]
pub fn finish(&mut self) -> Result<Vec<u8>, ErrorStack> {
+ self.finish2().map(|b| b.to_vec())
+ }
+
+ /// Returns the hash of the data written and resets the hasher.
+ ///
+ /// Unlike `finish`, this method does not allocate.
+ pub fn finish2(&mut self) -> Result<DigestBytes, ErrorStack> {
if self.state == Finalized {
try!(self.init());
}
unsafe {
let mut len = ffi::EVP_MAX_MD_SIZE;
- let mut res = vec![0; len as usize];
- try!(cvt(ffi::EVP_DigestFinal_ex(self.ctx, res.as_mut_ptr(), &mut len)));
- res.truncate(len as usize);
+ let mut buf = [0; ffi::EVP_MAX_MD_SIZE as usize];
+ try!(cvt(ffi::EVP_DigestFinal_ex(self.ctx, buf.as_mut_ptr(), &mut len)));
self.state = Finalized;
- Ok(res)
+ Ok(DigestBytes {
+ buf: buf,
+ len: len as usize,
+ })
}
}
}
@@ -192,34 +202,88 @@ impl Drop for Hasher {
fn drop(&mut self) {
unsafe {
if self.state != Finalized {
- drop(self.finish());
+ drop(self.finish2());
}
EVP_MD_CTX_free(self.ctx);
}
}
}
-/// Computes the hash of the `data` with the hash `t`.
+/// The resulting bytes of a digest.
+///
+/// This type derefs to a byte slice - it exists to avoid allocating memory to
+/// store the digest data.
+#[derive(Copy)]
+pub struct DigestBytes {
+ buf: [u8; ffi::EVP_MAX_MD_SIZE as usize],
+ len: usize,
+}
+
+impl Clone for DigestBytes {
+ #[inline]
+ fn clone(&self) -> DigestBytes {
+ *self
+ }
+}
+
+impl Deref for DigestBytes {
+ type Target = [u8];
+
+ #[inline]
+ fn deref(&self) -> &[u8] {
+ &self.buf[..self.len]
+ }
+}
+
+impl DerefMut for DigestBytes {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut [u8] {
+ &mut self.buf[..self.len]
+ }
+}
+
+impl AsRef<[u8]> for DigestBytes {
+ #[inline]
+ fn as_ref(&self) -> &[u8] {
+ self.deref()
+ }
+}
+
+impl fmt::Debug for DigestBytes {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&**self, fmt)
+ }
+}
+
+#[deprecated(note = "use hash2 instead", since = "0.9.11")]
pub fn hash(t: MessageDigest, data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
+ hash2(t, data).map(|b| b.to_vec())
+}
+
+/// Computes the hash of the `data` with the hash `t`.
+///
+/// Unlike `hash`, this function does not allocate the return value.
+pub fn hash2(t: MessageDigest, data: &[u8]) -> Result<DigestBytes, ErrorStack> {
let mut h = try!(Hasher::new(t));
try!(h.update(data));
- h.finish()
+ h.finish2()
}
#[cfg(test)]
mod tests {
use hex::{FromHex, ToHex};
- use super::{hash, Hasher, MessageDigest};
use std::io::prelude::*;
+ use super::*;
+
fn hash_test(hashtype: MessageDigest, hashtest: &(&str, &str)) {
- let res = hash(hashtype, &Vec::from_hex(hashtest.0).unwrap()).unwrap();
+ let res = hash2(hashtype, &Vec::from_hex(hashtest.0).unwrap()).unwrap();
assert_eq!(res.to_hex(), hashtest.1);
}
fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) {
let _ = h.write_all(&Vec::from_hex(hashtest.0).unwrap()).unwrap();
- let res = h.finish().unwrap();
+ let res = h.finish2().unwrap();
assert_eq!(res.to_hex(), hashtest.1);
}
@@ -259,10 +323,10 @@ mod tests {
fn test_finish_twice() {
let mut h = Hasher::new(MessageDigest::md5()).unwrap();
h.write_all(&Vec::from_hex(md5_tests[6].0).unwrap()).unwrap();
- h.finish().unwrap();
- let res = h.finish().unwrap();
- let null = hash(MessageDigest::md5(), &[]).unwrap();
- assert_eq!(res, null);
+ h.finish2().unwrap();
+ let res = h.finish2().unwrap();
+ let null = hash2(MessageDigest::md5(), &[]).unwrap();
+ assert_eq!(&*res, &*null);
}
#[test]
@@ -280,17 +344,17 @@ mod tests {
println!("Clone an updated hasher");
let mut h2 = h1.clone();
h2.write_all(&inp[p..]).unwrap();
- let res = h2.finish().unwrap();
+ let res = h2.finish2().unwrap();
assert_eq!(res.to_hex(), md5_tests[i].1);
}
h1.write_all(&inp[p..]).unwrap();
- let res = h1.finish().unwrap();
+ let res = h1.finish2().unwrap();
assert_eq!(res.to_hex(), md5_tests[i].1);
println!("Clone a finished hasher");
let mut h3 = h1.clone();
h3.write_all(&Vec::from_hex(md5_tests[i + 1].0).unwrap()).unwrap();
- let res = h3.finish().unwrap();
+ let res = h3.finish2().unwrap();
assert_eq!(res.to_hex(), md5_tests[i + 1].1);
}
diff --git a/openssl/src/pkcs5.rs b/openssl/src/pkcs5.rs
index 439c0d19..3093bb9c 100644
--- a/openssl/src/pkcs5.rs
+++ b/openssl/src/pkcs5.rs
@@ -126,8 +126,6 @@ pub fn scrypt(pass: &[u8],
#[cfg(test)]
mod tests {
- use hex::ToHex;
-
use hash::MessageDigest;
use symm::Cipher;
@@ -241,6 +239,8 @@ mod tests {
#[test]
#[cfg(all(feature = "v110", ossl110))]
fn scrypt() {
+ use hex::ToHex;
+
let pass = "pleaseletmein";
let salt = "SodiumChloride";
let expected = "7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613\