From: miha-q <> Date: Mon, 20 Jan 2025 20:08:09 +0000 (-0500) Subject: Mon Jan 20 03:08:09 PM EST 2025 X-Git-Url: http://www.foleosoft.com/?a=commitdiff_plain;h=c7684353c2036f0f1faa0ae83f5d495a5bc90ceb;p=RosadoAPI.git Mon Jan 20 03:08:09 PM EST 2025 --- diff --git a/build.sh b/build.sh index 514cc74..3f2cfeb 100644 --- a/build.sh +++ b/build.sh @@ -1,10 +1,10 @@ #!/bin/bash if [ "$1" == "run" ] then - while [ 1 ] - do - ./bin/rosado - done + while [ 1 ] + do + ./bin/rosado + done elif [ "$1" = "install" ] then sudo cp bin/rosado /usr/local/bin/rosado @@ -12,8 +12,12 @@ elif [ "$1" = "uninstall" ] then sudo rm /usr/local/bin/rosado else - xxd -i ./rcs/frontend.html ./src/frontend.h - gcc ./src/main.c -o ./bin/rosado $(mysql_config --cflags --libs) -lCryptoFoleo - rm ./src/frontend.h - cp ./rcs/* ./bin/ + + python << EOF | xxd -i > src/frontend.h +with open("src/www/frontend.html", "r") as f1: + with open("src/www/rosado-api.js", "r") as f2: + print(f1.read().replace(" src=\"rosado-api.js\">", ">\n" + f2.read() + "\n")) +EOF + gcc ./src/main.c -o ./bin/rosado $(mysql_config --cflags --libs) -lCryptoFoleo + rm ./src/frontend.h fi diff --git a/src/main.c b/src/main.c index 50ecbfa..b42318d 100644 --- a/src/main.c +++ b/src/main.c @@ -3,7 +3,6 @@ #include #include #include "http.c" -#include "frontend.h" #include "CryptoFoleo.h" uint8_t HOSTNAME[1024]; @@ -11,6 +10,11 @@ uint8_t HOSTNAME_I[1024]; uint8_t SQLPASS[1024]; uint8_t WEBPORT[1024]; +uint8_t FRONTEND[] = +{ +#include "frontend.h" +}; + //grabs auth info from the database uint8_t* getDatabaseInfo(uint8_t type, uint8_t* a, uint8_t* b, uint8_t* c) { @@ -346,9 +350,9 @@ void *handleRequest(void *vargp) info = httpParse("Path", buff, buff_len); if ( strcmp(info, "/") == 0 ) { - uint8_t* frontend = malloc(__rcs_frontend_html_len + 1); - memcpy(frontend, __rcs_frontend_html, __rcs_frontend_html_len); - frontend[__rcs_frontend_html_len] = 0; + uint8_t* frontend = malloc(sizeof(FRONTEND) + 1); + memcpy(frontend, FRONTEND, sizeof(FRONTEND)); + frontend[sizeof(FRONTEND)] = 0; httpStringOut(session_fd, frontend); free(frontend); } diff --git a/src/www/favicon.ico b/src/www/favicon.ico index e33686d..96c484b 100644 Binary files a/src/www/favicon.ico and b/src/www/favicon.ico differ diff --git a/src/www/frontend.html b/src/www/frontend.html index b77d983..f132617 100644 --- a/src/www/frontend.html +++ b/src/www/frontend.html @@ -1,1069 +1,99 @@ - - EstoulsAPI - - - - + + + +

 RosadoAPI

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Address:
Service:
Username:
Authkey:
Request:
Response:
+ - - - - - -
- -
-    -    -    - - -    -
  
