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
JavaScript
// 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