UNPKG

secret-manager-crypto-utils

Version:

Small set of crypto utilities - ed25519 signatures, el-gamal encrpytion with AES-256-CBC, diffie-hellman and elGamal Secret sharing.

806 lines (694 loc) 27.4 kB
// Generated by CoffeeScript 2.7.0 //########################################################### var ORDER, createKeyObject, createKeyObjectBytes, createKeyObjectHex, crypto, hashToScalar, mod; import * as ed255 from "@noble/ed25519"; import * as tbut from "thingy-byte-utils"; //########################################################### crypto = window.crypto.subtle; //########################################################### ORDER = BigInt(2) ** BigInt(252) + BigInt('27742317777372353535851937790883648493'); //########################################################### //region internalFunctions createKeyObject = async function(keyHex) { var keyBytes; keyBytes = tbut.hexToBytes(keyHex); return (await crypto.importKey("raw", keyBytes, { name: "AES-CBC" }, false, ["decrypt", "encrypt"])); }; createKeyObjectHex = createKeyObject; createKeyObjectBytes = async function(keyBytes) { return (await crypto.importKey("raw", keyBytes, { name: "AES-CBC" }, false, ["decrypt", "encrypt"])); }; //########################################################### hashToScalar = function(hash) { var bigInt, relevant; relevant = hash.slice(0, 32); relevant[0] &= 248; relevant[31] &= 127; relevant[31] |= 64; bigInt = tbut.bytesToBigInt(relevant); return mod(bigInt); }; mod = function(a, b = ORDER) { var result; result = a % b; if (result >= 0n) { return result; } else { return result + b; } }; //endregion //########################################################### //region exposedStuff //########################################################### //region shas //########################################################### // Hex Version export var sha256 = async function(content) { var contentBytes, hashBytes; if ((typeof content) === "string") { contentBytes = tbut.utf8ToBytes(content); } else { contentBytes = content; } hashBytes = (await crypto.digest("SHA-256", contentBytes)); return tbut.bytesToHex(hashBytes); }; export var sha512 = async function(content) { var contentBytes, hashBytes; if ((typeof content) === "string") { contentBytes = tbut.utf8ToBytes(content); } else { contentBytes = content; } hashBytes = (await crypto.digest("SHA-512", contentBytes)); return tbut.bytesToHex(hashBytes); }; export var sha256Hex = sha256; export var sha512Hex = sha512; //########################################################### // Byte Version export var sha256Bytes = async function(content) { var contentBytes; if ((typeof content) === "string") { contentBytes = tbut.utf8ToBytes(content); } else { contentBytes = content; } return new Uint8Array((await crypto.digest("SHA-256", contentBytes))); }; export var sha512Bytes = async function(content) { var contentBytes; if ((typeof content) === "string") { contentBytes = tbut.utf8ToBytes(content); } else { contentBytes = content; } return new Uint8Array((await crypto.digest("SHA-512", contentBytes))); }; //endregion //########################################################### //region keys //########################################################### // Hex Version export var createKeyPair = async function() { var publicKeyBytes, publicKeyHex, secretKeyBytes, secretKeyHex; secretKeyBytes = ed255.utils.randomPrivateKey(); publicKeyBytes = (await ed255.getPublicKeyAsync(secretKeyBytes)); secretKeyHex = tbut.bytesToHex(secretKeyBytes); publicKeyHex = tbut.bytesToHex(publicKeyBytes); return {secretKeyHex, publicKeyHex}; }; export var createSymKey = function() { var keyAndIV; keyAndIV = new Uint8Array(48); window.crypto.getRandomValues(keyAndIV); return tbut.bytesToHex(keyAndIV); }; export var createPublicKey = async function(secretKeyHex) { var publicKeyBytes; publicKeyBytes = (await ed255.getPublicKeyAsync(secretKeyHex)); return tbut.bytesToHex(publicKeyBytes); }; export var createKeyPairHex = createKeyPair; export var createSymKeyHex = createSymKey; export var createPublicKeyHex = createPublicKey; //########################################################### // Byte Version export var createKeyPairBytes = async function() { var publicKeyBytes, secretKeyBytes; secretKeyBytes = ed255.utils.randomPrivateKey(); publicKeyBytes = (await ed255.getPublicKeyAsync(secretKeyBytes)); return {secretKeyBytes, publicKeyBytes}; }; export var createSymKeyBytes = function() { var keyAndIV; keyAndIV = new Uint8Array(48); window.crypto.getRandomValues(keyAndIV); return keyAndIV; }; export var createPublicKeyBytes = async function(secretKeyBytes) { return (await ed255.getPublicKeyAsync(secretKeyBytes)); }; //endregion //########################################################### //region signatures //########################################################### // Hex Version export var createSignature = async function(content, signingKeyHex) { var contentBytes, signature, signingKeyBytes; contentBytes = tbut.utf8ToBytes(content); signingKeyBytes = tbut.hexToBytes(signingKeyHex); signature = (await ed255.signAsync(contentBytes, signingKeyBytes)); return tbut.bytesToHex(signature); }; export var verify = async function(sigHex, keyHex, content) { var contentBytes, keyBytes, sigBytes; sigBytes = tbut.hexToBytes(sigHex); keyBytes = tbut.hexToBytes(keyHex); contentBytes = tbut.utf8ToBytes(content); return (await ed255.verifyAsync(sigBytes, contentBytes, keyBytes)); }; export var createSignatureHex = createSignature; export var verifyHex = verify; //########################################################### // Byte Version export var createSignatureBytes = async function(content, signingKeyBytes) { var contentBytes; contentBytes = tbut.utf8ToBytes(content); return (await ed255.signAsync(contentBytes, signingKeyBytes)); }; export var verifyBytes = async function(sigBytes, keyBytes, content) { var contentBytes; contentBytes = tbut.utf8ToBytes(content); return (await ed255.verifyAsync(sigBytes, contentBytes, keyBytes)); }; //endregion //########################################################### //region symmetric encryption //########################################################### // Hex Version export var symmetricEncrypt = async function(content, keyHex) { var aesKeyHex, algorithm, gibbrishBytes, ivBytes, ivHex, keyObj, saltedContent; ivHex = keyHex.substring(0, 32); aesKeyHex = keyHex.substring(32, 96); ivBytes = tbut.hexToBytes(ivHex); saltedContent = saltContent(content); keyObj = (await createKeyObjectHex(aesKeyHex)); algorithm = { name: "AES-CBC", iv: ivBytes }; gibbrishBytes = (await crypto.encrypt(algorithm, keyObj, saltedContent)); return tbut.bytesToHex(gibbrishBytes); }; export var symmetricDecrypt = async function(gibbrishHex, keyHex) { var aesKeyHex, algorithm, gibbrishBytes, ivBytes, ivHex, keyObj, saltedContent; ivHex = keyHex.substring(0, 32); aesKeyHex = keyHex.substring(32, 96); ivBytes = tbut.hexToBytes(ivHex); gibbrishBytes = tbut.hexToBytes(gibbrishHex); keyObj = (await createKeyObjectHex(aesKeyHex)); algorithm = { name: "AES-CBC", iv: ivBytes }; saltedContent = (await crypto.decrypt(algorithm, keyObj, gibbrishBytes)); saltedContent = new Uint8Array(saltedContent); return unsaltContent(saltedContent); }; export var symmetricEncryptHex = symmetricEncrypt; export var symmetricDecryptHex = symmetricDecrypt; //########################################################### // Byte Version export var symmetricEncryptBytes = async function(content, keyBytes) { var aesKeyBytes, algorithm, gibbrishBytes, ivBytes, keyObj, saltedContent; ivBytes = new Uint8Array(keyBytes.buffer, 0, 16); aesKeyBytes = new Uint8Array(keyBytes.buffer, 16, 32); saltedContent = saltContent(content); keyObj = (await createKeyObjectBytes(aesKeyBytes)); algorithm = { name: "AES-CBC", iv: ivBytes }; gibbrishBytes = (await crypto.encrypt(algorithm, keyObj, saltedContent)); return gibbrishBytes; }; export var symmetricDecryptBytes = async function(gibbrishBytes, keyBytes) { var aesKeyBytes, algorithm, ivBytes, keyObj, saltedContent; ivBytes = new Uint8Array(keyBytes.buffer, 0, 16); aesKeyBytes = new Uint8Array(keyBytes.buffer, 16, 32); keyObj = (await createKeyObjectBytes(aesKeyBytes)); algorithm = { name: "AES-CBC", iv: ivBytes }; saltedContent = (await crypto.decrypt(algorithm, keyObj, gibbrishBytes)); saltedContent = new Uint8Array(saltedContent); return unsaltContent(saltedContent); }; //endregion //########################################################### //region asymmetric encryption //########################################################### // Hex Version //########################################################### export var asymmetricEncrypt = async function(content, publicKeyHex) { var ABytes, B, encryptedContentHex, gibbrishHex, lB, lBigInt, nBytes, referencePointHex, symkeyHex; // a = Secret Key of target user // k = sha512(a) -> hashToScalar (scalar for multiplication) // G = basePoint // B = kG = Public Key B = ed255.ExtendedPoint.fromHex(publicKeyHex); // n = new one-time secret (generated forgotten about) // l = sha512(n) -> hashToScalar (scalar for multiplication) // A = lG = one time public key = reference point // lB = lkG = shared secret // key = sha512(lB) // X = symmetricEncrypt(content, key) // {A,X} = data for targt user // n = one-time secret -> l nBytes = ed255.utils.randomPrivateKey(); lBigInt = hashToScalar((await sha512Bytes(nBytes))); // A reference Point ABytes = (await ed255.getPublicKeyAsync(nBytes)); // lB = lkG = shared Secret lB = B.multiply(lBigInt); // encrypt with symmetricEncryptHex symkeyHex = (await sha512Hex(lB.toRawBytes())); gibbrishHex = (await symmetricEncryptHex(content, symkeyHex)); referencePointHex = tbut.bytesToHex(ABytes); encryptedContentHex = gibbrishHex; return {referencePointHex, encryptedContentHex}; }; export var asymmetricDecrypt = async function(secrets, secretKeyHex) { var A, AHex, aBytes, content, gibbrishHex, kA, kBigInt, symkeyHex; AHex = secrets.referencePointHex || secrets.referencePoint; gibbrishHex = secrets.encryptedContentHex || secrets.encryptedContent; if ((AHex == null) || (gibbrishHex == null)) { throw new Error("Invalid secrets Object!"); } // a = Secret Key // k = sha512(a) -> hashToScalar // G = basePoint // B = kG = Public Key aBytes = tbut.hexToBytes(secretKeyHex); kBigInt = hashToScalar((await sha512Bytes(aBytes))); // {A,X} = secrets // A = lG = one time public reference point // klG = lB = kA = shared secret // key = sha512(kAHex) // content = symmetricDecrypt(X, key) A = ed255.ExtendedPoint.fromHex(AHex); kA = A.multiply(kBigInt); symkeyHex = (await sha512Hex(kA.toRawBytes())); content = (await symmetricDecryptHex(gibbrishHex, symkeyHex)); return content; }; export var asymmetricEncryptHex = asymmetricEncrypt; export var asymmetricDecryptHex = asymmetricDecrypt; //########################################################### // Byte Version export var asymmetricEncryptBytes = async function(content, publicKeyBytes) { var ABytes, B, encryptedContentBytes, gibbrishBytes, lB, lBigInt, nBytes, publicKeyHex, referencePointBytes, symkeyBytes; // a = Secret Key of target user // k = sha512(a) -> hashToScalar (scalar for multiplication) // G = basePoint // B = kG = Public Key publicKeyHex = tbut.bytesToHex(publicKeyBytes); B = ed255.ExtendedPoint.fromHex(publicKeyHex); // n = new one-time secret (generated forgotten about) // l = sha512(n) -> hashToScalar (scalar for multiplication) // A = lG = one time public key = reference point // lB = lkG = shared secret // key = sha512(lB) // X = symmetricEncrypt(content, key) // {A,X} = data for targt user // n = one-time secret -> l nBytes = ed255.utils.randomPrivateKey(); lBigInt = hashToScalar((await sha512Bytes(nBytes))); // A reference Point ABytes = (await ed255.getPublicKeyAsync(nBytes)); // lB = lkG = shared Secret lB = B.multiply(lBigInt); symkeyBytes = (await sha512Bytes(lB.toRawBytes())); gibbrishBytes = (await symmetricEncryptBytes(content, symkeyBytes)); referencePointBytes = ABytes; encryptedContentBytes = gibbrishBytes; return {referencePointBytes, encryptedContentBytes}; }; export var asymmetricDecryptBytes = async function(secrets, secretKeyBytes) { var A, ABytes, AHex, content, gibbrishBytes, kA, kBigInt, symkeyBytes; ABytes = secrets.referencePointBytes || secrets.referencePoint; gibbrishBytes = secrets.encryptedContentBytes || secrets.encryptedContent; if ((ABytes == null) || (gibbrishBytes == null)) { throw new Error("Invalid secrets Object!"); } // a = Secret Key // k = sha512(a) -> hashToScalar // G = basePoint // B = kG = Public Key kBigInt = hashToScalar((await sha512Bytes(secretKeyBytes))); // {A,X} = secrets // A = lG = one time public reference point // klG = lB = kA = shared secret // key = sha512(kAHex) // content = symmetricDecrypt(X, key) AHex = tbut.bytesToHex(ABytes); A = ed255.ExtendedPoint.fromHex(AHex); kA = A.multiply(kBigInt); symkeyBytes = (await sha512Bytes(kA.toRawBytes())); content = (await symmetricDecryptBytes(gibbrishBytes, symkeyBytes)); return content; }; //endregion //########################################################### //region deffieHellman/ElGamal secrets //########################################################### // Hex Versions //########################################################### export var diffieHellmanSecretHash = async function(secretKeyHex, publicKeyHex, contextString = "") { var B, aBytes, b, cBytes, i, j, k, kB, kBBytes, kBigInt, len, len1, seedBytes, sharedSecretHex; // a = our SecretKey // k = sha512(a) -> hashToScalar (scalar for multiplication) // B = lG = target User Public Key // kB = klG = shared Secret aBytes = tbut.hexToBytes(secretKeyHex); kBigInt = hashToScalar((await sha512Bytes(aBytes))); B = ed255.ExtendedPoint.fromHex(publicKeyHex); // A reference Point kB = B.multiply(kBigInt); kBBytes = kB.toRawBytes(); cBytes = tbut.utf8ToBytes(contextString); seedBytes = new Uint8Array(kBBytes.length + cBytes.length); for (i = j = 0, len = kBBytes.length; j < len; i = ++j) { b = kBBytes[i]; seedBytes[i] = b; } for (i = k = 0, len1 = cBytes.length; k < len1; i = ++k) { b = cBytes[i]; seedBytes[kBBytes.length + i] = b; } sharedSecretHex = (await sha512Hex(seedBytes)); return sharedSecretHex; }; export var diffieHellmanSecretHashHex = diffieHellmanSecretHash; export var createSharedSecretHash = diffieHellmanSecretHash; export var createSharedSecretHashHex = diffieHellmanSecretHash; export var diffieHellmanSecretRaw = async function(secretKeyHex, publicKeyHex) { var B, aBytes, kB, kBigInt, sharedSecretBytes, sharedSecretHex; // a = our SecretKey // k = sha512(a) -> hashToScalar (scalar for multiplication) // B = lG = target User Public Key // kB = klG = shared Secret aBytes = tbut.hexToBytes(secretKeyHex); kBigInt = hashToScalar((await sha512Bytes(aBytes))); B = ed255.ExtendedPoint.fromHex(publicKeyHex); kB = B.multiply(kBigInt); sharedSecretBytes = kB.toRawBytes(); sharedSecretHex = tbut.bytesToHex(sharedSecretBytes); return sharedSecretHex; }; export var diffieHellmanSecretRawHex = diffieHellmanSecretRaw; export var createSharedSecretRaw = diffieHellmanSecretRaw; export var createSharedSecretRawHex = diffieHellmanSecretRaw; //########################################################### export var elGamalSecretHash = async function(publicKeyHex, contextString = "") { var ABytes, B, b, cBytes, i, j, k, lB, lBBytes, lBigInt, len, len1, nBytes, referencePointHex, seedBytes, sharedSecretHex; // a = Secret Key of target user // k = sha512(a) -> hashToScalar (scalar for multiplication) // G = basePoint // B = kG = Public Key B = ed255.ExtendedPoint.fromHex(publicKeyHex); // n = new one-time secret (generated forgotten about) // l = sha512(n) -> hashToScalar (scalar for multiplication) // A = lG = one time public key = reference point // lB = lkG = shared secret // key = sha512(lB) // X = symmetricEncrypt(content, key) // {A,X} = data for targt user // n = one-time secret -> l nBytes = ed255.utils.randomPrivateKey(); lBigInt = hashToScalar((await sha512Bytes(nBytes))); // A reference Point ABytes = (await ed255.getPublicKeyAsync(nBytes)); // lB = lkG = shared Secret lB = B.multiply(lBigInt); lBBytes = lB.toRawBytes(); cBytes = tbut.utf8ToBytes(contextString); seedBytes = new Uint8Array(lBBytes.length + cBytes.length); for (i = j = 0, len = lBBytes.length; j < len; i = ++j) { b = lBBytes[i]; seedBytes[i] = b; } for (i = k = 0, len1 = cBytes.length; k < len1; i = ++k) { b = cBytes[i]; seedBytes[lBBytes.length + i] = b; } sharedSecretHex = (await sha512Hex(seedBytes)); referencePointHex = tbut.bytesToHex(ABytes); return {referencePointHex, sharedSecretHex}; }; export var elGamalSecretHashHex = elGamalSecretHash; export var referencedSharedSecretHash = elGamalSecretHash; export var referencedSharedSecretHashHex = elGamalSecretHash; export var referencedSecretHash = elGamalSecretHash; export var referencedSecretHashHex = elGamalSecretHash; export var elGamalSecretRaw = async function(publicKeyHex) { var ABytes, B, lB, lBBytes, lBigInt, nBytes, referencePointHex, sharedSecretHex; // a = Secret Key of target user // k = sha512(a) -> hashToScalar (scalar for multiplication) // G = basePoint // B = kG = Public Key B = ed255.ExtendedPoint.fromHex(publicKeyHex); // n = new one-time secret (generated forgotten about) // l = sha512(n) -> hashToScalar (scalar for multiplication) // A = lG = one time public key = reference point // lB = lkG = shared secret // key = sha512(lB) // X = symmetricEncrypt(content, key) // {A,X} = data for targt user // n = one-time secret -> l nBytes = ed255.utils.randomPrivateKey(); lBigInt = hashToScalar((await sha512Bytes(nBytes))); // A reference Point ABytes = (await ed255.getPublicKeyAsync(nBytes)); // lB = lkG = shared Secret lB = B.multiply(lBigInt); lBBytes = lB.toRawBytes(); sharedSecretHex = tbut.bytesToHex(lBBytes); referencePointHex = tbut.bytesToHex(ABytes); return {referencePointHex, sharedSecretHex}; }; export var elGamalSecretRawHex = elGamalSecretRaw; export var referencedSharedSecretRaw = elGamalSecretRaw; export var referencedSharedSecretRawHex = elGamalSecretRaw; export var referencedSecretRaw = elGamalSecretRaw; export var referencedSecretRawHex = elGamalSecretRaw; //########################################################### // Bytes Versions //########################################################### export var diffieHellmanSecretHashBytes = async function(secretKeyBytes, publicKeyBytes, contextString = "") { var B, BHex, b, cBytes, i, j, k, kB, kBBytes, kBigInt, len, len1, seedBytes, sharedSecretBytes; // a = our SecretKey // k = sha512(a) -> hashToScalar (scalar for multiplication) // B = lG = target User Public Key // kB = klG = shared Secret BHex = tbut.bytesToHex(publicKeyBytes); B = ed255.ExtendedPoint.fromHex(BHex); // k kBigInt = hashToScalar((await sha512Bytes(secretKeyBytes))); // kB = klG = shared Secret kB = B.multiply(kBigInt); kBBytes = kB.toRawBytes(); cBytes = tbut.utf8ToBytes(contextString); seedBytes = new Uint8Array(kBBytes.length + cBytes.length); for (i = j = 0, len = kBBytes.length; j < len; i = ++j) { b = kBBytes[i]; seedBytes[i] = b; } for (i = k = 0, len1 = cBytes.length; k < len1; i = ++k) { b = cBytes[i]; seedBytes[kBBytes.length + i] = b; } sharedSecretBytes = (await sha512Bytes(seedBytes)); return sharedSecretBytes; }; export var sharedSecretHashBytes = diffieHellmanSecretHashBytes; export var diffieHellmanSecretRawBytes = async function(secretKeyBytes, publicKeyBytes) { var B, BHex, kB, kBBytes, kBigInt; // a = our SecretKey // k = sha512(a) -> hashToScalar (scalar for multiplication) // B = lG = target User Public Key // kB = klG = shared Secret BHex = tbut.bytesToHex(publicKeyBytes); B = ed255.ExtendedPoint.fromHex(BHex); // k kBigInt = hashToScalar((await sha512Bytes(secretKeyBytes))); // kB = klG = shared Secret kB = B.multiply(kBigInt); kBBytes = kB.toRawBytes(); return kBBytes; }; export var sharedSecretRawBytes = diffieHellmanSecretRawBytes; //########################################################### export var elGamalSecretHashBytes = async function(publicKeyBytes, contextString = "") { var ABytes, B, BHex, b, cBytes, i, j, k, lB, lBBytes, lBigInt, len, len1, nBytes, referencePointBytes, seedBytes, sharedSecretBytes; // a = Secret Key of target user // k = sha512(a) -> hashToScalar (scalar for multiplication) // G = basePoint // B = kG = Public Key BHex = tbut.bytesToHex(publicKeyBytes); B = ed255.ExtendedPoint.fromHex(BHex); // n = new one-time secret (generated forgotten about) // l = sha512(n) -> hashToScalar (scalar for multiplication) // A = lG = one time public key = reference point // lB = lkG = shared secret // key = sha512(lB) // X = symmetricEncrypt(content, key) // {A,X} = data for targt user // n = one-time secret -> l nBytes = ed255.utils.randomPrivateKey(); lBigInt = hashToScalar((await sha512Bytes(nBytes))); // A reference Point ABytes = (await ed255.getPublicKeyAsync(nBytes)); // lB = lkG = shared Secret lB = B.multiply(lBigInt); lBBytes = lB.toRawBytes(); cBytes = tbut.utf8ToBytes(contextString); seedBytes = new Uint8Array(lBBytes.length + cBytes.length); for (i = j = 0, len = lBBytes.length; j < len; i = ++j) { b = lBBytes[i]; seedBytes[i] = b; } for (i = k = 0, len1 = cBytes.length; k < len1; i = ++k) { b = cBytes[i]; seedBytes[lBBytes.length + i] = b; } sharedSecretBytes = (await sha512Bytes(seedBytes)); referencePointBytes = ABytes; return {referencePointBytes, sharedSecretBytes}; }; export var referencedSharedSecretHashBytes = elGamalSecretHashBytes; export var referencedSecretHashBytes = elGamalSecretHashBytes; export var elGamalSecretRawBytes = async function(publicKeyBytes) { var ABytes, B, BHex, lB, lBBytes, lBigInt, nBytes, referencePointBytes, sharedSecretBytes; // a = Secret Key of target user // k = sha512(a) -> hashToScalar (scalar for multiplication) // G = basePoint // B = kG = Public Key BHex = tbut.bytesToHex(publicKeyBytes); B = ed255.ExtendedPoint.fromHex(BHex); // n = new one-time secret (generated forgotten about) // l = sha512(n) -> hashToScalar (scalar for multiplication) // A = lG = one time public key = reference point // lB = lkG = shared secret // key = sha512(lB) // X = symmetricEncrypt(content, key) // {A,X} = data for targt user // n = one-time secret -> l nBytes = ed255.utils.randomPrivateKey(); lBigInt = hashToScalar((await sha512Bytes(nBytes))); // A reference Point ABytes = (await ed255.getPublicKeyAsync(nBytes)); // lB = lkG = shared Secret lB = B.multiply(lBigInt); lBBytes = lB.toRawBytes(); sharedSecretBytes = lBBytes; referencePointBytes = ABytes; return {referencePointBytes, sharedSecretBytes}; }; export var referencedSharedSecretRawBytes = elGamalSecretRawBytes; export var referencedSecretRawBytes = elGamalSecretRawBytes; //endregion //########################################################### //region salts export var saltContent = function(content) { var c, contentLength, end, fullLength, idx, j, len, overlap, padding, prefixLength, resultBytes, salt, saltLength, sizeRand, sum, unpaddedLength; content = tbut.utf8ToBytes(content); contentLength = content.length; sizeRand = new Uint8Array(1); window.crypto.getRandomValues(sizeRand); saltLength = 33 + (sizeRand[0] & 127); salt = new Uint8Array(saltLength); window.crypto.getRandomValues(salt); // Prefix is salt + 3 bytes prefixLength = saltLength + 3; unpaddedLength = prefixLength + contentLength; overlap = unpaddedLength % 32; padding = 32 - overlap; fullLength = unpaddedLength + padding; resultBytes = new Uint8Array(fullLength); // immediatly write the content to the resultBytes for (idx = j = 0, len = content.length; j < len; idx = ++j) { c = content[idx]; resultBytes[idx + prefixLength] = c; } // The first 32 bytes of the prefix are 1:1 from the salt. sum = 0; idx = 32; while (idx--) { sum += salt[idx]; resultBytes[idx] = salt[idx]; } // the last byte of the prefix is the padding length resultBytes[saltLength + 2] = padding; // the padding postfix is the mirrored salt bytes up to padding size idx = 0; end = fullLength - 1; while (idx < padding) { resultBytes[end - idx] = salt[idx]; idx++; } // the prefix keeps the sum of the salt values as ending identification // make sure this condition is not met before we reach the real end idx = 32; while (idx < saltLength) { // when the condition is met we add +1 to the LSB(salt[idx+1]) to destroy it // Notice! If we add +1 to the MSB(salt[idx]) then we change what we cheched for previously, which might accidentally result in the condition being met now one byte before, which we donot check for ever again // if (sum == (salt[idx]*256 + salt[idx+1])) then salt[idx+1]++ salt[idx + 1] += sum === (salt[idx] * 256 + salt[idx + 1]); sum += salt[idx]; resultBytes[idx] = salt[idx]; idx++; } // save the sum in the right bytes resultBytes[saltLength] = sum >> 8; resultBytes[saltLength + 1] = sum % 256; // in this case we have the condition met when just taking the most significatn bytes of the real sum into account if (resultBytes[saltLength] === resultBytes[saltLength - 1] && resultBytes[saltLength + 1] === 2 * resultBytes[saltLength]) { resultBytes[saltLength - 1]++; sum++; resultBytes[saltLength] = sum >> 8; resultBytes[saltLength + 1] = sum % 256; } return resultBytes; }; export var unsaltContent = function(contentBytes) { var end, fullLength, idx, invalid, limit, overLimit, padding, start, sum; fullLength = contentBytes.length; if (fullLength > 160) { limit = 160; } else { limit = fullLength; } overLimit = limit + 1; sum = 0; idx = 32; while (idx--) { sum += contentBytes[idx]; } idx = 32; while (idx < overLimit) { if (sum === (contentBytes[idx] * 256 + contentBytes[idx + 1])) { start = idx + 3; padding = contentBytes[idx + 2]; break; } sum += contentBytes[idx]; idx++; } if (idx > limit) { throw new Error("Unsalt: No valid prefix ending found!"); } // Check if the padding matches the salt - so we can verify here nobody has tampered with it idx = 0; end = fullLength - 1; invalid = 0; while (idx < padding) { invalid += contentBytes[idx] !== contentBytes[end - idx]; idx++; } if (invalid) { throw new Error("Unsalt: Postfix and prefix did not match as expected!"); } end = fullLength - padding; contentBytes = contentBytes.slice(start, end); return tbut.bytesToUtf8(contentBytes); }; //endregion //endregion