HMAC-SHA1 in Rust
Asked Answered
W

2

10

I'm trying to apply HMAC-SHA1 in order to check some content but I'm unable to make it work.

These are the tests I have:

#[cfg(test)]
mod tests {

    use crypto::hmac::Hmac;
    use crypto::mac::Mac;

    use crypto::sha1::Sha1;
    use std::str::from_utf8;

    const BODY_CONTENT: &'static str = r#"bodystring"#;
    const KEY: &[u8] = b"secret_key";
    const COMPUTED_HMAC: &'static str = "97049623b0e5d20bf6beb5313d80600e3d6abe56";

    #[test]
    fn test_hmac_sha1() {
        let mut mac= Hmac::new(Sha1::new(), KEY);
        mac.input(BODY_CONTENT.as_bytes());
        let result = mac.result();
        let code = result.code();
        assert_eq!(COMPUTED_HMAC.as_bytes(), code);
        assert_eq!(COMPUTED_HMAC, from_utf8(&code).unwrap_or("failed"));
    }

    #[test]
    fn test_hmac_sha1_direct() {
        let hash = hmacsha1::hmac_sha1(KEY, BODY_CONTENT.as_bytes());
        assert_eq!(COMPUTED_HMAC.as_bytes(), hash);
        assert_eq!(COMPUTED_HMAC, from_utf8(&hash).unwrap_or("failed"));
    }
}

I've used this website in order to get the COMPUTED_HMAC by using one string (BODY_CONTENT) and a secret key (KEY).

As you can see, I'm trying to leverage both rust-crypto and hmac-sha1 crates and I obtain the same result with both of them.

The thing is that this result doesn't match with what I get in the website (97049623b0e5d20bf6beb5313d80600e3d6abe56) and the tests fail. You may think that the website is wrong but that's not the case as I'm using it to validate some other hashes generated by Github (I'm working in a Github App) and it works.

Then, obviously, I'm missing some step here but I'm unable to figure it out and I would really appreciate your help.

Woodworker answered 10/2, 2019 at 18:23 Comment(0)
D
8

The correct hash is returned, it's just not in the representation you expected. The hash is returned as raw bytes, not as bytes converted to ASCII hexadecimal digits.

If we print the hash code array as hex, like this:

println!("{:02x?}", code);

then we can see that it matches your string:

[97, 04, 96, 23, b0, e5, d2, 0b, f6, be, b5, 31, 3d, 80, 60, 0e, 3d, 6a, be, 56]
// 97049623b0e5d20bf6beb5313d80600e3d6abe56

whereas the string "97049623b0e5d20bf6beb5313d80600e3d6abe56" looks like this:

[39, 37, 30, 34, 39, 36, 32, 33, 62, 30, 65, 35, 64, 32, 30, 62, 66, 36, 62, 65,
 62, 35, 33, 31, 33, 64, 38, 30, 36, 30, 30, 65, 33, 64, 36, 61, 62, 65, 35, 36]

Using itertools, we can convert the former to the latter like this:

assert_eq!(
    COMPUTED_HMAC,
    code.iter().format_with("", |byte, f| f(&format_args!("{:02x}", byte))).to_string());
Dulciedulcify answered 10/2, 2019 at 18:41 Comment(1)
Thanks for your answer! I was going in circles. Finally just enconding the resulting hash to hexadecimal as you suggested worked perfectly. I used base16 to encode it.Woodworker
P
0

Thanks Francis and Robert, this code works for me.

code.iter().map(|b| format!("{:02x}", b)).collect::<Vec<_>>().join("")

That line returns: "97049623b0e5d20bf6beb5313d80600e3d6abe56" as String

Phenetidine answered 12/2, 2022 at 1:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.