mirror of
https://github.com/0x5eal/wg-lua.git
synced 2025-01-07 11:49:10 +00:00
Erica Marigold
666a5f79e8
`Wireguard:generatePublicKey` now accepts the privateKey as a base64 encoded string, which gets decoded internally to produce the raw bytes.
104 lines
3.1 KiB
TypeScript
104 lines
3.1 KiB
TypeScript
const { toBinary, getCharAt } = require<{
|
|
toBinary: (int: number) => string;
|
|
getCharAt: (str: string, pos: number) => string;
|
|
}>("./util.lua");
|
|
|
|
const BASE64_CHAR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
|
// Adapted from https://gist.github.com/jonleighton/958841
|
|
export function encode(buf: number[]): string {
|
|
let base64 = "";
|
|
|
|
const byteLength = buf.size();
|
|
const byteRemainder = byteLength % 3;
|
|
const mainLength = byteLength - byteRemainder;
|
|
|
|
let a: number, b: number, c: number, d: number;
|
|
let chunk;
|
|
|
|
// Main loop deals with bytes in chunks of 3
|
|
for (let i = 0; i < mainLength; i = i + 3) {
|
|
// Combine the three bytes into a single integer
|
|
chunk = (buf[i] << 16) | (buf[i + 1] << 8) | buf[i + 2];
|
|
|
|
// Use bitmasks to extract 6-bit segments from the triplet
|
|
a = (chunk & 16515072) >> 18;
|
|
b = (chunk & 258048) >> 12;
|
|
c = (chunk & 4032) >> 6;
|
|
d = chunk & 63;
|
|
|
|
// Convert the raw binary segments to the appropriate ASCII encoding
|
|
base64 +=
|
|
string.char(string.byte(BASE64_CHAR, a + 1)[0]) +
|
|
string.char(string.byte(BASE64_CHAR, b + 1)[0]) +
|
|
string.char(string.byte(BASE64_CHAR, c + 1)[0]) +
|
|
string.char(string.byte(BASE64_CHAR, d + 1)[0]);
|
|
}
|
|
|
|
// Deal with the remaining bytes and padding
|
|
if (byteRemainder === 1) {
|
|
chunk = buf[mainLength];
|
|
|
|
a = (chunk & 252) >> 2;
|
|
|
|
// Set the 4 least significant bits to zero
|
|
b = (chunk & 3) << 4;
|
|
|
|
base64 += string.byte(BASE64_CHAR, a)[0] + string.byte(BASE64_CHAR, b)[0] + "==";
|
|
} else if (byteRemainder === 2) {
|
|
chunk = (buf[mainLength] << 8) | buf[mainLength + 1];
|
|
|
|
a = (chunk & 64512) >> 10;
|
|
b = (chunk & 1008) >> 4;
|
|
|
|
// Set the 2 least significant bits to zero
|
|
c = (chunk & 15) << 2;
|
|
|
|
base64 +=
|
|
string.char(string.byte(BASE64_CHAR, a + 1)[0]) +
|
|
string.char(string.byte(BASE64_CHAR, b + 1)[0]) +
|
|
string.char(string.byte(BASE64_CHAR, c + 1)[0]) +
|
|
"=";
|
|
}
|
|
|
|
return base64;
|
|
}
|
|
|
|
// FIXME: Ideally, you'd want to use bit math and mask off bytes and stuff,
|
|
// but I'm lazy, so this logic uses string manipulation instead
|
|
export function decode(base64: string): number[] {
|
|
// Strip padding from base64
|
|
base64 = base64.split("=")[0].gsub("%s", "")[0];
|
|
|
|
// Convert base64 chars to lookup table offsets
|
|
const chars = [];
|
|
for (let i = 1; i <= base64.size(); i++) {
|
|
const char = getCharAt(base64, i);
|
|
const [pos] = string.find(BASE64_CHAR, char);
|
|
|
|
pos !== undefined ? chars.push(pos - 1) : error("invalid base64 data");
|
|
}
|
|
|
|
// Convert offsets to 6 bit binary numbers
|
|
const bin = chars.map(toBinary);
|
|
|
|
// Combine all binary numbers into one
|
|
let combinedBin = "";
|
|
bin.forEach((b) => (combinedBin += b));
|
|
|
|
// Split the combined binary number into smaller ones of 8 bits each
|
|
const intermediaryBin = [];
|
|
while (combinedBin.size() > 0) {
|
|
intermediaryBin.push(string.sub(combinedBin, 1, 8));
|
|
combinedBin = string.sub(combinedBin, 9, combinedBin.size());
|
|
}
|
|
|
|
// Convert each individual 8 bit binary number to a base 10 integer
|
|
const decoded = [];
|
|
for (let i = 0; i < intermediaryBin.size() - 1; i++) {
|
|
const byte = tonumber(intermediaryBin[i], 2);
|
|
decoded.push(byte !== undefined ? byte : error("got invalid byte while decoding base64"));
|
|
}
|
|
|
|
return decoded;
|
|
}
|