var node = false; var crypto; if (typeof process != "undefined") { crypto = await import('crypto'); if(typeof crypto.webcrypto != "undefined"){ crypto = crypto.webcrypto; console.log("subtle"); }else{ node = true; console.log("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;