#include "config.h" #include #include #include #include #include "Crypto.h" void print_hex(const unsigned char *data, size_t length) { for (size_t i = 0; i < length; ++i) { Serial.printf("%02x", data[i]); } Serial.println(); } void encrypt_string(const unsigned char *input, size_t length, unsigned char *output) { ChaChaPoly chachaPoly; // Initialize the encryption key unsigned char key[32]; for (int i = 0; i < 32; ++i) { sscanf(CHACHA20_KEY + 2*i, "%02x", &key[i]); } chachaPoly.setKey(key, sizeof(key)); // Generate a random nonce (IV) unsigned char nonce[12]; esp_fill_random(nonce, sizeof(nonce)); // Use the ESP-IDF random number generator chachaPoly.setIV(nonce, sizeof(nonce)); // Encrypt the input data chachaPoly.encrypt(output + sizeof(nonce), input, length); // Compute the authentication tag chachaPoly.computeTag(output + sizeof(nonce) + length, chachaPoly.tagSize()); // Prepend the nonce to the output memcpy(output, nonce, sizeof(nonce)); chachaPoly.clear(); } void decrypt_string(const unsigned char *input, size_t length, unsigned char *output) { ChaChaPoly chachaPoly; // Initialize the decryption key unsigned char key[32]; for (int i = 0; i < 32; ++i) { sscanf(CHACHA20_KEY + 2*i, "%02x", &key[i]); } chachaPoly.setKey(key, sizeof(key)); // Extract the nonce (IV) from the input unsigned char nonce[12]; memcpy(nonce, input, sizeof(nonce)); chachaPoly.setIV(nonce, sizeof(nonce)); // Check that length is long enough to contain a nonce and a tag. if (length < sizeof(nonce) + chachaPoly.tagSize()) { Serial.print("[CHACHA] Input too short to contain nonce and tag: "); print_hex(input, length); output[0] = '\0'; // Set output to an empty string return; } // Decrypt the input data size_t decryptedLength = length - sizeof(nonce) - chachaPoly.tagSize(); chachaPoly.decrypt(output, input + sizeof(nonce), decryptedLength); const unsigned char *tagPtr = input + sizeof(nonce) + decryptedLength; // actual tag uint8_t computedTag[16]; // computed tag chachaPoly.computeTag(computedTag, sizeof(computedTag)); // Can never match if the expected tag length is too long. if (chachaPoly.tagSize() > 16) { Serial.println("[CHACHA] Authentication failed: expected tag length is too long"); output[0] = '\0'; // Set output to an empty string return; } // Compute the tag and check it. // The crypto library implementation of tag verification crashes. bool equal = secure_compare(computedTag, tagPtr, chachaPoly.tagSize()); clean(computedTag); if (!equal) { Serial.println("[CHACHA] Authentication failed!"); output[0] = '\0'; return; } output[decryptedLength] = '\0'; chachaPoly.clear(); } unsigned char* encrypt_buffer(char* buf, unsigned int len, unsigned int* encrypted_len) { // Increase the size of encrypted_buf to hold the nonce, the encrypted data, and the authentication tag. unsigned char* encrypted_buf = (unsigned char*)malloc(12 + len + 16); // 12 bytes for nonce and 16 bytes for tag if(!encrypted_buf) { // handle error return NULL; } encrypt_string((unsigned char *)buf, len, encrypted_buf); *encrypted_len = 12 + len + 16; return encrypted_buf; }