Skip to content

feat: change to aes-cbc encryption #23

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

Open
wants to merge 7 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
139 changes: 76 additions & 63 deletions fossa/103_lnurl.ino
Original file line number Diff line number Diff line change
@@ -1,23 +1,84 @@
////////////////////////////////////////////
///////////////LNURL STUFF//////////////////
////USING STEPAN SNIGREVS GREAT CRYTPO//////
////////////THANK YOU STEPAN////////////////
////////////////////////////////////////////
void encrypt(unsigned 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, key, 256); // AES-256 requires a 32-byte key
mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, length, iv, (const unsigned char*)plainText, outputBuffer);
mbedtls_aes_free(&aes);
}

void deriveKeyAndIV(const char* secret, unsigned char* salt, unsigned char* outputBuffer) {
mbedtls_md5_context md5_ctx;
unsigned char data[24]; // 16 bytes key + 8 bytes salt
unsigned char md5Output[16]; // 16 bytes for MD5 output

memcpy(data, secret, 16);
memcpy(data + 16, salt, 8);

// first iteration
mbedtls_md5_init(&md5_ctx);
mbedtls_md5_update(&md5_ctx, data, sizeof(data));
mbedtls_md5_finish(&md5_ctx, md5Output);

// Copy the first 16 bytes to the output buffer for the key
memcpy(outputBuffer, md5Output, 16);

unsigned char data_md5[16 + 16 + 8]; // 16 bytes md5 output + 16 bytes key + 8 bytes salt

for (int i = 16; i <= 48; i+=16) {
memcpy(data_md5, md5Output, 16);
memcpy(data_md5 + 16, data, 24);
mbedtls_md5_init(&md5_ctx);
mbedtls_md5_update(&md5_ctx, data_md5, sizeof(data_md5));
mbedtls_md5_finish(&md5_ctx, md5Output);
// Copy the next 16 bytes to the output buffer
memcpy(outputBuffer + i, md5Output, 16);
}

mbedtls_md5_free(&md5_ctx);
}


bool makeLNURL() {
int salt_length = 8;
unsigned char salt[salt_length];
for (int i = 0; i < salt_length; i++) {
salt[i] = random(0, 255);
}
unsigned char keyIV[32 + 16] = {0};
deriveKeyAndIV(secretATM.c_str(), salt, keyIV);

unsigned char key[32] = {0};
unsigned char iv[16] = {0};

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

String payload = String(randomPin) + String(":") + String(total);
size_t payload_len = payload.length();
int padding = 16 - (payload_len % 16);
payload_len += padding;
for (int i = 0; i < padding; i++) {
payload += String((char)padding);
}

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);
unsigned char encrypted[payload_len] = {0};
encrypt(key, iv, payload_len, payload.c_str(), encrypted);

const unsigned char *saltedChars = (const unsigned char *)"Salted__";
unsigned char salted[payload_len + 16];
memcpy(salted, saltedChars, 8);
memcpy(salted + 8, salt, salt_length);
memcpy(salted + 16, encrypted, payload_len);

String preparedURL = baseURLATM + "?p=";
preparedURL += toBase64(salted, payload_len+16, BASE64_URLSAFE);

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 +88,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
Loading