Implement std::hash::Hasher + Clone for Hmac

Change-Id: I408c3b8d60ebe18664ed14d62eaf08e2ca699257
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cf1b967..93f926e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,8 @@
   feature flag).
 - Added `bytes` module guarded by the `bytes` feature, containing
   `constant_time_eq`.
+- `hmac::Hmac` now implements `Clone` and `std::hash::Hasher`, allowing it to be
+  used with any type that implements `std::hash::Hash`.
 
 ### Changed
 - `build.rs` implements symbol name scraping natively, and no longer relies on
diff --git a/boringssl/bindgen.sh b/boringssl/bindgen.sh
index a8262b8..1ff819e 100755
--- a/boringssl/bindgen.sh
+++ b/boringssl/bindgen.sh
@@ -86,6 +86,7 @@
 EVP_PBE_scrypt|\
 HMAC_CTX_init|\
 HMAC_CTX_cleanup|\
+HMAC_CTX_copy|\
 HMAC_Init_ex|\
 HMAC_Update|\
 HMAC_Final|\
diff --git a/boringssl/boringssl.rs b/boringssl/boringssl.rs
index 5c371a1..30f904f 100644
--- a/boringssl/boringssl.rs
+++ b/boringssl/boringssl.rs
@@ -913,6 +913,10 @@
     #[link_name = "__RUST_MUNDANE_0_4_0_HMAC_size"]
     pub fn HMAC_size(ctx: *const HMAC_CTX) -> usize;
 }
+extern "C" {
+    #[link_name = "__RUST_MUNDANE_0_4_0_HMAC_CTX_copy"]
+    pub fn HMAC_CTX_copy(dest: *mut HMAC_CTX, src: *const HMAC_CTX) -> ::std::os::raw::c_int;
+}
 #[repr(C)]
 #[derive(Debug, Copy, Clone)]
 pub struct hmac_ctx_st {
diff --git a/src/boringssl/mod.rs b/src/boringssl/mod.rs
index b51a979..84f99be 100644
--- a/src/boringssl/mod.rs
+++ b/src/boringssl/mod.rs
@@ -109,9 +109,9 @@
     EC_KEY_set_group, EC_curve_nid2nist, ED25519_keypair, ED25519_keypair_from_seed, ED25519_sign,
     ED25519_verify, ERR_print_errors_cb, EVP_PBE_scrypt, EVP_PKEY_assign_EC_KEY,
     EVP_PKEY_assign_RSA, EVP_PKEY_get1_EC_KEY, EVP_PKEY_get1_RSA, EVP_marshal_public_key,
-    EVP_parse_public_key, HMAC_CTX_init, HMAC_Final, HMAC_Init_ex, HMAC_Update, HMAC_size,
-    RAND_bytes, RSA_bits, RSA_generate_key_ex, RSA_marshal_private_key, RSA_parse_private_key,
-    RSA_sign_pss_mgf1, RSA_size, RSA_verify_pss_mgf1, SHA384_Init,
+    EVP_parse_public_key, HMAC_CTX_copy, HMAC_CTX_init, HMAC_Final, HMAC_Init_ex, HMAC_Update,
+    HMAC_size, RAND_bytes, RSA_bits, RSA_generate_key_ex, RSA_marshal_private_key,
+    RSA_parse_private_key, RSA_sign_pss_mgf1, RSA_size, RSA_verify_pss_mgf1, SHA384_Init,
 };
 #[cfg(feature = "rsa-pkcs1v15")]
 use boringssl::raw::{RSA_sign, RSA_verify};
@@ -567,6 +567,15 @@
             assert_abort_eq!(out.len(), size as usize);
         }
     }
+
+    /// The `HMAC_CTX_copy` function.
+    pub fn hmac_ctx_copy(&self) -> Result<Self, BoringError> {
+        unsafe {
+            let mut ctx = MaybeUninit::uninit();
+            HMAC_CTX_copy(ctx.as_mut_ptr(), self.as_const())?;
+            Ok(CStackWrapper::new(ctx.assume_init()))
+        }
+    }
 }
 
 impl CHeapWrapper<RSA> {
diff --git a/src/boringssl/raw.rs b/src/boringssl/raw.rs
index 9ac8fd7..f98fc29 100644
--- a/src/boringssl/raw.rs
+++ b/src/boringssl/raw.rs
@@ -357,6 +357,11 @@
     one_or_err("HMAC_Final", ffi::HMAC_Final(ctx, out, out_len))
 }
 
+#[allow(non_snake_case)]
+pub unsafe fn HMAC_CTX_copy(dest: *mut HMAC_CTX, src: *const HMAC_CTX) -> Result<(), BoringError> {
+    one_or_err("HMAC_CTX_copy", ffi::HMAC_CTX_copy(dest, src))
+}
+
 // rand.h
 
 #[allow(non_snake_case)]
diff --git a/src/hmac.rs b/src/hmac.rs
index 7db7949..bd68eb0 100644
--- a/src/hmac.rs
+++ b/src/hmac.rs
@@ -48,12 +48,42 @@
     }
 }
 
+// We expose `Clone` because implementing `std::hash::Hasher` is
+// useful, and forces us to expose a `fn finish(&self)`. That exposes
+// the capacity to compute a digest based on the current state and
+// keep going, so providing no way to do that using the native API
+// serves only to force users to jump through hoops.
+impl<H: Hasher> Clone for Hmac<H> {
+    fn clone(&self) -> Self {
+        Self {
+            // Can only fail due to OOM if `self` is properly initialized
+            ctx: self.ctx.hmac_ctx_copy().unwrap(),
+            _marker: PhantomData,
+        }
+    }
+}
+
 impl<H: Hasher> Debug for Hmac<H> {
     fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
         write!(f, "Hmac")
     }
 }
 
+impl<H: Hasher> std::hash::Hasher for Hmac<H> {
+    fn write(&mut self, bytes: &[u8]) {
+        self.update(bytes);
+    }
+
+    fn finish(&self) -> u64 {
+        let digest = self.clone().finish();
+        // Translate a digest to a u64 in an arbitrary reasonable way
+        let mut buf = [0; 8];
+        let len = digest.as_ref().len().min(8);
+        buf[0..len].copy_from_slice(&digest.as_ref()[0..len]);
+        u64::from_le_bytes(buf)
+    }
+}
+
 /// HMAC-SHA256.
 pub type HmacSha256 = Hmac<Sha256>;
 /// HMAC-SHA384.
@@ -145,6 +175,7 @@
     #[allow(deprecated)]
     use hash::insecure_sha1_digest::InsecureSha1Digest;
     use hash::*;
+    use std::convert::TryInto;
 
     #[test]
     fn test_hmac() {
@@ -158,9 +189,20 @@
             sha512: <Sha512 as Hasher>::Digest,
         }
 
+        fn std_hash<H: Hasher>(x: &[u8]) -> u64 {
+            use std::hash::Hasher;
+            let mut hmac = Hmac::<H>::new(TEST_KEY);
+            hmac.write(x);
+            <Hmac<H> as std::hash::Hasher>::finish(&hmac)
+        }
+
         for case in TEST_CASES.iter() {
             fn test<H: Hasher>(input: &'static [u8], digest: &H::Digest) {
                 assert_eq!(&hmac::<H>(TEST_KEY, input), digest, "input: {:?}", input);
+                assert_eq!(
+                    std_hash::<H>(input),
+                    u64::from_le_bytes(digest.as_ref()[0..8].try_into().unwrap())
+                );
                 // Test that adding bytes incrementally works too.
                 let mut hmac = Hmac::<H>::new(TEST_KEY);
                 for b in input {