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.
802 lines (692 loc) • 27.4 kB
JavaScript
// Generated by CoffeeScript 2.7.0
//###########################################################
var ORDER, encAlgo, hashToScalar, mod;
import * as ed255 from "@noble/ed25519";
import * as tbut from "thingy-byte-utils";
import crypto from "crypto";
//###########################################################
encAlgo = 'aes-256-cbc';
//###########################################################
ORDER = BigInt(2) ** BigInt(252) + BigInt('27742317777372353535851937790883648493');
//###########################################################
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;
}
};
//###########################################################
//region exposedStuff
//###########################################################
//region shas
//###########################################################
// Hex Version
export var sha256 = function(content) {
var hasher;
hasher = crypto.createHash("sha256");
hasher.update(content);
return hasher.digest("hex");
};
export var sha512 = function(content) {
var hasher;
hasher = crypto.createHash("sha512");
hasher.update(content);
return hasher.digest("hex");
};
export var sha256Hex = sha256;
export var sha512Hex = sha512;
//###########################################################
// Bytes Version
export var sha256Bytes = function(content) {
var hasher;
hasher = crypto.createHash("sha256");
hasher.update(content);
return hasher.digest();
};
export var sha512Bytes = function(content) {
var hasher;
hasher = crypto.createHash("sha512");
hasher.update(content);
return hasher.digest();
};
//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 = crypto.randomBytes(48);
return tbut.bytesToHex(keyAndIV);
};
export var createPublicKey = async function(secretKeyHex) {
var publicKeyBytes;
publicKeyBytes = (await ed255.getPublicKeyAsync(tbut.hexToBytes(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() {
return new Uint8Array(crypto.randomBytes(48));
};
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 = function(content, keyHex) {
var aesKeyBuffer, aesKeyHex, cipher, gibbrish, ivBuffer, ivHex, saltedContent;
ivHex = keyHex.substring(0, 32);
ivBuffer = Buffer.from(ivHex, "hex");
aesKeyHex = keyHex.substring(32, 96);
aesKeyBuffer = Buffer.from(aesKeyHex, "hex");
// console.log "- - ivHex: "
// console.log ivHex
// console.log ivHex.length
// console.log "- - aesKeyHex: "
// console.log aesKeyHex
// console.log aesKeyHex.length
saltedContent = saltContent(content);
cipher = crypto.createCipheriv(encAlgo, aesKeyBuffer, ivBuffer);
gibbrish = cipher.update(saltedContent, null, 'hex');
gibbrish += cipher.final('hex');
return gibbrish;
};
export var symmetricDecrypt = function(gibbrishHex, keyHex) {
var aesKeyBuffer, aesKeyHex, allSaltedContent, b, decipher, finalContent, i, ivBuffer, ivHex, j, k, len, len1, saltedContent;
ivHex = keyHex.substring(0, 32);
ivBuffer = Buffer.from(ivHex, "hex");
aesKeyHex = keyHex.substring(32, 96);
aesKeyBuffer = Buffer.from(aesKeyHex, "hex");
// console.log "- - ivHex: "
// console.log ivHex
// console.log ivHex.length
// console.log "- - aesKeyHex: "
// console.log aesKeyHex
// console.log aesKeyHex.length
decipher = crypto.createDecipheriv(encAlgo, aesKeyBuffer, ivBuffer);
saltedContent = decipher.update(gibbrishHex, 'hex');
finalContent = decipher.final();
if (finalContent.length === 0) {
return unsaltContent(saltedContent);
}
allSaltedContent = new Uint8Array(saltedContent.length + finalContent.length);
for (i = j = 0, len = saltContent.length; j < len; i = ++j) {
b = saltContent[i];
allSaltedContent[i] = b;
}
for (i = k = 0, len1 = finalContent.length; k < len1; i = ++k) {
b = finalContent[i];
allSaltedContent[saltedContent.length + i] = b;
}
return unsaltContent(allSaltedContent);
};
export var symmetricEncryptHex = symmetricEncrypt;
export var symmetricDecryptHex = symmetricDecrypt;
//###########################################################
// Byte Version
export var symmetricEncryptBytes = function(content, keyBytes) {
var aesKeyBuffer, allGibbrish, b, cipher, gibbrish, gibbrishFinal, i, ivBuffer, j, k, len, len1, saltedContent;
ivBuffer = Buffer.from(keyBytes.buffer, 0, 16);
aesKeyBuffer = Buffer.from(keyBytes.buffer, 16, 32);
saltedContent = saltContent(content);
cipher = crypto.createCipheriv(encAlgo, aesKeyBuffer, ivBuffer);
gibbrish = cipher.update(saltedContent);
gibbrishFinal = cipher.final();
if (gibbrishFinal.length === 0) {
return new Uint8Array(gibbrish);
}
allGibbrish = new Uint8Array(gibbrishFinal.length + gibbrish.length);
for (i = j = 0, len = gibbrish.length; j < len; i = ++j) {
b = gibbrish[i];
allGibbrish[i] = b;
}
for (i = k = 0, len1 = gibbrishFinal.length; k < len1; i = ++k) {
b = gibbrishFinal[i];
allGibbrish[gibbrish.length + i] = b;
}
return allGibbrish;
};
export var symmetricDecryptBytes = function(gibbrishBytes, keyBytes) {
var aesKeyBuffer, allSaltedContent, b, decipher, finalContent, i, ivBuffer, j, k, len, len1, saltedContent;
ivBuffer = Buffer.from(keyBytes.buffer, 0, 16);
aesKeyBuffer = Buffer.from(keyBytes.buffer, 16, 32);
decipher = crypto.createDecipheriv(encAlgo, aesKeyBuffer, ivBuffer);
saltedContent = decipher.update(gibbrishBytes);
finalContent = decipher.final();
if (finalContent.length === 0) {
return unsaltContent(saltedContent);
}
allSaltedContent = new Uint8Array(saltedContent.length + finalContent.length);
for (i = j = 0, len = saltContent.length; j < len; i = ++j) {
b = saltContent[i];
allSaltedContent[i] = b;
}
for (i = k = 0, len1 = finalContent.length; k < len1; i = ++k) {
b = finalContent[i];
allSaltedContent[saltedContent.length + i] = b;
}
return unsaltContent(allSaltedContent);
};
//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(sha512Bytes(nBytes));
// A reference Point
ABytes = (await ed255.getPublicKeyAsync(nBytes));
// lB = lkG = shared Secret
lB = B.multiply(lBigInt);
// encrypt with symmetricEncryptHex
symkeyHex = sha512Hex(lB.toRawBytes());
gibbrishHex = symmetricEncryptHex(content, symkeyHex);
referencePointHex = tbut.bytesToHex(ABytes);
encryptedContentHex = gibbrishHex;
return {referencePointHex, encryptedContentHex};
};
export var asymmetricDecrypt = 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(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 = sha512Hex(kA.toRawBytes());
content = 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(sha512Bytes(nBytes));
// A reference Point
ABytes = (await ed255.getPublicKeyAsync(nBytes));
// lB = lkG = shared Secret
lB = B.multiply(lBigInt);
symkeyBytes = sha512Bytes(lB.toRawBytes());
gibbrishBytes = symmetricEncryptBytes(content, symkeyBytes);
referencePointBytes = ABytes;
encryptedContentBytes = gibbrishBytes;
return {referencePointBytes, encryptedContentBytes};
};
export var asymmetricDecryptBytes = 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(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 = sha512Bytes(kA.toRawBytes());
content = symmetricDecryptBytes(gibbrishBytes, symkeyBytes);
return content;
};
//endregion
//###########################################################
//region deffieHellman/ElGamal secrets
//###########################################################
// Hex Versions
//###########################################################
export var diffieHellmanSecretHash = 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(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 = sha512Hex(seedBytes);
return sharedSecretHex;
};
export var diffieHellmanSecretHashHex = diffieHellmanSecretHash;
export var createSharedSecretHash = diffieHellmanSecretHash;
export var createSharedSecretHashHex = diffieHellmanSecretHash;
export var diffieHellmanSecretRaw = 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(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(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 = 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(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 = 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(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 = sha512Bytes(seedBytes);
return sharedSecretBytes;
};
export var sharedSecretHashBytes = diffieHellmanSecretHashBytes;
export var diffieHellmanSecretRawBytes = 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(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(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 = 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(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, resultBuffer, salt, saltLength, sum, unpaddedLength;
content = tbut.utf8ToBytes(content);
contentLength = content.length;
saltLength = 33 + (crypto.randomBytes(1)[0] & 127);
salt = crypto.randomBytes(saltLength);
// Prefix is salt + 3 bytes
prefixLength = saltLength + 3;
unpaddedLength = prefixLength + contentLength;
overlap = unpaddedLength % 32;
padding = 32 - overlap;
fullLength = unpaddedLength + padding;
resultBuffer = new Uint8Array(fullLength);
// immediatly write the content to the resultBuffer
for (idx = j = 0, len = content.length; j < len; idx = ++j) {
c = content[idx];
resultBuffer[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];
resultBuffer[idx] = salt[idx];
}
// the last byte of the prefix is the padding length
resultBuffer[saltLength + 2] = padding;
// the postfix padding is the first salt bytes up to padding size
idx = 0;
end = fullLength - 1;
while (idx < padding) {
resultBuffer[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];
resultBuffer[idx] = salt[idx];
idx++;
}
// save the sum in the right bytes
resultBuffer[saltLength] = sum >> 8;
resultBuffer[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 (resultBuffer[saltLength] === resultBuffer[saltLength - 1] && resultBuffer[saltLength + 1] === 2 * resultBuffer[saltLength]) {
resultBuffer[saltLength - 1]++;
sum++;
resultBuffer[saltLength] = sum >> 8;
resultBuffer[saltLength + 1] = sum % 256;
}
return resultBuffer;
};
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