当从 AsyncUDP onPacket 回调中使用 libsodium 解密时触发 ESP32 Stack canary 观察点
ESP32 Stack canary watchpoint triggered when decrypting with libsodium from an AsyncUDP onPacket Callback
从 AsyncUDP onPacket 回调调用解密例程时,我收到“堆栈金丝雀观察点已触发”。未从回调中调用的相同数据的测试解密工作正常。非常感谢任何有关如何解决此问题的帮助。
修剪代码
#define CRYPTO_SALT_BYTES 16
#define CRYPTO_ARGON_OUT_SIZE 32
// Code based on
//https://www.doorbird.com/downloads/api_lan.pdf?rev=0.28
//https://github.com/tsearle/doorbird/blob/master/doorbird.c
AsyncUDP udp1;
AsyncUDP udp2;
typedef struct {
unsigned char id[3];
unsigned char version;
uint32_t opslimit;
uint32_t memlimit;
unsigned char salt[16];
unsigned char nonce[8];
unsigned char ciphertext[34];
}__attribute__((packed)) NotifyBroadcast;
typedef struct {
char intercom_id[6];
char event [8];
unsigned timestamp;
} __attribute__((packed)) NotifyBroadcastCiphertext;
char * dbuser = "yourUserHere";
char * dbpassword = "yourPWHere";
unsigned int timestamp;
unsigned char* stretchPasswordArgon(const char *password, unsigned char *salt, unsigned *oplimit, unsigned *memlimit) {
if (sodium_is_zero(salt, CRYPTO_SALT_BYTES) ) {
randombytes_buf(salt, CRYPTO_SALT_BYTES);
return NULL;
}
unsigned char* key = (unsigned char *)malloc(CRYPTO_ARGON_OUT_SIZE);
if (!*oplimit)
*oplimit = crypto_pwhash_argon2i_OPSLIMIT_INTERACTIVE;
if (!*memlimit)
*memlimit = crypto_pwhash_MEMLIMIT_MIN;
if (crypto_pwhash(key, CRYPTO_ARGON_OUT_SIZE, password, strlen(password), salt, *oplimit, *memlimit, crypto_pwhash_ALG_ARGON2I13)) {
Serial.println("Argon2 Failed");
*oplimit = 0;
*memlimit = 0;
free(key);
return NULL;
}
return key;
}
NotifyBroadcastCiphertext decryptBroadcastNotification(const NotifyBroadcast * notification, const unsigned char* password) {
NotifyBroadcastCiphertext decrypted = {{0},{0},0};
int res = 0;
if(res = crypto_aead_chacha20poly1305_decrypt((unsigned char*)&decrypted, NULL, NULL, notification->ciphertext, sizeof(notification->ciphertext), NULL, 0, notification->nonce, password))
Serial.printf("crypto_aead_chacha20poly1305_decrypt() failed %d\n", res);
return decrypted;
}
NotifyBroadcastCiphertext decode_packet(unsigned char * packet, int size, char * password) {
char truncatedPassword[6];
NotifyBroadcast * pkt = (NotifyBroadcast*)packet;
NotifyBroadcastCiphertext decrypted = {{0},{0},0};
if (size != 70 || pkt->id[0] != 0xDE || pkt->id[1] != 0xAD || pkt->id[2] != 0xBE) {
return decrypted;
strncpy(truncatedPassword, password, 5);
truncatedPassword[5] = 0;
unsigned opslimit = ntohl(pkt->opslimit);
unsigned memlimit = ntohl(pkt->memlimit);
unsigned char* stretchPass = stretchPasswordArgon(truncatedPassword, pkt->salt, &opslimit, &memlimit);
if (stretchPass == NULL)
Serial.println("Error making stretchpass!\n");
decrypted = decryptBroadcastNotification(pkt, stretchPass);
free(stretchPass);
return decrypted;
}
void handle_event(char * event_str) {
Serial.printf("Got an event: '%s'\n", event_str);
}
void processPacket(AsyncUDPPacket packet) {
char intercom_id[10];
char event_str[10];
unsigned char* pk = (unsigned char*) malloc(packet.length() + 1);
memcpy(pk, packet.data(), packet.length());
NotifyBroadcastCiphertext event = decode_packet(pk, packet.length(), dbpassword);
free(pk);
if(event.timestamp == 0)
return;
strncpy(intercom_id, event.intercom_id, 6);
intercom_id[6] = 0;
strncpy(event_str, event.event, 8);
event_str[8] = 0;
if(strncmp(dbuser,intercom_id,6) != 0)
return;
if(timestamp == event.timestamp)
return;
timestamp = event.timestamp;
handle_event(event_str);
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" CONNECTED");
if (udp1.listen(6524))
{
udp1.onPacket([](AsyncUDPPacket packet) {
processPacket(packet);
});
}
if (udp2.listen(35344))
{
udp2.onPacket([](AsyncUDPPacket packet) {
processPacket(packet);
});
}
}
解码异常如下。
PC: 0x4010da59: blake2b_compress_ref at
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_generichash/blake2b/ref/blake2b-compress-ref.c
line 73 EXCVADDR: 0x00000000
Decoding stack results 0x4010da56: blake2b_compress_ref at
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_generichash/blake2b/ref/blake2b-compress-ref.c
line 73 0x4010caa4: crypto_generichash_blake2b__final at
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_generichash/blake2b/ref/blake2b-ref.c
line 314 0x4010cd69: crypto_generichash_blake2b__blake2b at
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_generichash/blake2b/ref/blake2b-ref.c
line 367 0x40107395: crypto_generichash_blake2b at
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_generichash/blake2b/ref/generichash_blake2b.c
line 23 0x4010b039: blake2b_long at
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_pwhash/argon2/blake2b-long.c
line 61 0x40108216: fill_first_blocks at
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_pwhash/argon2/argon2-core.c
line 378 0x40108311: initialize at
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_pwhash/argon2/argon2-core.c
line 509 0x4010d051: argon2_ctx at
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_pwhash/argon2/argon2.c
line 68 0x4010d0d2: argon2_hash at
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_pwhash/argon2/argon2.c
line 129 0x4010d172: argon2i_hash_raw at
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_pwhash/argon2/argon2.c
line 175 0x4010b165: crypto_pwhash_argon2i at
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_pwhash/argon2/pwhash_argon2i.c
line 168 0x4010725e: crypto_pwhash at
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_pwhash/crypto_pwhash.c
line 136 0x400d2424: stretchPasswordArgon(char const*, unsigned char*,
unsigned int*, unsigned int*) at
D:\Code\ArduinoWorkspace\dbesp32/dbesp32.ino line 66 0x400d2582:
decode_packet(unsigned char*, int, char*) at
D:\Code\ArduinoWorkspace\dbesp32/dbesp32.ino line 118 0x400d26b6:
processPacket(AsyncUDPPacket) at
D:\Code\ArduinoWorkspace\dbesp32/dbesp32.ino line 158 0x400d283a:
std::_Function_handler >::_M_invoke(const std::_Any_data &,
AsyncUDPPacket &) at D:\Code\ArduinoWorkspace\dbesp32/dbesp32.ino line
195 0x400d40f1: AsyncUDP::_recv(udp_pcb*, pbuf*, ip_addr const*,
unsigned short, netif*) at
c:\users\aa\appdata\local\arduino15\packages\esp32\tools\xtensa-esp32-elf-gcc\gcc8_4_0-esp-2021r1\xtensa-esp32-elf\include\c++.4.0\bits/std_function.h line 682 0x400d415d: _udp_task(void*) at
D:\Code\ArduinoWorkspace\hardware\espressif\esp32\libraries\AsyncUDP\src\AsyncUDP.cpp
line 709
为 async_udp 任务增加 AsyncUDP 库中的分配解决了问题
从 AsyncUDP onPacket 回调调用解密例程时,我收到“堆栈金丝雀观察点已触发”。未从回调中调用的相同数据的测试解密工作正常。非常感谢任何有关如何解决此问题的帮助。
修剪代码
#define CRYPTO_SALT_BYTES 16
#define CRYPTO_ARGON_OUT_SIZE 32
// Code based on
//https://www.doorbird.com/downloads/api_lan.pdf?rev=0.28
//https://github.com/tsearle/doorbird/blob/master/doorbird.c
AsyncUDP udp1;
AsyncUDP udp2;
typedef struct {
unsigned char id[3];
unsigned char version;
uint32_t opslimit;
uint32_t memlimit;
unsigned char salt[16];
unsigned char nonce[8];
unsigned char ciphertext[34];
}__attribute__((packed)) NotifyBroadcast;
typedef struct {
char intercom_id[6];
char event [8];
unsigned timestamp;
} __attribute__((packed)) NotifyBroadcastCiphertext;
char * dbuser = "yourUserHere";
char * dbpassword = "yourPWHere";
unsigned int timestamp;
unsigned char* stretchPasswordArgon(const char *password, unsigned char *salt, unsigned *oplimit, unsigned *memlimit) {
if (sodium_is_zero(salt, CRYPTO_SALT_BYTES) ) {
randombytes_buf(salt, CRYPTO_SALT_BYTES);
return NULL;
}
unsigned char* key = (unsigned char *)malloc(CRYPTO_ARGON_OUT_SIZE);
if (!*oplimit)
*oplimit = crypto_pwhash_argon2i_OPSLIMIT_INTERACTIVE;
if (!*memlimit)
*memlimit = crypto_pwhash_MEMLIMIT_MIN;
if (crypto_pwhash(key, CRYPTO_ARGON_OUT_SIZE, password, strlen(password), salt, *oplimit, *memlimit, crypto_pwhash_ALG_ARGON2I13)) {
Serial.println("Argon2 Failed");
*oplimit = 0;
*memlimit = 0;
free(key);
return NULL;
}
return key;
}
NotifyBroadcastCiphertext decryptBroadcastNotification(const NotifyBroadcast * notification, const unsigned char* password) {
NotifyBroadcastCiphertext decrypted = {{0},{0},0};
int res = 0;
if(res = crypto_aead_chacha20poly1305_decrypt((unsigned char*)&decrypted, NULL, NULL, notification->ciphertext, sizeof(notification->ciphertext), NULL, 0, notification->nonce, password))
Serial.printf("crypto_aead_chacha20poly1305_decrypt() failed %d\n", res);
return decrypted;
}
NotifyBroadcastCiphertext decode_packet(unsigned char * packet, int size, char * password) {
char truncatedPassword[6];
NotifyBroadcast * pkt = (NotifyBroadcast*)packet;
NotifyBroadcastCiphertext decrypted = {{0},{0},0};
if (size != 70 || pkt->id[0] != 0xDE || pkt->id[1] != 0xAD || pkt->id[2] != 0xBE) {
return decrypted;
strncpy(truncatedPassword, password, 5);
truncatedPassword[5] = 0;
unsigned opslimit = ntohl(pkt->opslimit);
unsigned memlimit = ntohl(pkt->memlimit);
unsigned char* stretchPass = stretchPasswordArgon(truncatedPassword, pkt->salt, &opslimit, &memlimit);
if (stretchPass == NULL)
Serial.println("Error making stretchpass!\n");
decrypted = decryptBroadcastNotification(pkt, stretchPass);
free(stretchPass);
return decrypted;
}
void handle_event(char * event_str) {
Serial.printf("Got an event: '%s'\n", event_str);
}
void processPacket(AsyncUDPPacket packet) {
char intercom_id[10];
char event_str[10];
unsigned char* pk = (unsigned char*) malloc(packet.length() + 1);
memcpy(pk, packet.data(), packet.length());
NotifyBroadcastCiphertext event = decode_packet(pk, packet.length(), dbpassword);
free(pk);
if(event.timestamp == 0)
return;
strncpy(intercom_id, event.intercom_id, 6);
intercom_id[6] = 0;
strncpy(event_str, event.event, 8);
event_str[8] = 0;
if(strncmp(dbuser,intercom_id,6) != 0)
return;
if(timestamp == event.timestamp)
return;
timestamp = event.timestamp;
handle_event(event_str);
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" CONNECTED");
if (udp1.listen(6524))
{
udp1.onPacket([](AsyncUDPPacket packet) {
processPacket(packet);
});
}
if (udp2.listen(35344))
{
udp2.onPacket([](AsyncUDPPacket packet) {
processPacket(packet);
});
}
}
解码异常如下。
PC: 0x4010da59: blake2b_compress_ref at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_generichash/blake2b/ref/blake2b-compress-ref.c line 73 EXCVADDR: 0x00000000
Decoding stack results 0x4010da56: blake2b_compress_ref at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_generichash/blake2b/ref/blake2b-compress-ref.c line 73 0x4010caa4: crypto_generichash_blake2b__final at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_generichash/blake2b/ref/blake2b-ref.c line 314 0x4010cd69: crypto_generichash_blake2b__blake2b at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_generichash/blake2b/ref/blake2b-ref.c line 367 0x40107395: crypto_generichash_blake2b at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_generichash/blake2b/ref/generichash_blake2b.c line 23 0x4010b039: blake2b_long at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_pwhash/argon2/blake2b-long.c line 61 0x40108216: fill_first_blocks at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_pwhash/argon2/argon2-core.c line 378 0x40108311: initialize at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_pwhash/argon2/argon2-core.c line 509 0x4010d051: argon2_ctx at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_pwhash/argon2/argon2.c line 68 0x4010d0d2: argon2_hash at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_pwhash/argon2/argon2.c line 129 0x4010d172: argon2i_hash_raw at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_pwhash/argon2/argon2.c line 175 0x4010b165: crypto_pwhash_argon2i at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_pwhash/argon2/pwhash_argon2i.c line 168 0x4010725e: crypto_pwhash at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/libsodium/libsodium/src/libsodium/crypto_pwhash/crypto_pwhash.c line 136 0x400d2424: stretchPasswordArgon(char const*, unsigned char*, unsigned int*, unsigned int*) at D:\Code\ArduinoWorkspace\dbesp32/dbesp32.ino line 66 0x400d2582: decode_packet(unsigned char*, int, char*) at D:\Code\ArduinoWorkspace\dbesp32/dbesp32.ino line 118 0x400d26b6: processPacket(AsyncUDPPacket) at D:\Code\ArduinoWorkspace\dbesp32/dbesp32.ino line 158 0x400d283a: std::_Function_handler >::_M_invoke(const std::_Any_data &, AsyncUDPPacket &) at D:\Code\ArduinoWorkspace\dbesp32/dbesp32.ino line 195 0x400d40f1: AsyncUDP::_recv(udp_pcb*, pbuf*, ip_addr const*, unsigned short, netif*) at c:\users\aa\appdata\local\arduino15\packages\esp32\tools\xtensa-esp32-elf-gcc\gcc8_4_0-esp-2021r1\xtensa-esp32-elf\include\c++.4.0\bits/std_function.h line 682 0x400d415d: _udp_task(void*) at D:\Code\ArduinoWorkspace\hardware\espressif\esp32\libraries\AsyncUDP\src\AsyncUDP.cpp line 709
为 async_udp 任务增加 AsyncUDP 库中的分配解决了问题