Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: change to aes-cbc encryption #23

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions fossa/100_config.ino
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ void setDefaultValues() {
Serial.println("Max amount: " + String(maxamount));
maxBeforeReset = MAX_BEFORE_RESET;
Serial.println("Max before reset: " + String(maxBeforeReset));
convertStringToFloatArray(COIN_AMOUNTS, coinAmountFloat);
Serial.println("Coin amounts: " + String(COIN_AMOUNTS));
}

void readFiles() {
Expand Down
12 changes: 10 additions & 2 deletions fossa/102_helpers.ino
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,20 @@ void splitSettings(String str) {
int firstComma = str.indexOf(',');
int secondComma = str.indexOf(',', firstComma + 1);
baseURLATM = str.substring(0, firstComma);
Serial.println("baseURLATM: " + baseURLATM);
// remove /api/v1.... and add /atm?lightning=
int apiPos = baseURLATM.indexOf("api");
baseUrlAtmPage = baseURLATM.substring(0, apiPos);
baseUrlAtmPage += "atm?lightning=";
Serial.println("baseUrlAtmPage: " + baseUrlAtmPage);
secretATM = str.substring(firstComma + 1, secondComma);
Serial.println("secretATM: " + secretATM);
currencyATM = str.substring(secondComma + 1);
Serial.println("currencyATM: " + currencyATM);
}

void convertStringToFloatArray(const char* str, float* floatArray) {
char buffer[20]; // Temporary buffer to hold each substring
char buffer[30]; // Temporary buffer to hold each substring
int index = 0; // Index for the float array
int bufferIndex = 0; // Index for the buffer

Expand All @@ -55,7 +63,7 @@ void convertStringToFloatArray(const char* str, float* floatArray) {
buffer[bufferIndex++] = str[i]; // Copy characters to buffer
}
}

// Don't forget to convert the last number in the string
buffer[bufferIndex] = '\0'; // Null-terminate the buffer
floatArray[index] = atof(buffer); // Convert buffer to float
Expand Down
101 changes: 35 additions & 66 deletions fossa/103_lnurl.ino
Original file line number Diff line number Diff line change
@@ -1,23 +1,40 @@
////////////////////////////////////////////
///////////////LNURL STUFF//////////////////
////USING STEPAN SNIGREVS GREAT CRYTPO//////
////////////THANK YOU STEPAN////////////////
////////////////////////////////////////////

void makeLNURL() {
int randomPin = random(1000, 9999);
byte nonce[8];
for (int i = 0; i < 8; i++) {
nonce[i] = random(256);
void encrypt(const char* key, unsigned char* iv, int length, const char* plainText, unsigned char* outputBuffer){
if (strlen(key) != 16) {
Serial.println("Key must be 16 bytes long. not " + String(strlen(key)) + " bytes.");
return;
}
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);
}

byte payload[51]; // 51 bytes is max one can get with xor-encryption

size_t payload_len = xor_encrypt(payload, sizeof(payload), (uint8_t *)secretATM.c_str(), secretATM.length(), nonce, sizeof(nonce), randomPin, float(total));
String preparedURL = baseURLATM + "?atm=1&p=";
preparedURL += toBase64(payload, payload_len, BASE64_URLSAFE | BASE64_NOPADDING);

bool makeLNURL() {
int iv_length = 16;
unsigned char iv_init[iv_length];
unsigned char iv[iv_length];
for (int i = 0; i < iv_length; i++) {
iv[i] = random(0, 255);
iv_init[i] = iv[i];
}
int randomPin = random(1000, 9999);
String payload = String(randomPin) + String(":") + String(total);
size_t payload_len = payload.length();
int padding = 16 - (payload_len % 16);
unsigned char encrypted[payload_len + padding] = {0};
encrypt(secretATM.c_str(), iv, payload_len + padding, payload.c_str(), encrypted);
String preparedURL = baseURLATM + "?p=";
preparedURL += toBase64(encrypted, payload_len, BASE64_URLSAFE | BASE64_NOPADDING);
preparedURL += "&iv=";
preparedURL += toBase64(iv_init, iv_length, BASE64_URLSAFE | BASE64_NOPADDING);
Serial.println(preparedURL);
lnurl_encode(preparedURL);
return true;
}

void lnurl_encode(String preparedURL) {
char Buf[200];
preparedURL.toCharArray(Buf, 200);
char *url = Buf;
Expand All @@ -27,54 +44,6 @@ void makeLNURL() {
char *charLnurl = (char *)calloc(strlen(url) * 2, sizeof(byte));
bech32_encode(charLnurl, "lnurl", data, len);
to_upper(charLnurl);
qrData = baseURLATM.substring(0, baseURLATM.length() - 18) + "atm" + "?lightning=" + charLnurl;
qrData = baseUrlAtmPage + charLnurl;
Serial.println(qrData);
}

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;
}
4 changes: 2 additions & 2 deletions fossa/105_display.ino
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ void feedmefiatloop() {
delay(100);
}

void qrShowCodeLNURL(String message) {
void qrShowCodeLNURL() {
#ifdef PRINTER
printMessage(printingT, waitT, "", TFT_WHITE, TFT_BLACK);
delay(3000);
Expand All @@ -59,7 +59,7 @@ void qrShowCodeLNURL(String message) {
tft.setCursor(40, 290);
tft.setTextSize(2);
tft.setTextColor(TFT_BLACK, TFT_WHITE);
tft.println(message);
tft.println(scanMeT);
delay(2000);
waitForTap = true;
while (waitForTap) {
Expand Down
102 changes: 67 additions & 35 deletions fossa/fossa.ino
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,30 @@
#include <SoftwareSerial.h>
#include <HardwareSerial.h>
#include <JC_Button.h>
#include <Hash.h>
#include <ArduinoJson.h>
#include "qrcoded.h"
#include "Bitcoin.h"
#include <Adafruit_Thermal.h>
#include <cstdlib>
#include <TFT_eSPI.h>
#include "mbedtls/aes.h"

#define FORMAT_ON_FAIL true
#define PARAM_FILE "/elements.json"

#include <TFT_eSPI.h>
#define VERSION "0.3.0"

//#define BILL_ACCEPTOR
#define BILL_RX 32 // RX Bill acceptor
#define BILL_TX 33 // TX Bill acceptor

//#define PRINTER
#define BILL_ACCEPTOR
#define COIN_ACCEPTOR
#define COIN_TX 34 // TX Coinmech
#define COIN_INHIBIT 35 // Coinmech interrupt

#define BTN1 39 // Screen tap button
#define BILL_RX 32 // RX Bill acceptor
#define BILL_TX 33 // TX Bill acceptor
#define COIN_TX 4 // TX Coinmech
#define COIN_INHIBIT 2 // Coinmech
#define PRINTER_RX 22 // RX of the thermal printer
#define PRINTER_TX 23 // TX of the thermal printer
//#define PRINTER
#define PRINTER_RX 22 // RX of the thermal printer
#define PRINTER_TX 23 // TX of the thermal printer

#define BTN1 21 // Screen tap button

// uncomment to use always hardcoded default settings
#define HARDCODED
Expand All @@ -35,7 +37,10 @@
#define CHARGE 10 // % you will charge people for service, set in LNbits extension
#define MAX_AMOUNT 30 // max amount per withdraw
#define MAX_BEFORE_RESET 300 // max amount you want to sell in the atm before having to reset power
#define DEVICE_STRING "https://XXXX.lnbits.com/fossa/api/v1/lnurl/XXXXX,XXXXXXXXXXXXXXXXXXXXXX,USD"
//#define DEVICE_STRING "https://XXXX.lnbits.com/fossa/api/v1/lnurl/XXXXX,XXXXXXXXXXXXXXXX,EUR"
#define DEVICE_STRING "https://test.b1tco1n.org/fossa/api/v1/lnurl/atm/T7HxgedvRJCZVHTm,9rtVvLAsx22hk9W6,USD"
#define COIN_AMOUNTS "0.05,1.0,0.25,0.5,0.1,2.0"
//#define BILL_AMOUNTS "0.01,0.05,0.1,0.25,0.5,1"

int billAmountInt[16];
float coinAmountFloat[6];
Expand All @@ -46,6 +51,7 @@ String language;
String deviceString;

String baseURLATM;
String baseUrlAtmPage;
String secretATM;
String currencyATM;

Expand Down Expand Up @@ -86,8 +92,10 @@ Adafruit_Thermal printer(&SerialPrinter);
TFT_eSPI tft = TFT_eSPI(TFT_WIDTH, TFT_HEIGHT);
Button BTNA(BTN1);


void setup() {
Serial.begin(115200);
Serial.println("Welcome to FOSSA, running on version: " + String(VERSION));
Serial.println("TFT: " + String(TFT_WIDTH) + "x" + String(TFT_HEIGHT));
Serial.println("TFT pin MISO: " + String(TFT_MISO));
Serial.println("TFT pin CS: " + String(TFT_CS));
Expand Down Expand Up @@ -116,21 +124,30 @@ void setup() {
readFiles();
translateAll(language);
# endif

splitSettings(deviceString);

BTNA.begin();
FlashFS.begin(FORMAT_ON_FAIL);

tft.init();
tft.setRotation(1);
tft.invertDisplay(false);

char buf[100];
sprintf(buf, "TFT (%dx%d) initialized.", TFT_WIDTH, TFT_HEIGHT);
Serial.println(buf);

printMessage("", "Loading..", "", TFT_WHITE, TFT_BLACK);
splitSettings(deviceString);

#ifdef BILL_ACCEPTOR
SerialBillAcceptor.begin(300, SERIAL_8N2, BILL_TX, BILL_RX);
SerialBillAcceptor.begin(300, SERIAL_8N2, BILL_RX, BILL_TX);
Serial.println("Bill Acceptor serial started.");
#endif
#ifdef COIN_ACCEPTOR
pinMode(COIN_TX, INPUT);
pinMode(COIN_INHIBIT, INPUT);
SerialCoinAcceptor.begin(4800, SERIAL_8N1, COIN_TX);
pinMode(COIN_INHIBIT, OUTPUT);
Serial.println("Coin Acceptor serial started.");
#endif
#ifdef PRINTER
Expand All @@ -141,24 +158,30 @@ void setup() {

void loop() {
if (maxBeforeResetTally >= maxBeforeReset) {
Serial.println("Max amount reached, please reset power.");
printMessage("", tooMuchFiatT, contactOwnerT, TFT_WHITE, TFT_BLACK);
delay(100000000);
} else {
#ifdef BILL_ACCEPTOR
SerialBillAcceptor.write(184);
digitalWrite(COIN_INHIBIT, HIGH);
#endif
#ifdef COIN_ACCEPTOR
digitalWrite(COIN_INHIBIT, LOW);
#endif
tft.fillScreen(TFT_BLACK);
BTNA.read(); // needed to clear accidental taps
moneyTimerFun();
Serial.println(total);
Serial.println(maxBeforeResetTally);
Serial.println("Total: " + String(total));
Serial.println("maxBeforeResetTally: " + String(maxBeforeResetTally));
maxBeforeResetTally = maxBeforeResetTally + (total / 100);
Serial.println(maxBeforeResetTally);
Serial.println("maxBeforeResetTally: " + String(maxBeforeResetTally));
makeLNURL();
qrShowCodeLNURL(scanMeT);
qrShowCodeLNURL();
}
}

void moneyTimerFun() {
Serial.println("Waiting for money...");
waitForTap = true;
coins = 0;
bills = 0;
Expand All @@ -171,10 +194,10 @@ void moneyTimerFun() {
feedmefiat();
feedmefiatloop();
}

#ifdef BILL_ACCEPTOR
if (SerialBillAcceptor.available()) {
int x = SerialBillAcceptor.read();

for (int i = 0; i < billAmountSize; i++) {
if ((i + 1) == x) {
bills = bills + billAmountInt[i];
Expand All @@ -183,24 +206,25 @@ void moneyTimerFun() {
}
}
}
// Turn off
SerialBillAcceptor.write(185);
#endif

#ifdef COIN_ACCEPTOR
if (SerialCoinAcceptor.available()) {
int x = SerialCoinAcceptor.read();
printMessage("", "WARNING: print bool", String(x), TFT_WHITE, TFT_BLACK);
delay(3000);
for (int i = 0; i < coinAmountSize; i++) {
if ((i + 1) == x) {
coins = coins + coinAmountFloat[i];
total = (coins + bills);
printMessage(coinAmountFloat[i] + currencyATM, totalT + String(total) + currencyATM, tapScreenT, TFT_WHITE, TFT_BLACK);
}
//printMessage("", "WARNING: print bool", String(x), TFT_WHITE, TFT_BLACK);
//delay(3000);
for (int i = 0; i < coinAmountSize; i++) {
if (i + 1 == x) {
coins = coins + coinAmountFloat[i];
total = (coins + bills);
String printCoin = coinAmountFloat[i] + currencyATM;
Serial.println("Coin inserted: " + String(i) + " -> " + printCoin);
String printTotal = totalT + String(total) + currencyATM;
Serial.println(printTotal);
printMessage(printCoin, printTotal, tapScreenT, TFT_WHITE, TFT_BLACK);
}
}
}
// Turn off
digitalWrite(COIN_INHIBIT, LOW);
#endif
BTNA.read();
if (BTNA.wasReleased() || total > maxamount) {
Expand All @@ -209,4 +233,12 @@ void moneyTimerFun() {
homeScreenNumColorCount++;
}
total = (coins + bills) * 100;
#ifdef BILL_ACCEPTOR
// Turn off
SerialBillAcceptor.write(185);
#endif
#ifdef COIN_ACCEPTOR
// Turn off
digitalWrite(COIN_INHIBIT, LOW);
#endif
}
Loading