Skip to content

Commit

Permalink
feat: change to aes-cbc encryption
Browse files Browse the repository at this point in the history
  • Loading branch information
dni committed Feb 25, 2025
1 parent a9b195c commit c70fb99
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 80 deletions.
8 changes: 8 additions & 0 deletions debug.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
arduino-cli compile \
--build-property "build.partitions=min_spiffs" \
--build-property "upload.maximum_size=1966080" \
--library ./libraries/TFT_eSPI \
--library ./libraries/QRCode \
--build-path build --fqbn esp32:esp32:ttgo-lora32 lnpos && \
arduino-cli upload --input-dir build --fqbn esp32:esp32:ttgo-lora32 -p /dev/ttyACM0 && \
arduino-cli monitor -p /dev/ttyACM0 -c baudrate=115200
3 changes: 1 addition & 2 deletions lnpos/100_config.ino
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ void readFiles()
secretPoS = getValue(lnurlPoS, ',', 1);
currencyPoS = getValue(lnurlPoS, ',', 2);
Serial.println("");
Serial.println("lnurlPoS used");
Serial.println("lnurlPoS: " + lnurlPoS);
if (secretPoS != "")
{
Expand All @@ -164,7 +163,7 @@ void readFiles()
secretATM = getValue(lnurlATM, ',', 1);
currencyATM = getValue(lnurlATM, ',', 2);
Serial.println("");
Serial.println("lnurlATM: " + lnurlATM);
Serial.println("lnurlATM: " + baseURLATM);
if (secretATM != "")
{
menuItemCheck[3] = 1;
Expand Down
142 changes: 64 additions & 78 deletions lnpos/lnpos.ino
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ fs::SPIFFSFS &FlashFS = SPIFFS;
#include <stdio.h>
#include "qrcoded.h"
#include <WiFiClientSecure.h>
#include "mbedtls/aes.h"

// ArduinoJson, Keypad and uBitcoin should be installed using the Arduino Library Manager.
// The latest versions should work, verified with ArduinoJson 7.2.1, Keypad 3.1.1 and uBitcoin 0.2.0
Expand All @@ -23,7 +24,6 @@ fs::SPIFFSFS &FlashFS = SPIFFS;
#define USB_POWER 1000 // battery percentage sentinel value to indicate USB power

//////////SET TO TRUE TO WIPE MEMORY//////////////

bool format = false;

////////////////////////////////////////////////////////
Expand Down Expand Up @@ -80,7 +80,7 @@ const char currencyItems[3][5] = {"sat", "USD", "EUR"};
char decimalplacesOutput[20];
int menuItemCheck[5] = {0, 0, 0, 0, 1};
int menuItemNo = 0;
int randomPin;
String randomPin;
int calNum = 1;
int sumFlag = 0;
int converted = 0;
Expand Down Expand Up @@ -931,9 +931,9 @@ void qrShowCodeln()
qrData.toUpperCase();
const char *qrDataChar = qrData.c_str();
QRCode qrcoded;
uint8_t qrcodeData[qrcode_getBufferSize(20)];
uint8_t qrcodeData[qrcode_getBufferSize(32)];

qrcode_initText(&qrcoded, qrcodeData, 11, 0, qrDataChar);
qrcode_initText(&qrcoded, qrcodeData, 32, 0, qrDataChar);

for (uint8_t y = 0; y < qrcoded.size; y++)
{
Expand Down Expand Up @@ -1011,20 +1011,24 @@ void qrShowCodeLNURL(String message)
qrData.toUpperCase();
const char *qrDataChar = qrData.c_str();
QRCode qrcoded;
uint8_t qrcodeData[qrcode_getBufferSize(20)];
qrcode_initText(&qrcoded, qrcodeData, 6, 0, qrDataChar);
uint8_t qrcodeData[qrcode_getBufferSize(11)];
qrcode_initText(&qrcoded, qrcodeData, 11, 0, qrDataChar);

unsigned int pixSize = 2;
unsigned int offsetTop = 3;
unsigned int offsetLeft = 65;

for (uint8_t y = 0; y < qrcoded.size; y++)
{
for (uint8_t x = 0; x < qrcoded.size; x++)
{
if (qrcode_getModule(&qrcoded, x, y))
{
tft.fillRect(65 + 3 * x, 5 + 3 * y, 3, 3, TFT_BLACK);
tft.fillRect(offsetLeft + pixSize * x, offsetTop + pixSize * y, pixSize, pixSize, TFT_BLACK);
}
else
{
tft.fillRect(65 + 3 * x, 5 + 3 * y, 3, 3, qrScreenBgColour);
tft.fillRect(offsetLeft + pixSize * x, offsetTop + pixSize * y, pixSize, pixSize, qrScreenBgColour);
}
}
}
Expand Down Expand Up @@ -1579,43 +1583,68 @@ void to_upper(char *arr)

bool makeLNURL()
{
if (amountToShow.toFloat() == 0)
if (amountToShow.toFloat() <= 0)
{
error("ZERO VALUE");
error("ZERO AMOUNT");
delay(3000);
return false;
}

randomPin = random(1000, 9999);
byte nonce[8];
for (int i = 0; i < 8; i++)
{
nonce[i] = random(256);
}

int multipler = pow(10, 2);

if (currencyPoS == "sat")
{
multipler = 1;
}

float total = amountToShow.toFloat() * multipler;

byte payload[51]; // 51 bytes is max one can get with xor-encryption
//const char* key = "Yq3t6w9z$C&F)J@M";

unsigned char iv_init[16];
unsigned char iv[16];

for (int i = 0; i < 16; i++) {
iv[i] = random(0, 255);
iv_init[i] = iv[i];
}

if (selection == "Offline PoS")
{
size_t payload_len = xor_encrypt(payload, sizeof(payload), (uint8_t *)secretPoS.c_str(), secretPoS.length(), nonce, sizeof(nonce), randomPin, total);
preparedURL = baseURLPoS + "?p=";
preparedURL += toBase64(payload, payload_len, BASE64_URLSAFE | BASE64_NOPADDING);
randomPin = String(random(1000, 9999));
preparedURL = baseURLATM;
}
else // ATM
{
size_t payload_len = xor_encrypt(payload, sizeof(payload), (uint8_t *)secretATM.c_str(), secretATM.length(), nonce, sizeof(nonce), randomPin, total);
preparedURL = baseURLATM + "?atm=1&p=";
preparedURL += toBase64(payload, payload_len, BASE64_URLSAFE | BASE64_NOPADDING);
randomPin = String("FFFF");
preparedURL = baseURLATM + "/atm/";
}
preparedURL += "?p=";

String payload = randomPin + String(":") + String(total);
Serial.print("payload: ");
Serial.println(payload);
size_t payload_len = payload.length();
int padding = 16 - (payload_len % 16);
unsigned char encrypted[payload_len + padding] = {0};
String s = "";
encrypt(secretATM.c_str(), iv, payload_len + padding, payload.c_str(), encrypted);
for (int i = 0; i < sizeof(encrypted); i++) {
s = String(encrypted[i], HEX);
if (s.length() == 1) {
s = "0" + s;
}
preparedURL += s;
}
// append iv to the url
preparedURL += "&iv=";
for (int i = 0; i < sizeof(iv_init); i++) {
s = String(iv_init[i], HEX);
if (s.length() == 1) {
s = "0" + s;
}
preparedURL += s;
}

Serial.println();
Serial.println(preparedURL);
char Buf[200];
preparedURL.toCharArray(Buf, 200);
Expand All @@ -1632,58 +1661,6 @@ bool makeLNURL()
return true;
}

int xor_encrypt(uint8_t *output, size_t outlen, uint8_t *key, size_t keylen, uint8_t *nonce, size_t nonce_len, uint64_t pin, uint64_t amount_in_cents)
{
// check we have space for all the data:
// <variant_byte><len|nonce><len|payload:{pin}{amount}><hmac>
if (outlen < 2 + nonce_len + 1 + lenVarInt(pin) + 1 + lenVarInt(amount_in_cents) + 8)
{
return 0;
}

int cur = 0;
output[cur] = 1; // variant: XOR encryption
cur++;

// nonce_len | nonce
output[cur] = nonce_len;
cur++;
memcpy(output + cur, nonce, nonce_len);
cur += nonce_len;

// payload, unxored first - <pin><currency byte><amount>
int payload_len = lenVarInt(pin) + 1 + lenVarInt(amount_in_cents);
output[cur] = (uint8_t)payload_len;
cur++;
uint8_t *payload = output + cur; // pointer to the start of the payload
cur += writeVarInt(pin, output + cur, outlen - cur); // pin code
cur += writeVarInt(amount_in_cents, output + cur, outlen - cur); // amount
cur++;

// xor it with round key
uint8_t hmacresult[32];
SHA256 h;
h.beginHMAC(key, keylen);
h.write((uint8_t *)"Round secret:", 13);
h.write(nonce, nonce_len);
h.endHMAC(hmacresult);
for (int i = 0; i < payload_len; i++)
{
payload[i] = payload[i] ^ hmacresult[i];
}

// add hmac to authenticate
h.beginHMAC(key, keylen);
h.write((uint8_t *)"Data:", 5);
h.write(output, cur);
h.endHMAC(hmacresult);
memcpy(output + cur, hmacresult, 8);
cur += 8;

// return number of bytes written to the output
return cur;
}

unsigned int getBatteryPercentage()
{
const float batteryMaxVoltage = 4.2;
Expand Down Expand Up @@ -1900,3 +1877,12 @@ void printSleepAnimationFrame(String text, int wait)
tft.println(text);
delay(wait);
}

//////////ENCRYPTION///////////////
void encrypt(const char* key, unsigned char* iv, int length, const char* plainText, unsigned char* outputBuffer){
mbedtls_aes_context aes;
mbedtls_aes_init(&aes);
mbedtls_aes_setkey_enc(&aes, (const unsigned char*)key, strlen(key)*8);
mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, length, iv, (const unsigned char*)plainText, outputBuffer);
mbedtls_aes_free(&aes);
}

0 comments on commit c70fb99

Please sign in to comment.