当从 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 库中的分配解决了问题