mirror of
https://gitlab.com/jusax23/ilmk.git
synced 2024-11-22 06:36:42 +01:00
353 lines
12 KiB
JavaScript
353 lines
12 KiB
JavaScript
var node = false;
|
|
var crypto;
|
|
|
|
if (typeof process != "undefined") {
|
|
crypto = await import('crypto');
|
|
if(typeof crypto.webcrypto != "undefined"){
|
|
crypto = crypto.webcrypto;
|
|
console.log("ilmk: using subtle");
|
|
}else{
|
|
node = true;
|
|
console.log("ilmk: using node crypto");
|
|
}
|
|
}else{
|
|
crypto = window.crypto;
|
|
}
|
|
|
|
var asciiList = [];
|
|
for (var i = 0; i < 256; i++) {
|
|
asciiList[i]=String.fromCharCode(i);
|
|
}
|
|
|
|
|
|
const C = {
|
|
sha256: async (msgBuffer) => {
|
|
return node ? new Uint8Array(crypto.createHash("sha256").update(msgBuffer).digest()) :
|
|
new Uint8Array(await crypto.subtle.digest('SHA-256', msgBuffer));
|
|
},
|
|
random: async (length) => {
|
|
return node ? crypto.randomFillSync(new Uint8Array(length)) :
|
|
crypto.getRandomValues(new Uint8Array(length));
|
|
},
|
|
randomKey: async (length) => {
|
|
return C.decode(await C.random(length));
|
|
},
|
|
encode : (data)=>{
|
|
console.log(data);
|
|
if(node){
|
|
return new Uint8Array(Buffer.from(data,"binary"));
|
|
}else{
|
|
var out = new Uint8Array(data.length);
|
|
for (var i = 0; i < data.length; i++) {
|
|
out[i] = data.charCodeAt(i);
|
|
}
|
|
return out;//new Uint8Array(data.split("").map(d => d.charCodeAt(0)));
|
|
}
|
|
},
|
|
decode : (data)=>{
|
|
if(node){
|
|
return Buffer.from(data).toString("binary");
|
|
}else{
|
|
var out = [];
|
|
var i = 0;
|
|
var limit = i - (i%16);
|
|
while (i < limit) {
|
|
out.push(asciiList[data[i]]+asciiList[data[i+1]]+asciiList[data[i+2]]+asciiList[data[i+3]]+asciiList[data[i+4]]+asciiList[data[i+5]]+asciiList[data[i+6]]+asciiList[data[i+7]]+asciiList[data[i+8]]+asciiList[data[i+9]]+asciiList[data[i+10]]+asciiList[data[i+11]]+asciiList[data[i+12]]+asciiList[data[i+13]]+asciiList[data[i+14]]+asciiList[data[i+15]]);
|
|
i+=16;
|
|
}
|
|
while (i < data.length) {
|
|
out.push(asciiList[data[i]]);
|
|
i++;
|
|
}
|
|
return out.join("");
|
|
}
|
|
},
|
|
atob: (data)=>node?Buffer.from(data,"base64").toString("binary"):atob(data), //base to ascii
|
|
btoa: (data)=>node?Buffer.from(data,"binary").toString("base64"):btoa(data), //ascii to base
|
|
pad: (data) => {
|
|
var length = 16 - (data.length % 16);
|
|
var mergedArray = new Uint8Array(data.length+length);
|
|
mergedArray.set(data);
|
|
mergedArray.set(new Uint8Array(length).fill(length), data.length);
|
|
return mergedArray;
|
|
},
|
|
unpad: (data) => {
|
|
return data.slice(0, -data[data.length - 1]);
|
|
},
|
|
AES:{
|
|
bytes_to_key: async (bytes, salt, output = 48) => {
|
|
var data = new Uint8Array([...bytes, ...salt]);
|
|
var key = new Uint8Array();
|
|
var final_key = new Uint8Array();
|
|
while (final_key.length < output) {
|
|
key = await C.sha256(new Uint8Array([...key, ...data]));
|
|
final_key = new Uint8Array([...final_key, ...key]);
|
|
}
|
|
return final_key.slice(0, output);
|
|
},
|
|
encryptData: async (rawdata, rawkey) => {
|
|
var salt = await C.random(8);
|
|
var key_iv = await C.AES.bytes_to_key(rawkey, salt, 32 + 16);
|
|
var key = key_iv.slice(0, 32);
|
|
var iv = key_iv.slice(32);
|
|
var aes;
|
|
if(node){
|
|
let cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
|
|
let encrypted = cipher.update(C.pad(rawdata));
|
|
aes = new Uint8Array(Buffer.concat([encrypted, cipher.final()]));
|
|
}else{
|
|
aes = new Uint8Array(await crypto.subtle.encrypt({name: "AES-CBC",iv},await crypto.subtle.importKey("raw",key,"AES-CBC",true,["encrypt", "decrypt"]),C.pad(rawdata)));
|
|
}
|
|
var mergedArray = new Uint8Array(aes.length+16);
|
|
mergedArray.set([83, 97, 108, 116, 95, 50, 53, 54]);
|
|
mergedArray.set(salt,8);
|
|
mergedArray.set(aes,16);
|
|
return mergedArray;
|
|
},
|
|
encrypt: async (message, passphrase) => {
|
|
var rawdata = C.encode(message);
|
|
var rawkey = C.encode(passphrase);
|
|
var step = await C.AES.encryptData(rawdata,rawkey);
|
|
return C.decode(step);
|
|
},
|
|
decryptData: async (rawdata, rawkey) => {
|
|
var check = [83, 97, 108, 116, 95, 50, 53, 54];
|
|
for (var i = 0; i < check.length; i++) {
|
|
if(check[i]!=rawdata[i])return null;
|
|
}
|
|
var salt = rawdata.slice(8,16);
|
|
var key_iv = await C.AES.bytes_to_key(rawkey, salt, 32 + 16);
|
|
var key = key_iv.slice(0, 32);
|
|
var iv = key_iv.slice(32);
|
|
if(node){
|
|
let cipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key), iv);
|
|
let encrypted = cipher.update(rawdata.slice(16));
|
|
return C.unpad(new Uint8Array(Buffer.concat([encrypted, cipher.final()])));
|
|
}else{
|
|
return C.unpad(
|
|
new Uint8Array (await crypto.subtle.decrypt(
|
|
{name: "AES-CBC",iv},
|
|
await crypto.subtle.importKey("raw",key,"AES-CBC",true,["encrypt", "decrypt"]),
|
|
rawdata.slice(16)
|
|
))
|
|
);
|
|
}
|
|
},
|
|
decrypt: async (message, passphrase) => {
|
|
var rawdata = C.encode(message);
|
|
var rawkey = C.encode(passphrase);
|
|
try {
|
|
var step = await C.AES.decryptData(rawdata,rawkey);
|
|
return C.decode(step);
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
},
|
|
},
|
|
RSA:{
|
|
generateEncryptionKey: async () =>{
|
|
if(node){
|
|
var { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {modulusLength: 4096,publicExponent:0x010001,hashAlgorithm:"sha256"});
|
|
return {publicKey: C.decode(new Uint8Array( publicKey.export({type:"spki", format:"der"}))),
|
|
privateKey:C.decode(new Uint8Array(privateKey.export({type:"pkcs8",format:"der"})))};
|
|
}else{
|
|
var keyPair = await crypto.subtle.generateKey(
|
|
{name: "RSA-OAEP",modulusLength: 4096,publicExponent: new Uint8Array([1, 0, 1]),hash: "SHA-256"},
|
|
true,
|
|
["encrypt", "decrypt"]
|
|
);
|
|
return {privateKey:C.decode(new Uint8Array(await crypto.subtle.exportKey("pkcs8",keyPair.privateKey))),
|
|
publicKey: C.decode(new Uint8Array(await crypto.subtle.exportKey("spki", keyPair.publicKey )))};
|
|
}
|
|
},
|
|
generateSigningKey: async () =>{
|
|
if(node){
|
|
var { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {modulusLength: 4096,publicExponent:0x010001,hashAlgorithm:"sha256"});
|
|
return {publicKey: C.decode(new Uint8Array( publicKey.export({type:"spki", format:"der"}))),
|
|
privateKey:C.decode(new Uint8Array(privateKey.export({type:"pkcs8",format:"der"})))};
|
|
}else{
|
|
var keyPair = await crypto.subtle.generateKey(
|
|
{name: "RSA-PSS",modulusLength: 4096,publicExponent: new Uint8Array([1, 0, 1]),hash: "SHA-256"},
|
|
true,
|
|
["sign", "verify"]
|
|
);
|
|
return {privateKey:C.decode(new Uint8Array(await crypto.subtle.exportKey("pkcs8",keyPair.privateKey))),
|
|
publicKey: C.decode(new Uint8Array(await crypto.subtle.exportKey("spki", keyPair.publicKey )))};
|
|
}
|
|
},
|
|
encrypt: async (message, publicKey) => {
|
|
var rawdata = C.encode(message);
|
|
var step;
|
|
if(node){
|
|
var rawkey = crypto.createPublicKey({key:C.encode(publicKey),format:"der",type:"spki"});
|
|
//console.log("d",rawkey);
|
|
step = crypto.publicEncrypt({
|
|
key: rawkey,
|
|
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
|
|
oaepHash: "sha256",
|
|
}, Buffer.from(rawdata));
|
|
}else{
|
|
var rawkey = await crypto.subtle.importKey("spki",C.encode(publicKey),{name: "RSA-OAEP",hash: "SHA-256"},true,["encrypt"]);
|
|
step = await crypto.subtle.encrypt({name: "RSA-OAEP"},rawkey,rawdata);
|
|
}
|
|
return C.decode(new Uint8Array(step));
|
|
},
|
|
decrypt: async (message, privateKey) => {
|
|
var rawdata = C.encode(message);
|
|
if(node){
|
|
var rawkey = crypto.createPrivateKey({key:C.encode(privateKey),format:"der",type:"pkcs8"});
|
|
try {
|
|
var step = crypto.privateDecrypt({
|
|
key: rawkey,
|
|
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
|
|
oaepHash: "sha256",
|
|
}, Buffer.from(rawdata));
|
|
return C.decode(new Uint8Array(step));
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}else{
|
|
var rawkey = await crypto.subtle.importKey("pkcs8",C.encode(privateKey),{name: "RSA-OAEP",hash: "SHA-256"},true,["decrypt"]);
|
|
try {
|
|
var step = await crypto.subtle.decrypt({name: "RSA-OAEP"},rawkey,rawdata);
|
|
return C.decode(new Uint8Array(step));
|
|
} catch (e) {
|
|
console.log(e);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
},
|
|
sign:async (message, privateKey) => {
|
|
var rawdata = C.encode(message);
|
|
var step;
|
|
if(node){
|
|
var rawkey = crypto.createPrivateKey({key:C.encode(privateKey),format:"der",type:"pkcs8"});
|
|
step = crypto.sign("sha256", Buffer.from(rawdata), {
|
|
key: rawkey,
|
|
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
|
|
saltLength:32
|
|
});
|
|
}else{
|
|
var rawkey = await crypto.subtle.importKey("pkcs8",C.encode(privateKey),{name: "RSA-PSS",hash: "SHA-256"},true,["sign"]);
|
|
step = await crypto.subtle.sign(
|
|
{
|
|
name: "RSA-PSS",
|
|
saltLength: 32,
|
|
},
|
|
rawkey,
|
|
rawdata
|
|
);
|
|
}
|
|
return C.decode(new Uint8Array(step));
|
|
},
|
|
verify:async (message, signature, publicKey) => {
|
|
var rawdata = C.encode(message);
|
|
var rawsig = C.encode(signature);
|
|
var step;
|
|
if(node){
|
|
var rawkey = crypto.createPublicKey({key:C.encode(publicKey),format:"der",type:"spki"});
|
|
step = crypto.verify(
|
|
"sha256",
|
|
Buffer.from(rawdata),
|
|
{
|
|
key: rawkey,
|
|
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
|
|
saltLength:32
|
|
},
|
|
Buffer.from(rawsig)
|
|
);
|
|
}else{
|
|
var rawkey = await crypto.subtle.importKey("spki",C.encode(publicKey),{name: "RSA-PSS",hash: "SHA-256"},true,["verify"]);
|
|
step = await crypto.subtle.verify(
|
|
{
|
|
name: "RSA-PSS",
|
|
saltLength: 32,
|
|
},
|
|
rawkey,
|
|
rawsig,
|
|
rawdata
|
|
);
|
|
}
|
|
|
|
return step;// ? "valid" : "invalid";
|
|
}
|
|
},
|
|
communicate:{
|
|
encrypt: async (message,publicKey)=>{
|
|
var randKey = await C.randomKey(32);
|
|
var send = {
|
|
d: await C.AES.encrypt(message,randKey),
|
|
k: await C.RSA.encrypt(randKey,publicKey)
|
|
};
|
|
return {send:JSON.stringify(send),key:randKey};
|
|
},
|
|
decrypt: async (data,privateKey)=>{
|
|
try {
|
|
let {d,k} = JSON.parse(data);
|
|
if(typeof d != "string" || typeof k != "string")throw "invalid Data";
|
|
var randKey = await C.RSA.decrypt(k,privateKey);
|
|
if(randKey == null) throw "invalid async Key";
|
|
var out = await C.AES.decrypt(d,randKey);
|
|
if(out == null) throw "invalid sync Key";
|
|
return {data:out,key:randKey};
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
},
|
|
//Message to send, reomte publicKey, own privateKey, my id so that the other one knows how i am (can be empty)
|
|
encryptSign: async (message,publicKey,privateKey,id)=>{
|
|
return await C.communicate.encrypt(JSON.stringify({
|
|
d:message,
|
|
i:id,
|
|
s:await C.RSA.sign(message,privateKey)
|
|
}),publicKey);
|
|
},
|
|
//Data to decrypt, my privateKey, callback to get reomtes publicKey with id
|
|
decryptSign: async (data,privateKey,publicKeyCall)=>{
|
|
try {
|
|
var inn = await C.communicate.decrypt(data,privateKey);
|
|
if(inn == null)throw "invalid privateKey";
|
|
inn = JSON.parse(inn);
|
|
if(typeof inn.d == "undefined"||typeof inn.i != "string"||typeof inn.s != "string") throw "invalid Data";
|
|
let {d,i,s} = inn;
|
|
var publicKey = publicKeyCall(i);
|
|
var okay = await C.RSA.verify(d,s,publicKey);
|
|
if(!okay) throw "wrong Public Key";
|
|
return d;
|
|
} catch (e) {
|
|
console.log(e);
|
|
return null;
|
|
}
|
|
},
|
|
}
|
|
};
|
|
|
|
var a = C.sha256;
|
|
var b = C.random;
|
|
var c = C.randomKey;
|
|
var d = C.encode;
|
|
var e = C.decode;
|
|
var f = C.atob;
|
|
var g = C.btoa;
|
|
var h = C.pad;
|
|
var i = C.unpad;
|
|
var j = C.AES;
|
|
var k = C.RSA;
|
|
var l = C.communicate;
|
|
|
|
export {
|
|
a as sha256,
|
|
b as random,
|
|
c as randomKey,
|
|
d as encode,
|
|
e as decode,
|
|
f as atob,
|
|
g as btoa,
|
|
h as pad,
|
|
i as unpad,
|
|
j as AES,
|
|
k as RSA,
|
|
l as communicate
|
|
};
|
|
export default C;
|