Skip to content

Instantly share code, notes, and snippets.

@noahcoad
Last active May 10, 2023 17:01
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save noahcoad/00ac0e8fdff0be0d927bfa8f35879644 to your computer and use it in GitHub Desktop.
Save noahcoad/00ac0e8fdff0be0d927bfa8f35879644 to your computer and use it in GitHub Desktop.
//
// Example of using ESP32 Arudino mbed library to
// Encrypt and Decrypt using an asyncronous RSA 2048 bit public and private key pair
// created 2020-07-05 by Noah Coad
//
// Inside a "data" directory, run these commands to generate a key pair
// then use the ESP32 Sketch Data Uploader to upload files to ESP32 SPIFFS files
//
// openssl genrsa -out private-rsa 2048
// openssl pkcs8 -topk8 -inform pem -in private-rsa -outform pem -nocrypt -out private
// openssl rsa -in private -pubout > public
//
// Thanks to these resources for getting me started:
// https://www.b4x.com/android/forum/threads/using-rsa-on-a-esp32-via-inline-c.104325/
//
#include "SPIFFS.h"
#include "mbedtls/pk.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/entropy.h"
#include "mbedtls/error.h"
#include "mbedtls/platform.h"
#include "libb64/cdecode.h"
#include "libb64/cencode.h"
void listDir(fs::FS &fs, const char * dirname, uint8_t levels = 0);
void setup() {
Serial.begin(115200);
// this is essential for mbed to be able to read files
SPIFFS.begin();
// show files to confirm keys are present
listDir(SPIFFS, "/");
readFirstLine("/spiffs/public");
// perform the encrpyion/decryption
RSA();
}
// list files in SPIFFS
void readFirstLine(const char* path) {
FILE* f = fopen(path, "r");
if (f == NULL) {
Serial.println("Failed to open file for reading");
return;
}
char line[64];
fgets(line, sizeof(line), f);
fclose(f);
Serial.println(line);
}
// list files in SPIFFS
void listDir(fs::FS &fs, const char * dirname, uint8_t levels) {
Serial.printf("Listing directory: %s\r\n", dirname);
File root = fs.open(dirname);
if (!root) {
Serial.println("- failed to open directory");
return;
}
if (!root.isDirectory()) {
Serial.println(" - not a directory");
return;
}
File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
Serial.print(" DIR : ");
Serial.println(file.name());
if (levels) {
listDir(fs, file.name(), levels - 1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print("\tSIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
// perform RSA encryption
void RSA() {
unsigned char encrypted[MBEDTLS_MPI_MAX_SIZE];
unsigned char decrypted[MBEDTLS_MPI_MAX_SIZE];
memset(encrypted, 0, sizeof(encrypted));
memset(decrypted, 0, sizeof(decrypted));
// initilize context
int ret = 0;
mbedtls_pk_context pk;
mbedtls_pk_init( &pk );
// read the public key
if ((ret = mbedtls_pk_parse_public_keyfile(&pk, "/spiffs/public")) != 0)
{
printf("Public key read failed\nmbedtls_pk_parse_public_keyfile returned -0x%04x\n", -ret);
char errbuf[256];
mbedtls_strerror(ret, errbuf, 200);
mbedtls_printf("Last error was: -0x%04x - %s\n\n", (int) - ret, errbuf);
}
else printf("Public Key loaded.\n");
// prep opperating context
size_t olen = 0;
unsigned char to_encrypt[] = "This is a test...";
// unsigned char to_encrypt[] = "{\"num\":\"1234123412341234\",\"exp\":\"12/23\",\"zip\":\"75002\"}";
size_t to_encrypt_len = sizeof(to_encrypt);
mbedtls_ctr_drbg_context ctr_drbg;
char *personalization = "my_app_specific_string";
mbedtls_entropy_context entropy;
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&ctr_drbg);
// seed deterministic random byte generator
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
(const unsigned char *) personalization, strlen(personalization));
// perform encryption
if ((ret = mbedtls_pk_encrypt(&pk, to_encrypt, to_encrypt_len,
encrypted, &olen, sizeof(encrypted),
mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) {
printf("Encryption failed\nmbedtls_pk_encrypt returned -0x%04x\n", -ret );
char errbuf[256];
mbedtls_strerror(ret, errbuf, 200);
mbedtls_printf("Last error was: -0x%04x - %s\n\n", (int) - ret, errbuf);
}
else {
printf("\n . Encrypted\n");
printf("Output Length: %i \n", olen);
}
char encstr[base64_encode_expected_len(olen)];
int enclen = base64_encode_chars(reinterpret_cast<const char*>(encrypted), olen, encstr);
printf("base64: %s\n", encstr);
// border between encrypting and decrypting
// decrypt from base64 encoding
// commend these next few lines out to
// decode from original encoding instead
memset(encrypted, 0, sizeof(encrypted));
char rsabytes[base64_decode_expected_len(strlen(encstr))];
int rsalen = base64_decode_chars(encstr, strlen(encstr), rsabytes);
memcpy(encrypted, rsabytes, rsalen);
// init for decryption
mbedtls_pk_init(&pk);
// read private key
if ((ret = mbedtls_pk_parse_keyfile(&pk, "/spiffs/private", "")) != 0) {
printf("Private key load failed\nmbedtls_pk_parse_keyfile returned -0x%04x\n", -ret );
}
else printf("Private Key loaded.\n");
printf("\n . Decryption\n");
printf("Output length: %i \n", olen);
// decypt
if ((ret = mbedtls_pk_decrypt(&pk, encrypted, olen, decrypted, &olen,
sizeof(decrypted), mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) {
printf("Decrypted failed\nmbedtls_pk_decrypt returned -0x%04x\n", -ret );
}
else {
printf("Decrypted Text: %s \n", decrypted);
// printBlock(decrypted, 128);
}
}
// print buffer block
void printBlock(unsigned char * block, size_t len) {
for (int i = 0; i < len; i++ ) {
printf( "%02x[%c]%c", block[i], (block[i] > 31) ? block[i] : ' ', ((i & 0xf) != 0xf) ? ' ' : '\n' );
}
printf("\n");
}
void loop() {
// don't need to loop anything here
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment