UNPKG

@tidecloak/js

Version:

TideCloak client side JS SDK

180 lines 9.49 kB
"use strict"; 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