@tidecloak/js
Version:
TideCloak client side JS SDK
180 lines • 9.49 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AuthorizedEncryptionFlow = AuthorizedEncryptionFlow;
const index_js_1 = require("../../Cryptide/index.js");
const Ed25519Components_js_1 = require("../../Cryptide/Components/Schemes/Ed25519/Ed25519Components.js");
const AES_js_1 = require("../../Cryptide/Encryption/AES.js");
const Serialization_js_1 = require("../../Cryptide/Serialization.js");
const Utils_js_1 = require("../../Tools/Utils.js");
const BaseTideRequest_js_1 = __importDefault(require("../../Models/BaseTideRequest.js"));
const NetworkClient_js_1 = __importDefault(require("../../Clients/NetworkClient.js"));
const dVVKSigningFlow_js_1 = __importDefault(require("../SigningFlows/dVVKSigningFlow.js"));
const Math_js_1 = require("../../Cryptide/Math.js");
const SerializedField_js_1 = __importDefault(require("../../Models/SerializedField.js"));
const dVVKDecryptionFlow_js_1 = __importDefault(require("../DecryptionFlows/dVVKDecryptionFlow.js"));
const Doken_js_1 = require("../../Models/Doken.js");
const TideKey_js_1 = __importDefault(require("../../Cryptide/TideKey.js"));
const KeyInfo_js_1 = __importDefault(require("../../Models/Infos/KeyInfo.js"));
/**
*
* @param {{
* vendorId: string,
* token: Doken,
* sessionKey: TideKey
* voucherURL: string,
* homeOrkUrl: string | null
* keyInfo: KeyInfo
* }} config
*/
function AuthorizedEncryptionFlow(config) {
if (!(this instanceof AuthorizedEncryptionFlow)) {
throw new Error("The 'AuthorizedEncryptionFlow' constructor must be invoked with 'new'.");
}
var encryptionFlow = this;
if (!config.token.payload.sessionKey.Equals(config.sessionKey.get_public_component())) {
throw Error("Mismatch between session key private and Doken session key public");
}
encryptionFlow.vvkId = config.vendorId;
encryptionFlow.token = config.token;
encryptionFlow.sessKey = config.sessionKey;
encryptionFlow.voucherURL = config.voucherURL;
encryptionFlow.vvkInfo = config.keyInfo;
/**
*
* @param {[
* {
* data: Uint8Array,
* tags: string[]
* }
* ]} datasToEncrypt
* @returns
*/
encryptionFlow.encrypt = async function (datasToEncrypt) {
const encReqs = await Promise.all(datasToEncrypt.map(async (d) => {
const d_b = d.data;
if (d_b.length < 32) {
// if data is less than 32B
// Gr. EncryptedData
const encryptedData = await index_js_1.ElGamal.encryptDataRaw(d_b, encryptionFlow.vvkInfo.UserPublic);
const tags_b = d.tags.map(t => (0, Serialization_js_1.StringToUint8Array)(t));
return {
encryptionToSign: encryptedData,
encryptedData: encryptedData,
tags: tags_b,
sizeLessThan32: true
};
}
else {
// if data is more than 32B
const largeDataKey = window.crypto.getRandomValues(new Uint8Array(32));
const encryptedData = await (0, AES_js_1.encryptDataRawOutput)(d_b, largeDataKey);
const encryptedKey = await index_js_1.ElGamal.encryptDataRaw(largeDataKey, encryptionFlow.vvkInfo.UserPublic);
const tags_b = d.tags.map(t => (0, Serialization_js_1.StringToUint8Array)(t));
return {
encryptionToSign: encryptedKey,
encryptedData: encryptedData,
tags: tags_b,
sizeLessThan32: false
};
}
}));
// Start signing flow to authorize this encryption
const timestamp = (0, Utils_js_1.CurrentTime)();
const timestamp_b = (0, Serialization_js_1.numberToUint8Array)(timestamp, 8);
const size = encReqs.reduce((sum, next) => {
// init 4 + as we'll be creating tide memory within tide memory
// + 4 again since its another index
const nsize = 4 + 4 + (4 + next.encryptionToSign.length + next.tags.reduce((sum, next) => sum + 4 + next.length, 0));
return sum + nsize;
}, 0) + 4 + timestamp_b.length;
const draft = index_js_1.Serialization.CreateTideMemory(timestamp_b, size);
encReqs.forEach((enc, i) => {
const entry = index_js_1.Serialization.CreateTideMemory(enc.encryptionToSign, 4 + enc.encryptionToSign.length + enc.tags.reduce((sum, next) => sum + 4 + next.length, 0));
enc.tags.forEach((tag, j) => {
index_js_1.Serialization.WriteValue(entry, j + 1, tag);
});
index_js_1.Serialization.WriteValue(draft, i + 1, entry);
});
const encryptionRequest = new BaseTideRequest_js_1.default("TideSelfEncryption", "1", "Doken:1", draft);
// Deserialize token to retrieve vuid - if it exists
const vuid = this.token.payload.vuid;
if (vuid)
encryptionRequest.dyanmicData = (0, Serialization_js_1.StringToUint8Array)(vuid);
// Initiate signing flow
const encryptingSigningFlow = new dVVKSigningFlow_js_1.default(this.vvkId, encryptionFlow.vvkInfo.UserPublic, encryptionFlow.vvkInfo.OrkInfo, encryptionFlow.sessKey, encryptionFlow.token, this.voucherURL);
const signatures = await encryptingSigningFlow.start(encryptionRequest);
// Construct final serialized payloads for client to store
return signatures.map((sig, i) => SerializedField_js_1.default.create(encReqs[i].encryptedData, timestamp, encReqs[i].sizeLessThan32 ? null : encReqs[i].encryptionToSign, sig));
};
/**
*
* @param {[
* {
* encrypted: Uint8Array,
* tags: string[]
* }
* ]} datasToDecrypt
*/
encryptionFlow.decrypt = async function (datasToDecrypt) {
// Deserialize all datasToDecrypt + include tags in object
const deserializedDatas = datasToDecrypt.map(d => {
const b = SerializedField_js_1.default.deserialize(d.encrypted);
if (b.signature == null)
throw Error("Signature must be provided in Tide Serialized Data to an Authorized Decryption");
const tags_b = d.tags.map(t => (0, Serialization_js_1.StringToUint8Array)(t));
return {
...b,
tags: tags_b
};
});
// Get orks to apply vvk
const entries = deserializedDatas.map((data, i) => {
if (data.encKey) {
// We must decrypt the encrypted key, not the data itself
const entry = index_js_1.Serialization.CreateTideMemory(data.encKey, 4 + data.encKey.length + 4 + data.signature.length + 4 + data.timestamp.length + data.tags.reduce((sum, next) => sum + 4 + next.length, 0));
index_js_1.Serialization.WriteValue(entry, 1, data.signature); // won't be null
index_js_1.Serialization.WriteValue(entry, 2, data.timestamp);
data.tags.forEach((tag, j) => {
index_js_1.Serialization.WriteValue(entry, j + 3, tag); // + 3 as we start at index 3
});
return entry;
}
else {
// decrypt data directly
const entry = index_js_1.Serialization.CreateTideMemory(data.encFieldChk, 4 + data.encFieldChk.length + 4 + data.signature.length + 4 + data.timestamp.length + data.tags.reduce((sum, next) => sum + 4 + next.length, 0));
index_js_1.Serialization.WriteValue(entry, 1, data.signature); // won't be null
index_js_1.Serialization.WriteValue(entry, 2, data.timestamp);
data.tags.forEach((tag, j) => {
index_js_1.Serialization.WriteValue(entry, j + 3, tag); // + 3 as we start at index 3
});
return entry;
}
});
const draft = index_js_1.Serialization.CreateTideMemory(entries[0], entries.reduce((sum, next) => sum + 4 + next.length, 0));
for (let i = 1; i < entries.length; i++) {
index_js_1.Serialization.WriteValue(draft, i, entries[i]);
}
const decryptionRequest = new BaseTideRequest_js_1.default("SelfDecrypt", "1", "Doken:1", draft);
const flow = new dVVKDecryptionFlow_js_1.default(this.vvkId, this.vvkInfo.UserPublic, this.vvkInfo.OrkInfo, this.sessKey, this.token, this.voucherURL);
const dataKeys = await flow.start(decryptionRequest);
// Decrypt all datas
const decryptedDatas = await Promise.all(deserializedDatas.map(async (data, i) => {
// if encKey exists - decrypt with elgamal that
// then decrypt encField with key
if (data.encKey) {
const key = await (0, AES_js_1.decryptDataRawOutput)(data.encKey.slice(32), dataKeys[i]);
return await (0, AES_js_1.decryptDataRawOutput)(data.encFieldChk, key);
}
else {
// else - decrypt encField with elgamal
return await (0, AES_js_1.decryptDataRawOutput)(data.encFieldChk.slice(32), dataKeys[i]);
}
}));
// Return as bytes
return decryptedDatas;
};
}
//# sourceMappingURL=AuthorizedEncryptionFlow.js.map