- -
- - - - - - -
1
-
-
-
-
-
-
- - - - + $("#resp").value = ""; + }); + + + diff --git a/src/www/rosado-api.js b/src/www/rosado-api.js new file mode 100644 index 0000000..d126d61 --- /dev/null +++ b/src/www/rosado-api.js @@ -0,0 +1,358 @@ +var RosadoAPI = +{ + username: undefined, + apikey: undefined, + endpoint: undefined, + + Math32: + { + clamp: a => + { + while (a < 0 || a > 0xFFFFFFFF) + a += a < 0 ? 0x100000000 : -0x100000000; + return a; + }, + shl: (a, b) => RosadoAPI.Math32.clamp(a << b), + shr: (a, b) => RosadoAPI.Math32.clamp(a >>> b), + rtl: (a, b) => RosadoAPI.Math32.clamp((a << b) | (a >>> (32 - b))), + rtr: (a, b) => RosadoAPI.Math32.clamp((a >>> b) | (a << (32 - b))), + add: (a, b) => RosadoAPI.Math32.clamp(a + b), + sub: (a, b) => RosadoAPI.Math32.clamp(a + b), + or: (a, b) => RosadoAPI.Math32.clamp(a | b), + xor: (a, b) => RosadoAPI.Math32.clamp(a ^ b) + }, + HMACSHA256: + { + sign: async (key, msg) => + { + key = new Uint8Array(key); + msg = new Uint8Array(msg); + var ikey = await crypto.subtle.importKey + ( + "raw", + key, + { name: "HMAC", hash: { name: "SHA-256" }}, + false, + ["sign", "verify"] + ); + return new Uint8Array(await window.crypto.subtle.sign({ name: "HMAC", }, ikey, msg)); + } + }, + ChaCha20: + { + QR: (cc, a, b, c, d) => + { + cc[a] = RosadoAPI.Math32.add(cc[a], cc[b]); + cc[d] = RosadoAPI.Math32.xor(cc[d], cc[a]); + cc[d] = RosadoAPI.Math32.rtl(cc[d], 16); + + cc[c] = RosadoAPI.Math32.add(cc[c], cc[d]); + cc[b] = RosadoAPI.Math32.xor(cc[b], cc[c]); + cc[b] = RosadoAPI.Math32.rtl(cc[b], 12); + + cc[a] = RosadoAPI.Math32.add(cc[a], cc[b]); + cc[d] = RosadoAPI.Math32.xor(cc[d], cc[a]); + cc[d] = RosadoAPI.Math32.rtl(cc[d], 8); + + cc[c] = RosadoAPI.Math32.add(cc[c], cc[d]); + cc[b] = RosadoAPI.Math32.xor(cc[b], cc[c]); + cc[b] = RosadoAPI.Math32.rtl(cc[b], 7); + }, + DR: (cc) => + { + RosadoAPI.ChaCha20.QR(cc, 0, 4, 8, 12); + RosadoAPI.ChaCha20.QR(cc, 1, 5, 9, 13); + RosadoAPI.ChaCha20.QR(cc, 2, 6, 10, 14); + RosadoAPI.ChaCha20.QR(cc, 3, 7, 11, 15); + RosadoAPI.ChaCha20.QR(cc, 0, 5, 10, 15); + RosadoAPI.ChaCha20.QR(cc, 1, 6, 11, 12); + RosadoAPI.ChaCha20.QR(cc, 2, 7, 8, 13); + RosadoAPI.ChaCha20.QR(cc, 3, 4, 9, 14); + }, + CB: (cc) => + { + var i; + var x = new Array(16); + for (i = 0; i < 16; i++) + { + x[i] = cc[i]; + } + for (i = 0; i < 10; i++) + { + RosadoAPI.ChaCha20.DR(cc); + } + for (i = 0; i < 16; i++) + { + cc[i] = RosadoAPI.Math32.add(cc[i], x[i]); + } + }, + S: (cc, cs) => + { + for (var i = 0; i < 16; i++) + { + cs[4 * i] = (cc[i] & 0xFF); + cs[4 * i + 1] = ((cc[i] >> 8) & 0xFF); + cs[4 * i + 2] = ((cc[i] >> 16) & 0xFF); + cs[4 * i + 3] = ((cc[i] >> 24) & 0xFF); + } + }, + B: (key, nonce, block, out) => + { + var cc = + [ + 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574, + + key[0] | (key[1] << 8) | (key[2] << 16) | (key[3] << 24), + key[4] | (key[5] << 8) | (key[6] << 16) | (key[7] << 24), + key[8] | (key[9] << 8) | (key[10] << 16) | (key[11] << 24), + key[12] | (key[13] << 8) | (key[14] << 16) | (key[15] << 24), + + key[16] | (key[17] << 8) | (key[18] << 16) | (key[19] << 24), + key[20] | (key[21] << 8) | (key[22] << 16) | (key[23] << 24), + key[24] | (key[25] << 8) | (key[26] << 16) | (key[27] << 24), + key[28] | (key[29] << 8) | (key[30] << 16) | (key[31] << 24), + + block, + + nonce[0] | (nonce[1] << 8) | (nonce[2] << 16) | (nonce[3] << 24), + nonce[4] | (nonce[5] << 8) | (nonce[6] << 16) | (nonce[7] << 24), + nonce[8] | (nonce[9] << 8) | (nonce[10] << 16) | (nonce[11] << 24) + ]; + + RosadoAPI.ChaCha20.CB(cc); + RosadoAPI.ChaCha20.S(cc, out); + }, + encrypt: async (key, nonce, block, data) => + { + var count = data.length; + if (count > (274877906944 - block * 64)) return null; + var ret = new Array(0); + var ccblock = new Array(64); + var size = 0; + while (count > 64) + { + ret.length = size + 64; + RosadoAPI.ChaCha20.B(key, nonce, block++, ccblock); + for (var i = 0; i < 64; i++) ret[size + i] = ccblock[i]; + size += 64; + count -= 64; + } + if (count > 0) + { + ret.length = size + count; + RosadoAPI.ChaCha20.B(key, nonce, block, ccblock); + for (var i = 0; i < count; i++) ret[size + i] = ccblock[i]; + } + for (var i = 0; i < data.length; i++) ret[i] ^= data[i]; + return new Uint8Array(ret); + } + }, + + Base64: + { + encode: async (x) => + { + return await new Promise(r => + { + const reader = new FileReader(); + reader.addEventListener("load", () => r(reader.result.split(",")[1])); + reader.readAsDataURL(new Blob([new Uint8Array(x)])); + }); + }, + + decode: (b64) => + { + var dec1 = (v) => + { + switch (v) + { + case 'A': return 0; + case 'B': return 1; + case 'C': return 2; + case 'D': return 3; + case 'E': return 4; + case 'F': return 5; + case 'G': return 6; + case 'H': return 7; + case 'I': return 8; + case 'J': return 9; + case 'K': return 10; + case 'L': return 11; + case 'M': return 12; + case 'N': return 13; + case 'O': return 14; + case 'P': return 15; + case 'Q': return 16; + case 'R': return 17; + case 'S': return 18; + case 'T': return 19; + case 'U': return 20; + case 'V': return 21; + case 'W': return 22; + case 'X': return 23; + case 'Y': return 24; + case 'Z': return 25; + case 'a': return 26; + case 'b': return 27; + case 'c': return 28; + case 'd': return 29; + case 'e': return 30; + case 'f': return 31; + case 'g': return 32; + case 'h': return 33; + case 'i': return 34; + case 'j': return 35; + case 'k': return 36; + case 'l': return 37; + case 'm': return 38; + case 'n': return 39; + case 'o': return 40; + case 'p': return 41; + case 'q': return 42; + case 'r': return 43; + case 's': return 44; + case 't': return 45; + case 'u': return 46; + case 'v': return 47; + case 'w': return 48; + case 'x': return 49; + case 'y': return 50; + case 'z': return 51; + case '0': return 52; + case '1': return 53; + case '2': return 54; + case '3': return 55; + case '4': return 56; + case '5': return 57; + case '6': return 58; + case '7': return 59; + case '8': return 60; + case '9': return 61; + case '+': return 62; + case '/': return 63; + } + return 255; + }; + + var ret = new Array(0); + var buffer = 0; + var bufferS = 0; + for (var i = 0; i < b64.length; i++) + { + if (b64[i] == '=') { bufferS = 0; continue; }; + var val = dec1(b64[i]); + if (val == 255) return null; + buffer = ((buffer << 6) | val) & 0xFFFF; + bufferS += 6; + if (bufferS >= 8) + { + var shift = (16 - bufferS) & 0xFF; + buffer = (buffer << shift) & 0xFFFF; + ret[ret.length] = (buffer >>> 8) & 0xFF; + buffer = buffer & 0x00FF; + buffer = (buffer >>> shift) & 0xFFFF; + bufferS -= 8; + } + } + if (bufferS > 0) + { + buffer = (buffer << (16 - bufferS)) & 0xFFFF; + ret[ret.length] = (buffer >>> 8) & 0xFF; + } + return new Uint8Array(ret); + } + }, + + Hex: + { + encode: (x) => + { + var ret = ""; + x.forEach(y => { ret += y.toString(16).padStart(2, "0"); }); + return ret; + }, + decode: (x) => + { + var arr = new Array(0); + for (var i = 0; i < x.length; i += 2) + { + arr[arr.length] = parseInt(x.charAt(i) + x.charAt(i + 1), 16); + } + return new Uint8Array(arr); + } + }, + + generateRequest: async (msg) => + { + msg = new TextEncoder().encode(msg); + var key = RosadoAPI.Hex.decode(RosadoAPI.apikey); + //var sess = crypto.getRandomValues(new Uint8Array(12)); + var r = () => { return Math.floor(Math.random() * 10000) % 256 };; + var sess = new Uint8Array([r(), r(), r(), r(), r(), r(), r(), r(), r(), r(), r(), r()]); + var rawdata = await RosadoAPI.ChaCha20.encrypt(key, sess, 0, msg); + var dgst = await RosadoAPI.Hex.encode(await RosadoAPI.HMACSHA256.sign(key, rawdata)); + var data = await RosadoAPI.Base64.encode(rawdata); + var resp = "user=" + RosadoAPI.username; + resp += "&sess=" + RosadoAPI.Hex.encode(sess); + resp += "&dgst=" + dgst; + resp += "&data=" + data; + return resp; + }, + + parseResponse: async (msg) => + { + if (!msg.includes("user=") || !msg.includes("&sess=") || !msg.includes("&dgst=") || !msg.includes("&data=")) + { + return { success: false, response: "invalid response" }; + } + var user = msg.split("user=")[1].split("&")[0].trim(); + var sess = msg.split("&sess=")[1].split("&")[0].trim(); + var dgst = msg.split("&dgst=")[1].split("&")[0].trim(); + var data = msg.split("&data=")[1].split("&")[0].trim(); + + if (user != RosadoAPI.username) + { + return { success: false, response: "invalid user in response" }; + } + data = RosadoAPI.Base64.decode(data); + sess = RosadoAPI.Hex.decode(sess); + var key = RosadoAPI.Hex.decode(RosadoAPI.apikey); + var sig = await RosadoAPI.Hex.encode(await RosadoAPI.HMACSHA256.sign(key, data)); + if (sig != dgst) + { + return { success: false, response: "invalid signature" }; + } + var resp = await RosadoAPI.ChaCha20.encrypt(key, sess, 0, data); + resp = new TextDecoder().decode(resp); + resp = resp ? resp : "(null)"; + return { success: true, response: resp }; + }, + + request: async (msg) => + { + if (msg.trim().length == 0) return { success: true, response: "" }; + var req = await RosadoAPI.generateRequest(msg); + return await new Promise(r => + { + const xhr = new XMLHttpRequest(); + xhr.open("POST", RosadoAPI.endpoint, true); + xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); + xhr.onreadystatechange = (x) => + { + if (xhr.readyState === XMLHttpRequest.DONE) + { + if (xhr.status === 200) + { + RosadoAPI.parseResponse(xhr.responseText).then(pr => { r(pr); }).catch(x => alert("ERR(3)")); + } + else + { + r({success: false, response: xhr.status.toString()}); + } + } + } + xhr.send(req); + }).catch(x => alert("ERR(1): " + x)); + } +}; +