From 13af4e9ff38bf0394d01afbd45e888c737d7cf71 Mon Sep 17 00:00:00 2001 From: schauausgmbh Date: Wed, 30 Sep 2026 15:55:27 +0200 Subject: [PATCH] firmware update to support display on ESP32-C6-LCD-1.47 --- AES256_Seed_Phrase_encryptor.ino | 238 ++++++++++++++++++++++--------- README.md | 26 +++- display.cpp | 184 ++++++++++++++++++++++++ display.h | 34 +++++ 4 files changed, 409 insertions(+), 73 deletions(-) create mode 100644 display.cpp create mode 100644 display.h diff --git a/AES256_Seed_Phrase_encryptor.ino b/AES256_Seed_Phrase_encryptor.ino index 9bc8d97..384f280 100644 --- a/AES256_Seed_Phrase_encryptor.ino +++ b/AES256_Seed_Phrase_encryptor.ino @@ -20,38 +20,72 @@ * DEALINGS IN THE SOFTWARE. */ +// compiler values definition +#define PRINT_SERIAL 1 +#define DEBUG 0 +#define USE_DISPLAY 1 +#define HAS_KEYBOARD 0 + +#define BTN_HOME 9 + +#define MAX_INPUT_LENGHT 256 + +// external libraries #include #include #include -#define MAX_INPUT_LENGHT 256 +// project files to include +#include "display.h" //creating an object of AES256 class AES256_ESP aes256; void printHelp () { - Serial.println(); - Serial.println("┌-----------------------------------------------------┐"); - Serial.println("| Encrypt / Decrypt seed phrase with AES256 algorithm |"); - Serial.println("└-----------------------------------------------------┘"); - Serial.println(); - Serial.println("WARNING: DO NOT USE THIS ON ANY NETWORK CONNECTED DEVICE AND ENSURE THE DECRYPTION IS WORKING PROPERLY!"); - Serial.println("USE IN SECURE ENVIRONMENTS ONLY!"); - Serial.println("This program is offered as it is and no warranties will be granted in any case!"); - Serial.println("Review the source code thoroughly before using it for real application!"); - Serial.println("Available commands:"); - Serial.println("help - print this help to serial console"); - Serial.println("key - generate random HEX key and print it to the serial console"); - Serial.println("key - set key (hexadecimal or ascii) for encryption / decryption"); - Serial.println("encrypt <12 or 24 word seed phrase> - encrypts your 12 ord 24 word plain text seed phrase to HEX string"); - Serial.println("decrypt - decrypts your encrypted HEX string back to clear text seed phrase"); - Serial.println("clear - clear all cryptographic information from memory"); - Serial.println("restart - reboot the device for a fresh restart; any working data will be removed from memory"); + #if PRINT_SERIAL + Serial.println(); + Serial.println("┌-----------------------------------------------------┐"); + Serial.println("| Encrypt / Decrypt seed phrase with AES256 algorithm |"); + Serial.println("└-----------------------------------------------------┘"); + Serial.println(); + Serial.println("WARNING: DO NOT USE THIS ON ANY NETWORK CONNECTED DEVICE AND ENSURE THE DECRYPTION IS WORKING PROPERLY!"); + Serial.println("USE IN SECURE ENVIRONMENTS ONLY!"); + Serial.println("This program is offered as it is and no warranties will be granted in any case!"); + Serial.println("Review the source code thoroughly before using it for real application!"); + Serial.println("Available commands:"); + Serial.println("help - print this help to serial console"); + Serial.println("key - generate random HEX key and print it to the serial console"); + Serial.println("key - set key (hexadecimal or ascii) for encryption / decryption"); + Serial.println("encrypt <12 or 24 word seed phrase> - encrypts your 12 ord 24 word plain text seed phrase to HEX string"); + Serial.println("decrypt - decrypts your encrypted HEX string back to clear text seed phrase"); + Serial.println("clear - clear all cryptographic information from memory"); + Serial.println("restart - reboot the device for a fresh restart; any working data will be removed from memory"); + #endif + + #if USE_DISPLAY + display_help(); + #endif +} + +void byteToHex (byte b, char* returnVal) { + static const char hexChars[] = "0123456789ABCDEF"; + + //char returnVal[4]; + returnVal[0] = hexChars[b >> 4]; + returnVal[1] = hexChars[b & 0x0F]; + returnVal[2] = ' '; + returnVal[3] = '\0'; + #if PRINT_SERIAL + Serial.print(returnVal); + #endif } void setCryptKey (String argKey) { - Serial.println(); - Serial.println("Operation: setting encryption key"); + #if PRINT_SERIAL + Serial.println(); + Serial.println("Operation: setting encryption key"); + #endif + argKey.trim(); String tempKey = argKey; byte cryptKey[32]; @@ -59,19 +93,18 @@ void setCryptKey (String argKey) { tempKey.replace(" ", ""); // remove any spaces in between characters to check for hexadecimal values if(argKey.length() != 32 && tempKey.length() / 2 != 32) { // there was no valid key given; keys need to consist of 32 characters (256bit) - Serial.println("No valid key handed over; generating new key:"); + #if PRINT_SERIAL + Serial.println("No valid key handed over; generating new key:"); + #endif + for(int i=0; i < 32; i++) { cryptKey[i] = random(256); } - for(size_t i=0; i<32; i++) { - if(cryptKey[i] < 16) Serial.print("0"); - Serial.print(cryptKey[i], HEX); - Serial.print(" "); - } - Serial.println(); } else { // process valid key provided - Serial.println("Valid key detected"); + #if PRINT_SERIAL + Serial.println("Valid key detected"); + #endif bool keyIsHex = true; for(size_t i = 0; i < tempKey.length(); i++) @@ -96,17 +129,33 @@ void setCryptKey (String argKey) { } // set the final key for encryption / decryption aes256.setKey(cryptKey, 32); - Serial.println("Key set for encryption / decryption"); + + #if PRINT_SERIAL + Serial.println("Key set for encryption / decryption"); + for(size_t i=0; i<32; i++) { + if(cryptKey[i] < 16) Serial.print("0"); + Serial.print(cryptKey[i], HEX); + Serial.print(" "); + } + Serial.println(); + #endif + + #if USE_DISPLAY + display_key(cryptKey); + #endif } void decryptData (String data) { - Serial.println(); - Serial.println("Operation: decrypting data"); + #if PRINT_SERIAL + Serial.println(); + Serial.println("Operation: decrypting data"); + #endif data.replace(" ", ""); byte dataBlock[aes256.blockSize()]; byte plainText[aes256.blockSize()]; String byteString = ""; + String fullString = ""; // check whether the input data is a hexadecimal string bool dataIsHex = true; @@ -117,11 +166,16 @@ void decryptData (String data) { dataIsHex = false; if(!dataIsHex) { - Serial.println("Abort decryption! No valid input data!"); + #if PRINT_SERIAL + Serial.println("Abort decryption! No valid input data!"); + #endif return; } - Serial.println("decrypted data block: "); + #if PRINT_SERIAL + Serial.println("decrypted data block: "); + #endif + for(int i=0; i < data.length(); i += aes256.blockSize() * 2) { for(int j=0; j 0) { - cmd = inp.substring(0, inp.indexOf(' ')); - arg = inp.substring(inp.indexOf(' ') + 1); - arg.trim(); + if(inp.indexOf(' ') > 0) { + cmd = inp.substring(0, inp.indexOf(' ')); + arg = inp.substring(inp.indexOf(' ') + 1); + arg.trim(); + } + else + cmd = inp; + + if (cmd == "help") printHelp(); + else if(cmd == "key") setCryptKey(arg); + else if (cmd == "encrypt") encryptData(arg); + else if (cmd == "decrypt") decryptData(arg); + else if (cmd == "clear") clearCryptograficInformation(); + else if (cmd == "restart") restartDevice(); + else { + #if PRINT_SERIAL + Serial.println("\r\nUnknown command! Try again!"); + #endif + } } - else - cmd = inp; +} - if (cmd == "help") printHelp(); - else if(cmd == "key") setCryptKey(arg); - else if (cmd == "encrypt") encryptData(arg); - else if (cmd == "decrypt") decryptData(arg); - else if (cmd == "clear") clearCryptograficInformation(); - else if (cmd == "restart") restartDevice(); - else Serial.println("\r\nUnknown command! Try again!"); +void readHome() { + if(!digitalRead(BTN_HOME)) { // Home-Button pressed (pulled high with 10K resistor on the board) + #if USE_DISPLAY + display_home(); + #endif + + #if PRINT_SERIAL + Serial.println("Waiting for command (send \"help\" for available commands)"); + #endif + delay(1000); + } } void setup() { Serial.begin(115200); - printHelp(); + while(!Serial); + pinMode(BTN_HOME, INPUT); + display_setup(); + Serial.println("Waiting for command"); + #if PRINT_SERIAL + Serial.println("send \"help\" for available commands"); + #endif } void loop() { readCmd(); + readHome(); // check for Home-button being pressed } diff --git a/README.md b/README.md index c9d58c3..cd02712 100644 --- a/README.md +++ b/README.md @@ -19,21 +19,34 @@ This is a Firmware for ESP32-based boards to encrypt / decrypt seed phrases and This firmware is making use of: - [ESP32 board definition](https://github.com/espressif/arduino-esp32) => install "esp32" by Espressif Systems in the boards manager inside the Arduino IDE - [Arduino Cryptography Library](https://rweather.github.io/arduinolibs/crypto.html) => install the library "Crypto" by Rhys Weatherley inside the Arduino IDE +- [GFX Library for Arduino](https://github.com/moononournation/Arduino_GFX) => install the library "GFX Library for Arduino" by Moon On Our Nation inside the Arduino IDE ## License -This firmware is open source licensed under the [EUROPEAN UNION PUBLIC LICENCE (EUPL) v. 1.2](LICENSE). -You can do with and modify it however you want. -You cannot hold us liable for any loss or damage caused by the use of this firmware. You will use it on your own risk. +This firmware is open source licensed under the [EUROPEAN UNION PUBLIC LICENCE (EUPL) v. 1.2](LICENSE). +You can do with and modify it however you want. +You cannot hold us liable for any loss or damage caused by the use of this firmware. You will use it on your own risk. -## Installation +## Hardware +This project was solely developed to make use of the [Waveshare ESP32-C6-LCD-1.47 board](https://docs.waveshare.com/ESP32-C6-LCD-1.47) or any of its clones. +The firmware is able to run on pretty much any ESP32 microcontroller though. But some tweaking for other displays may be needed. + +## Installation of the Firmware + +- Install Arduino IDE (if it was not installed already) - Download this repository to your computer - Install the needed board definitions and libraries - select the board that you'd like to use from the tools menu - selct the serial port your board is connected to in the tools menu +- set the compiler directives according to your likings + * PRINT_SERIAL = 1 for information sent back to the serial terminal + * DEBUG = 1 if you'd like some more verbose feedback sent to the serial terminal + * USE_DISPLAY = 1 if you were using a board with a display connected + * HAS_KEYBOARD = 1 if you were using a matrix keyboard connected to the microcontroller + * DEBUG_DISPLAY = 1 (in display.h) to receive some more verbose feedback from the display driver - hit the upload button -- wait for the compilation and upload to complete +- wait for the compilation and upload to complete; this may take a while due to the compilation time of the libraries involved ## Usage @@ -145,5 +158,6 @@ decrypt 49 04 36 FE DD 5D ED 78 D4 7F EF 1B 82 6F 6C 2A 83 4E 38 8F BB D0 34 F1 ## notes on issues and security - Send any findings in the cryptographic library to [the original author of the library](https://github.com/rweather/arduinolibs) -- any issues on the firmware implementaion: contact us on the [fediverse @schauausgmbh@social.schauaus.at](https://social.schauaus.at/@schauausgmbh) or Matrix @schauausgmbh:matrix.schauaus.at +- Send any findings in the Arduino GFX library to [the original author of the library](https://github.com/moononournation/Arduino_GFX) +- any issues on the firmware implementaion: contact us on the [fediverse @schauausgmbh@social.schauaus.at](https://social.schauaus.at/@schauausgmbh) or on Matrix @schauausgmbh:matrix.schauaus.at - any security issues on the firmware: contact us on Matrix @schauausgmbh:matrix.schauaus.at \ No newline at end of file diff --git a/display.cpp b/display.cpp new file mode 100644 index 0000000..30c7144 --- /dev/null +++ b/display.cpp @@ -0,0 +1,184 @@ +#include +#include +#include "pins_arduino.h" +#include "display.h" + +Arduino_DataBus *bus = new Arduino_HWSPI( TFT_DC, TFT_CS); +Arduino_GFX *gfx = new Arduino_ST7789(bus, TFT_RST, TFT_ROTATION, TFT_IPS, TFT_WIDTH, TFT_HEIGHT, TFT_COL_OFFSET, TFT_ROW_OFFSET); + +void display_crypt_block(String str_to_print, uint16_t btn) { + const uint8_t textOffsetX = 20; + const uint8_t textOffsetY = 3; + uint16_t strIndex = 0; + + rgbLedWrite(RGB_LED, 255, 25, 0); + gfx->setTextColor( RGB565(255, 255, 0 ) ); + + while (true) { //render single pages + uint8_t line = 1; + + // clear screen and print page header + gfx->fillScreen( RGB565( 255, 100, 0 ) ); + gfx->setTextSize(3); + gfx->setCursor(5, 5); + gfx->println("encrypted"); + gfx->setTextSize(2); + gfx->setCursor(textOffsetX, 35); + + while (line <= 14) { // render lines + uint8_t word = 1; + do { //print next line + if(str_to_print[strIndex] == ' ') { + word++; + if(word % 5) gfx->print(' '); + } + else gfx->print(str_to_print[strIndex]); + strIndex++; + if( strIndex >= str_to_print.length() ) break; + } while( word % 5); + if( strIndex >= str_to_print.length() ) break; + gfx->println(); + gfx->setCursor(textOffsetX, gfx->getCursorY() + textOffsetY); + line++; + } + if( strIndex >= str_to_print.length() ) break; + gfx->print('>'); + + // wait for Home-button to be pressed and released before continuing to next page + while ( digitalRead(btn) ); //Home-button not pressed + while ( !digitalRead(btn) ); //Home-button pressed + } +} + +void display_decrypt_text(String str_to_print, uint16_t btn) { + // get number of spaces in string and by that the number of words in the seed phrase + uint8_t numWords = 0; + for(int i = 0; i < str_to_print.length(); i++) { + if (str_to_print[i] == ' ') numWords++; + } + if(numWords > 0) numWords++; + #if DEBUG_DISPLAY + Serial.print("Number of seed words: "); + Serial.println(numWords); + #endif + + int strIndex = 0; + for(int page = 0; page <= floor (numWords / 12); page++) { + int word = 1; + + gfx->fillScreen( RGB565( 0, 220, 0 ) ); + rgbLedWrite(RGB_LED, 0, 255, 0); + gfx->setTextColor( RGB565(255, 255, 255 ) ); + gfx->setTextSize(3); + gfx->setCursor(5, 5); + gfx->println("decrpyted"); + gfx->setTextSize(2); + gfx->setCursor(0, 40); + gfx->print(' '); + + do { + if(str_to_print[strIndex] == ' ') { + gfx->println(); + word++; + gfx->setCursor(0, gfx->getCursorY() + 5); + } + gfx->print( str_to_print[strIndex] ); + strIndex++; + if( strIndex >= str_to_print.length() ) break; + } + while (word <= 12); + if( strIndex >= str_to_print.length() ) break; + gfx->setCursor(0, 300); + gfx->print(" >"); + + // wait for Home-button to be pressed and released before continuing to next page + while ( digitalRead(btn) ); //Home-button not pressed + while ( !digitalRead(btn) ); //Home-button pressed + } +} + +void display_help() { + #define TEXT_X_OFFSET 3 + gfx->fillScreen( RGB565( 0, 0, 255 ) ); + rgbLedWrite(RGB_LED, 0, 0, 255); + gfx->setTextSize(2); + gfx->setTextColor( RGB565(255, 255, 255 ) ); + gfx->setCursor(0, 17); + gfx->setCursor(TEXT_X_OFFSET, gfx->getCursorY()); + gfx->println("help\r\n print this\r\n"); + gfx->setCursor(TEXT_X_OFFSET, gfx->getCursorY()); + gfx->println("key\r\n generate\r\n random key"); + gfx->setCursor(TEXT_X_OFFSET, gfx->getCursorY()); + gfx->println("key \r\n use def. key\r\n"); + gfx->setCursor(TEXT_X_OFFSET, gfx->getCursorY()); + gfx->println("encrypt \r\n encrypt seed"); + gfx->setCursor(TEXT_X_OFFSET, gfx->getCursorY()); + gfx->println("decrpyt\r\n decrypt seed\r\n "); + gfx->setCursor(TEXT_X_OFFSET, gfx->getCursorY()); + gfx->println("clear\r\n clear data"); + gfx->setCursor(TEXT_X_OFFSET, gfx->getCursorY()); + gfx->println("restart\r\n reboot device"); +} + +void display_home() { + gfx->fillScreen( RGB565( 255, 255, 255 ) ); + rgbLedWrite(RGB_LED, 255, 255, 255); + gfx->setTextSize(2); + gfx->setTextColor( RGB565(30, 30, 30 ) ); + gfx->setCursor(20, 5); + gfx->println("Seed Phrase"); + gfx->setCursor(2, gfx->getCursorY()); + gfx->println("Crypter AES256"); + gfx->setTextSize(1); + gfx->setCursor(5, 45); + gfx->println("Encrypt/Decrypt seed phrase"); + gfx->setCursor(23, gfx->getCursorY() + 1); + gfx->println("with AES256 algorithm"); + gfx->setTextSize(2); + gfx->setCursor(14, 120); + gfx->println("Enter 'help'"); + gfx->setCursor(26, gfx->getCursorY()); + gfx->println("to display"); + gfx->setCursor(14, gfx->getCursorY()); + gfx->println("commands and"); + gfx->setCursor(20, gfx->getCursorY()); + gfx->println("information"); +} + +void display_key(byte hexKey[32]) { + const uint8_t textOffsetX = 20; + const uint8_t textOffsetY = 3; + + gfx->fillScreen( RGB565( 255, 220, 0 ) ); + rgbLedWrite(RGB_LED, 255, 100, 0); + gfx->setTextSize(3); + gfx->setTextColor( RGB565(255, 0, 0 ) ); + gfx->setCursor(25, 10); + gfx->println("Key set"); + gfx->setTextSize(2); + gfx->setCursor(textOffsetX, 50); + for(int i=0; i<32; i++) { + if(hexKey[i] < 16) + gfx->print("0"); + gfx->print(hexKey[i], HEX); + if( (i+1) % 4 == 0 ) { + gfx->println(); + gfx->setCursor(textOffsetX, gfx->getCursorY() + textOffsetY); + } + else gfx->print(" "); + } +} + +void display_setup() { + pinMode(TFT_BKL, OUTPUT); + analogWrite(TFT_BKL, floor(TFT_BKL_DUTY * 255 / 100 + 0.5) ); + + SPI.begin(TFT_SCK, TFT_MISO, TFT_MOSI, TFT_CS); + + if (!gfx->begin()) + { + Serial.println("gfx->begin() failed!"); + } + gfx->fillScreen( RGB565( 255, 255, 255 ) ); + display_home(); +} diff --git a/display.h b/display.h new file mode 100644 index 0000000..a4d31bc --- /dev/null +++ b/display.h @@ -0,0 +1,34 @@ +//#include +#include + +#define DEBUG_DISPLAY 0 + +// pin definition +#define TFT_CS 14 +#define TFT_DC 15 +#define TFT_IPS true +#define TFT_MISO -1 +#define TFT_MOSI 6 +#define TFT_RST 21 +#define TFT_SCK 7 +#define TFT_BKL 22 +#define RGB_LED 8 + +// display dimensions ESP32-C6-LCD1.47 is portrait by default +#define TFT_HEIGHT 320 +#define TFT_WIDTH 172 +#define TFT_COL_OFFSET 34 // offset needed due to organization of ST7789 VRAM +#define TFT_ROW_OFFSET 0 // offset needed due to organization of ST7789 VRAM + +// set display rotation (needs to be 0 for offsets to be applied properly!) +#define TFT_ROTATION 0 + +// backlight settings +#define TFT_BKL_DUTY 50 + +void display_setup(); +void display_help(); +void display_home(); +void display_key(byte hexKey[32]); +void display_crypt_block(String str_to_print, uint16_t btn = 9); +void display_decrypt_text(String str_to_print, uint16_t btn = 9);