Output of cryptographic hashing function does not produce the same output as in python
I'm trying to get a message authentication system going on the Arduino. I've found the Arduino Cryptographic Library which seems to do what I want, except I can't get it to agree with the python hash.
I have chosen to use the Blake2s protocol. In Python it seems to be pretty straightforward:
import hashlib
message = b'This is a test'
key = b'secret'
h = hashlib.blake2s(digest_size=32, key=key)
h.update(message)
print(h.hexdigest().encode('utf-8'))
Prints b'06082b17a536da2054dd3f1f75baafd84ac8d65eba56dd6f882d723292393ffd'
.
Unfortunately the documentation of the library is spotty at best, and I have to admit I'm not following 100%. It isn't helping that I rarely program in C (I'm usually a Fortran/Python programmer). The only 'example' I could find on how to use this library is a unit test, with lots of magic numbers. But I think the meat of the HMAC process is in lines 202-207 of that file:
// Now use the library to compute the HMAC.
hash->resetHMAC(buffer, keyLen);
memset(buffer, 0xBA, sizeof(buffer));
hash->update(buffer, sizeof(buffer));
memset(buffer, (uint8_t)keyLen, keyLen);
hash->finalizeHMAC(buffer, keyLen, buffer, HASH_SIZE);
So here's what I came up with:
#include <Crypto.h>
#include <BLAKE2s.h>
#include <stdlib.h>
#define HASH_SIZE 32
#define MESSAGE "This is a test"
#define KEY "secret"
#define SIGNATURE "06082b17a536da2054dd3f1f75baafd84ac8d65eba56dd6f882d723292393ffd"
void hexstring_to_array(String value_string, uint8_t value[HASH_SIZE]){
char buf[3];
for (uint8_t i=0; i<HASH_SIZE; i++){
value_string.substring(2*i, 2*i+2).toCharArray(buf, 3);
buf[2] = '\n';
value[i] = strtoll(buf, NULL, 16);
}
}
void calculate_signature(Hash *hash, char * message, size_t message_len, char * key, size_t key_len, uint8_t sig[HASH_SIZE]){
hash -> resetHMAC(key, key_len);
hash -> update(message, message_len);
hash -> finalizeHMAC(key, key_len, sig, HASH_SIZE);
}
void setup(){
BLAKE2s blake2s;
Serial.begin(115200);
char message[] = (MESSAGE);
char key[] = (KEY);
uint8_t good_sig[HASH_SIZE];
uint8_t sig[HASH_SIZE];
hexstring_to_array(SIGNATURE, sig);
calculate_signature(&blake2s, message, sizeof(message), key, sizeof(key), good_sig);
if (memcmp(sig, good_sig, HASH_SIZE) == 0) {
Serial.println("Yes");
} else {
Serial.println("No");
}
}
I've checked the output, it's b7d9f4091c44596d5545edc79a17f6448e04d3be39d909d62e0d3dfed2fb1d94
, so clearly not the same.
I've played around with the trailing \0
character (leaving it out by reducing the length arguments, or adding it to the python script), but that didn't help.
If someone just had some pointers to more understandable resources, that would help me.
(This is a hobby. I understand that the code is crude and probably full of ugly code smell and potentially some bugs. I'm working on this in my limited spare time.)
Thank you
Thank you @dandavis, you pointed out what I was missing. My main issue was the Python part, not the Arduino code. Here is the correct python implementation:
import hmac
key = "secret"
message = "This is a test"
h = hmac.new(key=key.encode(), digestmod='blake2s')
h.update(message.encode())
print(h.hexdigest())
This prints a64f8cd3aee4b1d6a7a89eec6b60da153ba0a484656d6ffeb8a7061fe695f4ff
There was also a minor bug in the Arduino code, as @Majenko pointed out, I needed to replace the sizeof
with strlen
methods in the call to calculate_signature
. (And yes, I also replaced the '\n'
with '\0'
.)
With these changes, the Arduino code produces the same digest.