2

I am attempting to implement HMAC verification using SHA256 to interact with an API. I've found the hmac and sha2 crates, and according to their examples they will work perfectly for my purposes.

I have this code:

extern crate hmac;
extern crate sha2;

use hmac::{Hmac, Mac};
use sha2::{Digest, Sha256};

pub fn verify(message: &[u8], code: &[u8], key: &[u8]) -> bool {
    type HmacSha256 = Hmac<Sha256>;

    let mut mac = HmacSha256::new_varkey(key).unwrap();
    mac.input(message);

    let result = mac.result().code();
    return result == code;
}

#[cfg(test)]
mod tests {
    use verify;
    #[test]
    fn should_work() {
        assert!(verify(
          b"code=0907a61c0c8d55e99db179b68161bc00&shop=some-shop.myshopify.com&timestamp=1337178173",
          b"4712bf92ffc2917d15a2f5a273e39f0116667419aa4b6ac0b3baaf26fa3c4d20",
          b"hush"
        ), "Returned false with correct parameters!");
    }

    #[test]
    fn shouldnt_work() {
        assert!(
            !verify(
                b"things=things&stuff=this_is_pod_racing",
                b"3b3f62798a09c78hjbjsakbycut^%9n29ddeb8f6862b42c7eb6fa65cf2a8cade",
                b"mysecu)reAn111eecretB"
            ),
            "Returned true with incorrect parameters!"
        );
    }
}

cargo test should show a valid HMAC verification, and an invalid one.

Unfortunately, the results given from the verify function disagree with the result from online HMAC generators. As an example, with the message code=0907a61c0c8d55e99db179b68161bc00&shop=some-shop.myshopify.com&timestamp=1337178173 and key hush, this online HMAC generator indicates the hash should be 4712bf92ffc2917d15a2f5a273e39f0116667419aa4b6ac0b3baaf26fa3c4d20, but this causes my tests to fail, and printing out the result confirms that the hash is not correct.

I've confirmed that the results of my byte-string literals are indeed their ASCII equivalents, and otherwise I'm performing this process almost exactly like the examples demonstrate.

I will not be using result == code in the final version due to side-channel attacks, that is just to make my debugging life a little easier.

Cargo.toml

[package]
name = "crypto"
version = "0.1.0"


[dependencies]
hmac = "0.6.2"
sha2 = "0.7.1"
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Qwertycrackers
  • 626
  • 4
  • 12

1 Answers1

4
4712bf92ffc2917d15a2f5a273e39f0116667419aa4b6ac0b3baaf26fa3c4d20

This isn't supposed to be treated as an ASCII bytestring. This is a hex-encoding of the raw bytes to an easily human-readable format. You need to properly match encodings:

extern crate hmac;
extern crate sha2;
extern crate hex;

use hmac::{Hmac, Mac};
use sha2::Sha256;

pub fn verify(message: &[u8], code: &str, key: &[u8]) -> bool {
    type HmacSha256 = Hmac<Sha256>;

    let mut mac = HmacSha256::new_varkey(key).unwrap();
    mac.input(message);

    let result = mac.result().code();

    let r2 = hex::encode(&result);

    r2 == code
}

#[test]
fn should_work() {
    assert!(verify(
        b"code=0907a61c0c8d55e99db179b68161bc00&shop=some-shop.myshopify.com&timestamp=1337178173",
        "4712bf92ffc2917d15a2f5a273e39f0116667419aa4b6ac0b3baaf26fa3c4d20",
        b"hush"
    ), "Returned false with correct parameters!");
}

#[test]
fn shouldnt_work() {
    assert!(
        !verify(
            b"things=things&stuff=this_is_pod_racing",
            "3b3f62798a09c78hjbjsakbycut^%9n29ddeb8f6862b42c7eb6fa65cf2a8cade",
            b"mysecu)reAn111eecretB"
        ),
        "Returned true with incorrect parameters!"
    );
}

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366