From ac6915443c1725fafe853f91bec00e0a7013f46b Mon Sep 17 00:00:00 2001 From: SCHAUAUS GmbH <2+schauausgmbh@noreply.aaskablackwolf.servehttp.com> Date: Wed, 9 Sep 2026 09:55:30 +0000 Subject: [PATCH] Initial version of the firmware and tables - Initial version of the firmware - table for creating hexadecimal values with a 20 sided die - table to note down encryption key and encrypted data to print on an A4 sheet in landscape format (including a cutting line to separate the data from the key) --- AES256_Seed_Phrase_encryptor.ino | 208 +++++++++++++++++++++++++++++++ D20_table.ods | Bin 0 -> 12242 bytes 2 files changed, 208 insertions(+) create mode 100644 AES256_Seed_Phrase_encryptor.ino create mode 100644 D20_table.ods diff --git a/AES256_Seed_Phrase_encryptor.ino b/AES256_Seed_Phrase_encryptor.ino new file mode 100644 index 0000000..9bc8d97 --- /dev/null +++ b/AES256_Seed_Phrase_encryptor.ino @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2026 SCHAUAUS GmbH + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#define MAX_INPUT_LENGHT 256 + +//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"); +} + +void setCryptKey (String argKey) { + Serial.println(); + Serial.println("Operation: setting encryption key"); + argKey.trim(); + String tempKey = argKey; + byte cryptKey[32]; + + 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:"); + 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"); + + bool keyIsHex = true; + for(size_t i = 0; i < tempKey.length(); i++) + if ( !(tempKey[i] >= '0' && tempKey[i] <= '9') && + !(tempKey[i] >= 'a' && tempKey[i] <= 'f') && + !(tempKey[i] >= 'A' && tempKey[i] <= 'F') ) + keyIsHex = false; + + if (keyIsHex) { // input key is hexadecimal representation + String byteString = ""; + for(size_t idx = 0; idx < tempKey.length(); idx += 2) { + byteString = tempKey.substring(idx, idx+2); + long byteValue = strtol(byteString.c_str(), NULL, 16); + cryptKey[idx / 2] = (byte)byteValue; + } + } + else { // input key is ASCII-representation + for(size_t i=0; i<32; i++) { + cryptKey[i] = argKey[i]; + } + } + } + // set the final key for encryption / decryption + aes256.setKey(cryptKey, 32); + Serial.println("Key set for encryption / decryption"); +} + +void decryptData (String data) { + Serial.println(); + Serial.println("Operation: decrypting data"); + + data.replace(" ", ""); + byte dataBlock[aes256.blockSize()]; + byte plainText[aes256.blockSize()]; + String byteString = ""; + + // check whether the input data is a hexadecimal string + bool dataIsHex = true; + for(size_t i = 0; i < data.length(); i++) + if ( !(data[i] >= '0' && data[i] <= '9') && + !(data[i] >= 'a' && data[i] <= 'f') && + !(data[i] >= 'A' && data[i] <= 'F') ) + dataIsHex = false; + + if(!dataIsHex) { + Serial.println("Abort decryption! No valid input data!"); + return; + } + + Serial.println("decrypted data block: "); + for(int i=0; i < data.length(); i += aes256.blockSize() * 2) { + for(int j=0; j data.length()) dataBlock[j] = '\0'; + } + aes256.encryptBlock(cypher, dataBlock); + for(int j=0; j 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 Serial.println("\r\nUnknown command! Try again!"); +} + +void setup() { + Serial.begin(115200); + printHelp(); +} + +void loop() { + readCmd(); +} diff --git a/D20_table.ods b/D20_table.ods new file mode 100644 index 0000000000000000000000000000000000000000..8ca087ace2c22c7e23f4670dd242aee000cf317c GIT binary patch literal 12242 zcmb7q1z23m(%|44+&y@LyORV68r(I54K`SiKyY^m?hriq;K3b&J4|p1?(VRYyL;b# z|G)e8+wJ-KoSHtTs{2%RbyruFiUI;60RVss0L-{E8wP=e!r1`;z@G|h0@zyFnmfBY zm>WAdfUQi8ovrNcI9%<_*zJv-ten{G9n9^_>`h&4&F!4oog6-y8=E;FIWeO z<17ttxh*C2 z7V0$0Q|o|&?AJ}7?OqFgObTKXzyy!gr_ClDDZ?OdJMW8idnd6wAuna6)JDO*4_jSAWj9OEsQbhp;wf5R_5(y3f2tWV;{wMqX7RkSO2Lo_m zRnp!LWM$#<=`Ue8adZ4(?)*@8FqZS5EN@t(ZfO{zKx*&Os*%MRTd zPLU6nF7;>zDB}o1?ll}39)c7^AqCF6m0B#?@=?|VdaWj7YQ=;> z>`GM*T1`(~pQG%8h0@5f$ICFpsu+-O}zF$zs=RWd!x!A}GCpx*xLimyVspTJd9Zg=@1xQH)M`z;;^6Xp5YL#s;c zlXMuvcg0Z>d|PXMJk^2Hfv5$O;H8}$-OwFQvY_KeiGH=dXp3D=bJSv0#a*-sYf#yx zN({fT>hwP4xL#9-tP0C0UuOt$(knEjkqKXF!GL_SS= zVMyGLEeH^*)_|?OP?!2du}NPsj;R(b$+C?ge>*cAcQ~m7+T|H?8lcnvFhDH2En8q7 zBU_m_`NF@FlE_mCvF>B;Q3~v?U2IXCn&%&zt~qhzd-lUcEI`Br5pc&XYaP0%zjVaQ zkmNT`OKxE3*Oe@w5e;lHq~j#w8Kk^^3wuXVD53h+CGgig-=X(=jiMU zY6(mp32)T{%_UJ2dQ+L(V$NL~u!ivxt{Dm^@gK>>Hs7N~(a|+8kcM4ZBKmmEU9!wx z60BT|pze+hdWh-mM%Q}jO>i8W^?9fXF|>2X($@~mj74F-J50)$P^QgF=t^4cJv&&Z z$Q-dS8G*Y~RA+G~EnDYIx)pq@jm1WwxjBtHHlM$k6G}z#y${a`1$m7vNrm34OP@sp zE}RVkJe3hC{q+uBrNr8%jQjns9I+yEKPlZfRP}=JNt2Kd$Gzg%w?;qdX!q~+zPjNf&vufEg_5^#STrmANWQJu%ltELDHIR zRD!ecK-Fd&)cCOt-}OfO+%kpI&tx5qqQ^4$OcmXF?AI!l6MruS(dTV^P@|MmR1tY} zmh!QeDHhFAuH zo-^BclMFIFC;i9nvlG0JBc&#}bdTABTA8eiXja$Z?~l zE3#EaY50{?$e6YzZ{=)Ly15ne{A4F-<6pDVj3p zNSf@b%A*F%_fjoi=i^NOp%~;O-h=gt#aMPKfO@S|+`5Q5@R{d=(2ex zYE%D;_qAeIdwcc!h;Z6g+p?0T?=sx(W0&o&9TdOdA0lIQJftIw>=9q*X(3%w>p07b zNS`S~LWQ~3K<<2yvluQv&26Dyhour_A>ABNqF4BYr-2%Qs^=US#qBbobL)7p``g-@|a888Z zIuJkg>@^R~i&%q<2^3zvEJn#YKe{%KcCG3=l!6Jls(s^Z32o!=JA0?ro9hyp;*5Cw z%T8Jg8e+JZ!FALa!83c_oDZQ{EqI847_@gJX-+%5s83P9F^*+|)^ss1jw4mCF3ydR zZ!Kwh&MdkdkA8+7oMUOc30!A8Ki9`bUb|n{iOLX5>m><2BZPUu`mrPt_ z;$JB}nwdrxw(IVBED!Yy?_4d!J6?Da*%En4Dpv2hR1-Bkd*`pmuMVdpErWN9uXe1T zW<%70ffQu-YurP!9WBC zl5vd&5L#9G({$L-A-6et$?>!7nGBQCGag&(ren8V{!j#A8t@00Ja-dM`P6NezXh@8 z71h{6@R~JYbU+CvM^muh@dj77;iXz$x~!-**%WU93WZRBS4Q^z&Lh)-ST4|{f`foq}nt)W9>mh(ugEQ>jj8rOE}2{PuP==VyfRK8Y1gdYof zHA}a+8IQbvjyZ_zY(|Gi3`-Zdr?Z)3t!UZIVįb%`RMVOqQCP~DZp5q>oy#3{8 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 ZA9PDa0SWofYiO_^2|NIh&-Ulv{{a7sVAB8q literal 0 HcmV?d00001