aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGleb Kozyrev <[email protected]>2014-11-20 07:06:59 +0200
committerGleb Kozyrev <[email protected]>2014-11-26 21:38:06 +0200
commit5fafe4fc60848d525e3edb37266bc0f762cb7963 (patch)
tree8f85a76fb624b873506265382b4bcf4a7e67c5a1 /src
parentBump to 0.1.1 (diff)
downloadrust-openssl-5fafe4fc60848d525e3edb37266bc0f762cb7963.tar.xz
rust-openssl-5fafe4fc60848d525e3edb37266bc0f762cb7963.zip
Hasher: static contract checking, context reuse
- Store EVP_MD_CTX in a separate struct. - Add with_context() constructor that uses an existing context. - Switch to EVP_Digest(Init|Final)_ex for efficient context reuse. - Make update() borrow &mut self. - Make finalize() consume self. Add finalize_reuse() that also returns the context which can be passed to from_context() constructor for reuse. These changes let the type system prevent illegal calls to update() and finalize().
Diffstat (limited to 'src')
-rw-r--r--src/crypto/hash.rs85
1 files changed, 63 insertions, 22 deletions
diff --git a/src/crypto/hash.rs b/src/crypto/hash.rs
index 1587e55d..b5d0eab5 100644
--- a/src/crypto/hash.rs
+++ b/src/crypto/hash.rs
@@ -28,10 +28,32 @@ pub fn evpmd(t: HashType) -> (*const ffi::EVP_MD, uint) {
}
}
+pub struct HasherContext {
+ ptr: *mut ffi::EVP_MD_CTX
+}
+
+impl HasherContext {
+ pub fn new() -> HasherContext {
+ ffi::init();
+
+ unsafe {
+ HasherContext { ptr: ffi::EVP_MD_CTX_create() }
+ }
+ }
+}
+
+impl Drop for HasherContext {
+ fn drop(&mut self) {
+ unsafe {
+ ffi::EVP_MD_CTX_destroy(self.ptr);
+ }
+ }
+}
+
#[allow(dead_code)]
pub struct Hasher {
evp: *const ffi::EVP_MD,
- ctx: *mut ffi::EVP_MD_CTX,
+ ctx: HasherContext,
len: uint,
}
@@ -44,21 +66,23 @@ impl io::Writer for Hasher {
impl Hasher {
pub fn new(ht: HashType) -> Hasher {
- ffi::init();
+ let ctx = HasherContext::new();
+ Hasher::with_context(ctx, ht)
+ }
- let ctx = unsafe { ffi::EVP_MD_CTX_create() };
+ pub fn with_context(ctx: HasherContext, ht: HashType) -> Hasher {
let (evp, mdlen) = evpmd(ht);
unsafe {
- ffi::EVP_DigestInit(ctx, evp);
+ ffi::EVP_DigestInit_ex(ctx.ptr, evp, 0 as *const _);
}
Hasher { evp: evp, ctx: ctx, len: mdlen }
}
/// Update this hasher with more input bytes
- pub fn update(&self, data: &[u8]) {
+ pub fn update(&mut self, data: &[u8]) {
unsafe {
- ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), data.len() as c_uint)
+ ffi::EVP_DigestUpdate(self.ctx.ptr, data.as_ptr(), data.len() as c_uint)
}
}
@@ -66,20 +90,21 @@ impl Hasher {
* Return the digest of all bytes added to this hasher since its last
* initialization
*/
- pub fn finalize(&self) -> Vec<u8> {
- unsafe {
- let mut res = Vec::from_elem(self.len, 0u8);
- ffi::EVP_DigestFinal(self.ctx, res.as_mut_ptr(), ptr::null_mut());
- res
- }
+ pub fn finalize(self) -> Vec<u8> {
+ let (res, _) = self.finalize_reuse();
+ res
}
-}
-impl Drop for Hasher {
- fn drop(&mut self) {
+ /**
+ * 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 = Vec::from_elem(self.len, 0u8);
unsafe {
- ffi::EVP_MD_CTX_destroy(self.ctx);
- }
+ ffi::EVP_DigestFinal_ex(self.ctx.ptr, res.as_mut_ptr(), ptr::null_mut())
+ };
+ (res, self.ctx)
}
}
@@ -88,7 +113,7 @@ impl Drop for Hasher {
* value
*/
pub fn hash(t: HashType, data: &[u8]) -> Vec<u8> {
- let h = Hasher::new(t);
+ let mut h = Hasher::new(t);
h.update(data);
h.finalize()
}
@@ -108,9 +133,7 @@ mod tests {
expected_output: output.to_string() }
}
- fn hash_test(hashtype: super::HashType, hashtest: &HashTest) {
- let calced_raw = super::hash(hashtype, hashtest.input.as_slice());
-
+ fn compare(calced_raw: Vec<u8>, hashtest: &HashTest) {
let calced = calced_raw.as_slice().to_hex().into_string();
if calced != hashtest.expected_output {
@@ -120,6 +143,22 @@ mod tests {
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);
+ }
+
+ 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(data).unwrap();
@@ -144,8 +183,10 @@ mod tests {
HashTest("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"),
HashTest("AAED18DBE8938C19ED734A8D", "6f80fb775f27e0a4ce5c2f42fc72c5f1")];
+ let mut ctx = super::HasherContext::new();
+
for test in tests.iter() {
- hash_test(super::HashType::MD5, test);
+ ctx = hash_reuse_test(ctx, super::HashType::MD5, test);
}
}