I am trying to generate a SAS token to authenticate to Azure IoT Hub using the PubSub Client in the Tasmota framework https://tasmota.github.io/.
Following an example: https://github.com/Azure/azure-sdk-for-c/blob/master/sdk/samples/iot/aziot_esp8266/aziot_esp8266.ino, I am able to create a signature for only a 4 character secret when compared to a known good Python example. When I increase or decrease the length of the secret, the hash does not match. Any suggestion on what I am doing wrong would be great.
It looks like it is only hashing and encoding the first 4 characters (note how the C code 'mark' = 'markmark').
C Code (run on an ESP8266):
#include <bearssl\bearssl.h> // from https://github.com/arendst/Tasmota/tree/development/lib/lib_ssl
#include <base64.hpp> // from https://github.com/arendst/Tasmota/tree/development/lib/lib_ssl
const char *PSK = "MBXjqeJm6jNEGa7TvqIEkbRHbRP+U1QhXgxR1+QGoM4=";
const char *dataToSign = "mark";
br_sha256_context sha256_context;
br_hmac_key_context hmac_key_context;
br_hmac_context hmac_context;
unsigned char decodedPSK[32];
unsigned char encryptedSignature[100];
unsigned char encodedSignature[100];
// need to base64 decode the Preshared key and the length
int base64_decoded_device_length = decode_base64((unsigned char*)PSK, decodedPSK);
// create the sha256 hmac and hash the data
br_sha256_init(&sha256_context);
br_hmac_key_init(&hmac_key_context, sha256_context.vtable, decodedPSK, base64_decoded_device_length);
br_hmac_init(&hmac_context, &hmac_key_context, 32);
br_hmac_update(&hmac_context, dataToSign, sizeof(dataToSign));
br_hmac_out(&hmac_context, encryptedSignature);
// base64 decode the HMAC to a char
encode_base64(encryptedSignature, br_hmac_size(&hmac_context), encodedSignature);
printf("PSK is %s \n", PSK);
printf("decodedPSK is %s \n", decodedPSK);
printf("dataToSign is %s \n", dataToSign);
printf("encryptedSignature is %s \n", encryptedSignature);
printf("encodedSignature is %s \n", encodedSignature);
Python code:
from base64 import b64encode, b64decode
from hashlib import sha256
from urllib.parse import quote_plus, urlencode
from hmac import HMAC
PSK="MBXjqeJm6jNEGa7TvqIEkbRHbRP+U1QhXgxR1+QGoM4="
sign_key = "mark".encode('utf-8')
signature = b64encode(HMAC(b64decode(PSK), sign_key, sha256).digest())
print('PSK = ' + PSK)
print('sign_key = ' + str(sign_key))
print('signature = ' + str(signature))
If set dataToSign
to mark, the hash matches:
C output:
PSK is MBXjqeJm6jNEGa7TvqIEkbRHbRP+U1QhXgxR1+QGoM4=
ecodedPSK is 0␕��f�3D␙�Ӿ�␄��Gm␓�ST!^␌Q��␆��
dataToSign is mark
encryptedSignature is ␝�8)����jLQ��␃b!��x␞Ǿ2��1�W␗S4���?���?�␕�?
encodedSignature is Hak4Kaic0vtqTFGSlQNiIeeD6ngex74yoOExgVcXUzQ=
Python output:
C:/Python38-64/python.exe d:/Git/createsastoken/generate/test.py
PSK = MBXjqeJm6jNEGa7TvqIEkbRHbRP+U1QhXgxR1+QGoM4=
sign_key = b'mark'
signature = b'Hak4Kaic0vtqTFGSlQNiIeeD6ngex74yoOExgVcXUzQ=
If I change the dataToSign
to 'markmark', they do not match:
C Output:
PSK is MBXjqeJm6jNEGa7TvqIEkbRHbRP+U1QhXgxR1+QGoM4=
ecodedPSK is 0␕��f�3D␙�Ӿ�␄��Gm␓�ST!^␌Q��␆��
dataToSign is markmark
encryptedSignature is ␝�8)����jLQ��␃b!��x␞Ǿ2��1�W␗S4���?���?�␕�?
encodedSignature is Hak4Kaic0vtqTFGSlQNiIeeD6ngex74yoOExgVcXUzQ=
Python Output:
C:/Python38-64/python.exe d:/Git/createsastoken/generate/test.py
PSK = MBXjqeJm6jNEGa7TvqIEkbRHbRP+U1QhXgxR1+QGoM4=
sign_key = b'markmark'
signature = b'XSf//iSjx9hB6lOQe5lcYkxLGWY+g5oXM8AX0XVGIh4='
This problem also happens if I make the dataToSign
shorter, example 'joe'.
C Output:
PSK is MBXjqeJm6jNEGa7TvqIEkbRHbRP+U1QhXgxR1+QGoM4=
ecodedPSK is 0␕��f�3D␙�Ӿ�␄��Gm␓�ST!^␌Q��␆��
dataToSign is joe
encryptedSignature is ~����␕�␡
encodedSignature is fp21m4IVnH8Arfnpb1SNY3HifxunD5se9QwF/KA3z2E=
Python:
& C:/Python38-64/python.exe d:/Git/createsastoken/generate/test.py
PSK = MBXjqeJm6jNEGa7TvqIEkbRHbRP+U1QhXgxR1+QGoM4=
sign_key = b'joe'
signature = b'69FWap6f/xD4JauDwia5y9fqYdq8qnSH5F7Yo5aa4FI='
The sizeof
will always be four because it is a pointer (at least on a 32 bit system). Thus it works for 'mark' but fails for 'joe' and 'markmark'. Declare it as
Then sizeof will give you the array size but this will include the terminating zero so you will need to subtract one.