2024-06-27 22:35:58 -06:00
|
|
|
#include "config.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ChaChaPoly.h>
|
|
|
|
#include <HardwareSerial.h>
|
2024-06-30 19:00:22 -06:00
|
|
|
#include "Crypto.h"
|
2024-06-27 22:35:58 -06:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2024-06-30 19:00:22 -06:00
|
|
|
const unsigned char *tagPtr = input + sizeof(nonce) + decryptedLength; // actual tag
|
|
|
|
uint8_t computedTag[16]; // computed tag
|
|
|
|
chachaPoly.computeTag(computedTag, sizeof(computedTag));
|
2024-06-27 22:35:58 -06:00
|
|
|
|
2024-06-30 19:00:22 -06:00
|
|
|
// 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;
|
2024-06-27 22:35:58 -06:00
|
|
|
}
|
|
|
|
|
2024-06-30 19:00:22 -06:00
|
|
|
// Compute the tag and check it.
|
2024-07-02 21:18:25 -06:00
|
|
|
// The crypto library implementation of tag verification crashes.
|
2024-06-30 19:00:22 -06:00
|
|
|
bool equal = secure_compare(computedTag, tagPtr, chachaPoly.tagSize());
|
|
|
|
clean(computedTag);
|
|
|
|
if (!equal) {
|
|
|
|
Serial.println("[CHACHA] Authentication failed!");
|
|
|
|
output[0] = '\0';
|
2024-06-27 22:35:58 -06:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-06-30 19:00:22 -06:00
|
|
|
///// END TAG VERIFY
|
2024-06-27 22:35:58 -06:00
|
|
|
|
2024-06-30 19:00:22 -06:00
|
|
|
output[decryptedLength] = '\0';
|
2024-06-27 22:35:58 -06:00
|
|
|
chachaPoly.clear();
|
2024-07-02 21:18:25 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|