firmware update to support display on ESP32-C6-LCD-1.47

This commit is contained in:
schauausgmbh committed 2026-09-30 15:55:27 +02:00
1 parent a66ccd75c0
commit 13af4e9ff3
4 files changed
+409 -73

No files matched your search

+171 -67
View File
@@ -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 <Crypto.h>
#include <AES.h>
#include <string.h>
#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 <your 32byte 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 <encrypted HEX string> - 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 <your 32byte 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 <encrypted HEX string> - 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<aes256.blockSize() * 2; j+=2) {
byteString = data.substring(i + j, i + j + 2);
@@ -131,20 +185,35 @@ void decryptData (String data) {
aes256.decryptBlock(plainText, dataBlock);
for(int i=0; i<sizeof(plainText); i++){
if(plainText[i] == '\0') break;
Serial.write(plainText[i]);
#if PRINT_SERIAL
Serial.write(plainText[i]);
#endif
fullString += (char)plainText[i];
}
}
Serial.println();
#if PRINT_SERIAL
Serial.println();
#endif
#if USE_DISPLAY
display_decrypt_text(fullString, BTN_HOME);
#endif
}
void encryptData (String data) {
Serial.println();
Serial.println("Operation: encrypting data");
#if PRINT_SERIAL
Serial.println();
Serial.println("Operation: encrypting data");
#endif
byte dataBlock[aes256.blockSize()];
byte cypher[aes256.blockSize()];
String fullString = "";
char hexStr[4];
#if PRINT_SERIAL
Serial.println("encrypted data block: ");
#endif
Serial.println("encrypted data block: ");
for(int i=0; i<data.length(); i+=aes256.blockSize()) {
for(int j=0; j<aes256.blockSize(); j++) {
dataBlock[j] = data[i + j];
@@ -152,57 +221,92 @@ void encryptData (String data) {
}
aes256.encryptBlock(cypher, dataBlock);
for(int j=0; j<sizeof(cypher); j++) {
if(cypher[j] < 16) Serial.print("0");
Serial.print(cypher[j], HEX);
Serial.print(" ");
byteToHex(cypher[j], hexStr);
fullString += hexStr;
}
}
Serial.println();
#if PRINT_SERIAL
Serial.println();
#endif
display_crypt_block(fullString, BTN_HOME);
}
void clearCryptograficInformation () {
Serial.println();
Serial.println("Operation: clear all cryptographic information from memory");
#if PRINT_SERIAL
Serial.println();
Serial.println("Operation: clear all cryptographic information from memory");
#endif
aes256.clear();
Serial.println("Memory cleared");
#if PRINT_SERIAL
Serial.println("Memory cleared");
#endif
display_home();
}
void restartDevice () {
Serial.println("\r\nInitiating reboot of this device!\r\n");
#if PRINT_SERIAL
Serial.println("\r\nInitiating reboot of this device!\r\n");
#endif
ESP.restart();
}
void readCmd () {
Serial.println();
Serial.println("Waiting for command (send \"help\" for available commands)");
while (Serial.available() == 0) {} // wait until input on the serial console is available
String inp = Serial.readString();
inp.trim();
String cmd = "";
String arg = "";
if ( Serial.available() ) {
String inp = Serial.readString();
inp.trim();
String cmd = "";
String arg = "";
if(inp.indexOf(' ') > 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
}
+20 -6
View File
@@ -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
+184
View File
@@ -0,0 +1,184 @@
#include <sys/_stdint.h>
#include <sys/_types.h>
#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 <key>\r\n use def. key\r\n");
gfx->setCursor(TEXT_X_OFFSET, gfx->getCursorY());
gfx->println("encrypt <seed>\r\n encrypt seed");
gfx->setCursor(TEXT_X_OFFSET, gfx->getCursorY());
gfx->println("decrpyt<HEX>\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();
}
+34
View File
@@ -0,0 +1,34 @@
//#include <U8g2lib.h>
#include <Arduino_GFX_Library.h>
#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);