问题描述
我正在尝试使用 Tasmota 框架 https://tasmota.github.io/ 中的 PubSub 客户端生成 SAS 令牌以对 Azure IoT 中心进行身份验证。
以下示例:https://github.com/Azure/azure-sdk-for-c/blob/master/sdk/samples/iot/aziot_esp8266/aziot_esp8266.ino,与已知的优秀 Python 示例相比,我只能为 4 个字符的秘密创建签名。当我增加或减少秘密的长度时,散列不匹配。任何关于我做错了什么的建议都会很棒。
看起来它只是对前 4 个字符进行了散列和编码(注意 C 代码如何使用 'mark' = 'markmark')。
C 代码(在 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 代码:
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))
如果将 dataToSign
设置为标记,则哈希匹配:
C 输出:
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 输出:
C:/python38-64/python.exe d:/Git/createsastoken/generate/test.py
PSK = MBXjqeJm6jNEGa7TvqIEkbRHbRP+U1QhXgxR1+QGoM4=
sign_key = b'mark'
signature = b'Hak4Kaic0vtqTFGSlQNiIeeD6ngex74yoOExgVcXUzQ=
如果我将 dataToSign
更改为 'markmark',它们不匹配:
C 输出:
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 输出:
C:/python38-64/python.exe d:/Git/createsastoken/generate/test.py
PSK = MBXjqeJm6jNEGa7TvqIEkbRHbRP+U1QhXgxR1+QGoM4=
sign_key = b'markmark'
signature = b'XSf//iSJx9hB6lOQe5lcYkxLGWY+g5oXM8AX0XVGIh4='
如果我将 dataToSign
缩短,例如“joe”,也会出现此问题。
C 输出:
PSK is MBXjqeJm6jNEGa7TvqIEkbRHbRP+U1QhXgxR1+QGoM4=
ecodedPSK is 0␕��f�3D␙�Ӿ�␄��Gm␓�ST!^␌Q��␆��
dataToSign is joe
encryptedSignature is ~����␕�␡
encodedSignature is fp21m4IVnH8Arfnpb1SNY3HifxunD5se9QwF/KA3z2E=
蟒蛇:
& C:/python38-64/python.exe d:/Git/createsastoken/generate/test.py
PSK = MBXjqeJm6jNEGa7TvqIEkbRHbRP+U1QhXgxR1+QGoM4=
sign_key = b'joe'
signature = b'69FWap6f/xD4JauDwia5y9fqYdq8qnSH5F7Yo5aa4FI='
解决方法
尺寸
const char *dataToSign = "mark";
将始终为 4,因为它是一个指针(至少在 32 位系统上)。因此它对“mark”有效,但对“joe”和“markmark”无效。 声明为
const char dataToSign[] = "whatever...";
然后 sizeof 将为您提供数组大小,但这将包括终止零,因此您需要减去一。