@tidecloak/js
Version:
TideCloak client side JS SDK
222 lines • 12.4 kB
JavaScript
"use strict";
//
// Tide Protocol - Infrastructure for a TRUE Zero-Trust paradigm
// Copyright (C) 2022 Tide Foundation Ltd
//
// This program is free software and is subject to the terms of
// the Tide Community Open Code License as published by the
// Tide Foundation Limited. You may modify it and redistribute
// it in accordance with and subject to the terms of that License.
// This program is distributed WITHOUT WARRANTY of any kind,
// including without any implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
// See the Tide Community Open Code License for more details.
// You should have received a copy of the Tide Community Open
// Code License along with this program.
// If not, see https://tide.org/licenses_tcoc2-0-0-en
//
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.GetDecryptedChallenge = GetDecryptedChallenge;
exports.PrismConvertReply = PrismConvertReply;
exports.CmkConvertReply = CmkConvertReply;
exports.ConvertRememberedReply = ConvertRememberedReply;
exports.AuthenticateBasicReply = AuthenticateBasicReply;
exports.AuthenticateConsentReply = AuthenticateConsentReply;
const Hash_js_1 = require("../Cryptide/Hashing/Hash.js");
const Utils_js_1 = require("../Tools/Utils.js");
const Serialization_js_1 = require("../Cryptide/Serialization.js");
const Math_js_1 = require("../Cryptide/Math.js");
const PrismConvertResponse_js_1 = __importDefault(require("../Models/Responses/KeyAuth/Convert/PrismConvertResponse.js"));
const index_js_1 = require("../Cryptide/index.js");
const DecryptedCMKConvertResponse_js_1 = __importDefault(require("../Models/Responses/KeyAuth/Convert/DecryptedCMKConvertResponse.js"));
const CMKConvertResponse_js_1 = __importDefault(require("../Models/Responses/KeyAuth/Convert/CMKConvertResponse.js"));
const DecryptedPrismConvertResponse_js_1 = __importDefault(require("../Models/Responses/KeyAuth/Convert/DecryptedPrismConvertResponse.js"));
const AuthRequest_js_1 = __importDefault(require("../Models/AuthRequest.js"));
const BlindSig_js_1 = require("../Cryptide/Signing/BlindSig.js");
const AuthenticateResponse_js_1 = __importDefault(require("../Models/Responses/KeyAuth/Authenticate/AuthenticateResponse.js"));
const DecryptedConvertRememberedResponse_js_1 = __importDefault(require("../Models/Responses/KeyAuth/Convert/DecryptedConvertRememberedResponse.js"));
const ConvertRememberedResponse_js_1 = __importDefault(require("../Models/Responses/KeyAuth/Convert/ConvertRememberedResponse.js"));
const VendorData_js_1 = __importDefault(require("../Models/VendorData.js"));
const Ed25519_js_1 = require("../Cryptide/Ed25519.js");
const Ed25519Components_js_1 = require("../Cryptide/Components/Schemes/Ed25519/Ed25519Components.js");
/**
* For use in change password flow
* @param {PrismConvertResponse[]} convertResponses
* @param {bigint[]} lis
* @param {Point[]} mgORKi
* @param {bigint} r1
* @returns
*/
async function GetDecryptedChallenge(convertResponses, lis, mgORKi, r1) {
const gPassPRISM = convertResponses.reduce((sum, next, i) => sum.add(next.GBlurPassPrismi.mul(lis[i])), Ed25519_js_1.Point.ZERO).mul((0, Math_js_1.mod_inv)(r1));
const gPassPRISM_hashed = (0, Math_js_1.mod)((0, Serialization_js_1.BigIntFromByteArray)(await (0, Hash_js_1.SHA256_Digest)(gPassPRISM.toRawBytes())));
const pre_prismAuthi = mgORKi.map(async (ork) => await (0, Hash_js_1.SHA256_Digest)(ork.mul(gPassPRISM_hashed).toRawBytes())); // create a prismAuthi for each ork
const prismAuthis = await Promise.all(pre_prismAuthi); // wait for all async functions to finish
let decryptedChallenges;
try {
const pre_decData = convertResponses.map(async (resp, i) => await index_js_1.AES.decryptData(resp.EncChallengei, prismAuthis[i]));
decryptedChallenges = await Promise.all(pre_decData);
}
catch {
throw Error("enclave.invalidAccount");
}
return decryptedChallenges;
}
/**
* @param {PrismConvertResponse[]} convertResponses
* @param {bigint[]} ids
* @param {Point[]} mgORKi
* @param {bigint} r1
* @param {Uint8Array[]} prkECDHi
*/
async function PrismConvertReply(convertResponses, ids, mgORKi, r1, prkECDHi) {
// ∑ gPass ⋅ r1 ⋅ PRISMi ⋅ li / r1
const gPassPRISM = index_js_1.Interpolation.AggregatePointsWithIds(convertResponses.map(resp => resp.GBlurPassPrismi), ids).divide(r1);
const gPassPRISM_hashed = await gPassPRISM.hash();
const prismAuthis = await index_js_1.DH.generateECDHi(mgORKi, gPassPRISM_hashed);
let decPrismRequesti;
try {
const pre_decPrismRequesti = convertResponses.map(async (chall, i) => DecryptedPrismConvertResponse_js_1.default.from(await index_js_1.AES.decryptData(chall.EncRequesti, prismAuthis[i])));
decPrismRequesti = await Promise.all(pre_decPrismRequesti);
}
catch {
throw Error("enclave.invalidAccount");
}
const timestampi = (0, Math_js_1.median)(decPrismRequesti.map(resp => resp.Timestampi));
const pre_selfRequesti = decPrismRequesti.map(async (req, i) => await index_js_1.AES.decryptData(req.PRKRequesti, prkECDHi[i]));
const selfRequesti = await Promise.all(pre_selfRequesti);
// Calculate when the stored token expires
const expired = (0, Utils_js_1.CurrentTime)() + (0, Math_js_1.Min)(decPrismRequesti.map(d => d.Exti));
return { prismAuthis, timestampi, selfRequesti, expired };
}
/**
* @param {CMKConvertResponse[]} convertResponses
* @param {bigint[]} ids
* @param {Uint8Array[]} prismAuthis
* @param {Point} gCMK
* @param {bigint} timestampi
* @param {string} sessID
* @param {string} purpose
* @param {Point} qPub
* @param {bigint} uDeObf
* @param {bigint} blurerKPriv
* @param {Ed25519PublicComponent} gSessKeyPub
*/
async function CmkConvertReply(convertResponses, ids, prismAuthis, gCMK, timestampi, sessID, purpose, qPub, uDeObf, blurerKPriv, gSessKeyPub) {
let decData;
try {
const pre_decData = convertResponses.map(async (resp, i) => DecryptedCMKConvertResponse_js_1.default.from(await index_js_1.AES.decryptData(resp.EncChallengei, prismAuthis[i])));
decData = await Promise.all(pre_decData);
}
catch {
throw Error("enclave.invalidAccount");
}
const userPRISM = index_js_1.Interpolation.AggregatePointsWithIds(decData.map(d => d.UserPRISMi), ids);
const userPRISMdec = userPRISM.mul((0, Math_js_1.mod)((0, Serialization_js_1.BigIntFromByteArray)(await index_js_1.DH.computeSharedKey(qPub, blurerKPriv))));
const gUserCMK = userPRISMdec.divide(uDeObf);
const gUserCMK_Hash = await index_js_1.Hash.SHA512_Digest(gUserCMK.toRawBytes());
const CMKMul = (0, Math_js_1.mod)((0, Serialization_js_1.BigIntFromByteArray)(gUserCMK_Hash.slice(0, 32)));
const VUID = (0, Serialization_js_1.Bytes2Hex)(gUserCMK_Hash.slice(-32));
const gCMKAuth = gCMK.mul(CMKMul);
const gCMKR = index_js_1.Interpolation.AggregatePoints(convertResponses.map(resp => resp.GCMKRi));
const authToken = AuthRequest_js_1.default.new(VUID, purpose, gSessKeyPub.Serialize().ToString(), timestampi + (0, Utils_js_1.randBetween)(30, 90), sessID);
const { blurHCMKMul, blur, gRMul } = await (0, BlindSig_js_1.genBlindMessage)(gCMKR, gCMKAuth, authToken.toUint8Array(), CMKMul);
return { VUID: VUID, blurHCMKMul, r4: blur, gCMKAuth, authToken, gRMul };
}
/**
* @param {ConvertRememberedResponse[]} responses
* @param {bigint[]} mIdORKi
* @param {Point} gCMK
* @param {string} sessID
* @param {Uint8Array[]} prkECDHi
* @param {Point} qPub
* @param {bigint} uDeObf
* @param {bigint} blurerKPriv
* @param {Ed25519PublicComponent} gSessKeyPub
*/
async function ConvertRememberedReply(responses, mIdORKi, gCMK, sessID, prkECDHi, qPub, uDeObf, blurerKPriv, gSessKeyPub) {
const pre_decryptedResonses = responses.map((async (resp, i) => DecryptedConvertRememberedResponse_js_1.default.from(await index_js_1.AES.decryptData(resp.EncRequesti, prkECDHi[i]))));
const decryptedResponses = await Promise.all(pre_decryptedResonses);
const timestamp = index_js_1.Math.median(decryptedResponses.map(d => d.timestampi));
const userPRISM = index_js_1.Interpolation.AggregatePointsWithIds(decryptedResponses.map(d => d.UserPRISMi), mIdORKi);
const userPRISMdec = userPRISM.mul((0, Math_js_1.mod)((0, Serialization_js_1.BigIntFromByteArray)(await index_js_1.DH.computeSharedKey(qPub, blurerKPriv))));
const gUserCMK = userPRISMdec.divide(uDeObf);
const gUserCMK_Hash = await index_js_1.Hash.SHA512_Digest(gUserCMK.toRawBytes());
const CMKMul = (0, Math_js_1.mod)((0, Serialization_js_1.BigIntFromByteArray)(gUserCMK_Hash.slice(0, 32)));
const VUID = (0, Serialization_js_1.Bytes2Hex)(gUserCMK_Hash.slice(-32));
const gCMKAuth = gCMK.mul(CMKMul);
const gCMKR = index_js_1.Interpolation.AggregatePoints(responses.map(resp => resp.GCMKRi));
const authToken = AuthRequest_js_1.default.new(VUID, "auth", gSessKeyPub.Serialize().ToString(), timestamp + (0, Utils_js_1.randBetween)(30, 90), sessID);
const { blurHCMKMul, blur: r4, gRMul } = await (0, BlindSig_js_1.genBlindMessage)(gCMKR, gCMKAuth, authToken.toUint8Array(), CMKMul);
return {
VUID,
gCMKAuth,
blurHCMKMul,
r4,
gRMul,
authToken,
prkECDHi
};
}
/**
*
* @param {string} vuid
* @param {Uint8Array[]} prkECDHi
* @param {string[]} encSigi
* @param {Point} gCMKAuth
* @param {AuthRequest} authToken
* @param {bigint} r4
* @param {Point} gRMul
* @param {Point} gVRK
*/
async function AuthenticateBasicReply(vuid, prkECDHi, encSigi, gCMKAuth, authToken, r4, gRMul, gVRK) {
const pre_authResp = encSigi.map(async (enc, i) => AuthenticateResponse_js_1.default.from(await index_js_1.AES.decryptData(enc, prkECDHi[i])));
const authResp = await Promise.all(pre_authResp);
const blindS = (0, Math_js_1.mod)(authResp.reduce((sum, next) => sum + next.Si, BigInt(0)));
const sig = await (0, BlindSig_js_1.unblindSignature)(blindS, r4);
const blindSigValid = await (0, BlindSig_js_1.verifyBlindSignature)(sig, gRMul, gCMKAuth, authToken.toUint8Array());
if (!blindSigValid)
throw Error("Blind Signature Failed");
const blindSig = (0, Serialization_js_1.bytesToBase64)((0, BlindSig_js_1.serializeBlindSig)(sig, gRMul));
if (gVRK == null) {
const vendorData = new VendorData_js_1.default(vuid, gCMKAuth, blindSig, authToken).toString();
return vendorData;
}
else {
const VendorEncryptedData = await index_js_1.ElGamal.encryptData((0, Serialization_js_1.StringToUint8Array)(new VendorData_js_1.default(vuid, gCMKAuth, blindSig, authToken).toString()), gVRK);
return VendorEncryptedData;
}
}
/**
*
* @param {string} vuid
* @param {Uint8Array[]} prkECDHi
* @param {string[]} encSigi
* @param {Point} gCMKAuth
* @param {AuthRequest} authToken
* @param {bigint} r4
* @param {Point} gRMul
* @param {Point} gVRK
* @param {bigint} sessKey
* @param {string} consentToSign
*/
async function AuthenticateConsentReply(vuid, prkECDHi, encSigi, gCMKAuth, authToken, r4, gRMul, gVRK, sessKey, consentToSign) {
const pre_authResp = encSigi.map(async (enc, i) => AuthenticateResponse_js_1.default.from(await index_js_1.AES.decryptData(enc, prkECDHi[i])));
const authResp = await Promise.all(pre_authResp);
const blindS = (0, Math_js_1.mod)(authResp.reduce((sum, next) => sum + next.Si, BigInt(0)));
const sig = await (0, BlindSig_js_1.unblindSignature)(blindS, r4);
const blindSigValid = await (0, BlindSig_js_1.verifyBlindSignature)(sig, gRMul, gCMKAuth, authToken.toUint8Array());
if (!blindSigValid)
throw Error("Blind Signature Failed");
const blindSig = (0, Serialization_js_1.bytesToBase64)((0, BlindSig_js_1.serializeBlindSig)(sig, gRMul));
const vendorData = new VendorData_js_1.default(vuid, gCMKAuth, blindSig, authToken);
const VendorEncryptedData = await index_js_1.ElGamal.encryptData((0, Serialization_js_1.StringToUint8Array)(JSON.stringify({
VendorData: vendorData.toString(),
Consent: (await index_js_1.EdDSA.sign(consentToSign, sessKey))
})), gVRK);
return VendorEncryptedData;
}
//# sourceMappingURL=KeyAuthentication.js.map