UNPKG

@meeco/cryppo

Version:

In-browser encryption and decryption. Clone of Ruby Cryppo

990 lines (866 loc) 30.1 kB
import { Buffer } from 'buffer'; import { __assign, __awaiter, __generator } from 'tslib'; import { util, random, pki, md, pkcs5, cipher, hmac } from 'node-forge'; import { deserialize, serialize as serialize$1 } from 'bson'; import { defaultOptions, stringify, parse } from 'yaml'; var SerializationFormat; (function (SerializationFormat) { SerializationFormat["legacy"] = "legacy"; SerializationFormat["latest_version"] = "latest_version"; })(SerializationFormat || (SerializationFormat = {})); defaultOptions.schema = 'yaml-1.1'; // 65 is the version byte for encryption artefacts encoded with BSON var ENCRYPTION_ARTEFACTS_CURRENT_VERSION = 'A'; // 75 is the version byte for derivation artefacts encoded with BSON var DERIVATION_ARTEFACTS_CURRENT_VERSION = 'K'; /** * Wrapping some node-forge utils in case we ever need to replace it */ var encode64 = util.encode64; var decode64 = util.decode64; var encodeUtf8 = util.encodeUtf8; var utf8ToBytes = util.text.utf8.encode; var utf16ToBytes = util.text.utf16.encode; var binaryStringToBytes = util.binary.raw.decode; var bytesToBinaryString = function bytesToBinaryString(bytes) { var binary = ''; var len = bytes.byteLength; for (var i = 0; i < len; i++) { binary += String.fromCharCode(bytes[i]); } return binary; }; var bytesToUtf16 = function bytesToUtf16(bytes) { var binary = ''; var utf16Bytes = new Uint16Array(bytes.buffer); var len = utf16Bytes.byteLength; for (var i = 0; i < len; i++) { binary += String.fromCharCode(utf16Bytes[i]); } return binary; }; var bytesToUtf8 = function bytesToUtf8(bytes) { var binary = ''; var len = bytes.byteLength; for (var i = 0; i < len; i++) { binary += String.fromCharCode(bytes[i]); } return util.decodeUtf8(binary); }; var binaryStringToBytesBuffer = function binaryStringToBytesBuffer(value) { return Buffer.from(util.binary.raw.decode(value)); }; var bytesBufferToBinaryString = function bytesBufferToBinaryString(val) { return util.createBuffer(val).data; }; var generateRandomBytesString = function generateRandomBytesString(length) { if (length === void 0) { length = 32; } return random.getBytesSync(length); }; function serializeDerivedKeyOptions(strategy, artifacts, serializationFormat) { if (serializationFormat === void 0) { serializationFormat = SerializationFormat.latest_version; } switch (serializationFormat) { case SerializationFormat.legacy: { var yaml = encodeYaml(artifacts); return strategy + "." + encodeSafe64(yaml); } default: { return strategy + "." + encodeSafe64Bson(DERIVATION_ARTEFACTS_CURRENT_VERSION, artifacts); } } } function deSerializeDerivedKeyOptions(serialized) { var items = serialized.split('.'); // We might get passed an entire encrypted string in which case we just want the key and strategy if (items.length > 2) { items = items.slice(-2); } var derivationStrategy = items[0], artifacts = items[1]; var serializationArtifacts = decodeArtifactData(artifacts); return { derivationStrategy: derivationStrategy, serializationArtifacts: serializationArtifacts }; } function serialize(strategy, data, artifacts, serializationFormat) { if (serializationFormat === void 0) { serializationFormat = SerializationFormat.latest_version; } switch (serializationFormat) { case SerializationFormat.legacy: { var yaml = encodeYaml(artifacts); return strategy + "." + encodeSafe64(data) + "." + encodeSafe64(yaml); } default: { return strategy + "." + encodeSafe64(data) + "." + encodeSafe64Bson(ENCRYPTION_ARTEFACTS_CURRENT_VERSION, artifacts); } } } function encodeYaml(data) { // Note the pad and binary replacements are only for backwards compatibility // with Ruby Cryppo. They technically should not be required and there should // be a flag to disable them. var pad = "---\n"; return pad + stringify(data).replace(/!!binary/g, '!binary'); } function deSerialize(serialized) { var items = serialized.split('.'); if (items.length < 2) { throw new Error('String is not a serialized encrypted string'); } if (items.length % 2 !== 1) { throw new Error('Serialized string should have an encryption strategy and pairs of encoded data and artifacts'); } var encryptionStrategy = items[0]; var decodedPairs = items.slice(1).map(function (item, i) { if (i % 2 === 0) { // Base64 encoded encrypted data return decodeSafe64(item); } else { return decodeArtifactData(item); } }); if (!decodedPairs.length) { throw new Error('No data found to decrypt in serialized string'); } return { encryptionStrategy: encryptionStrategy, decodedPairs: decodedPairs }; } // tslint:disable-next-line: max-line-length function decodeArtifactData(text) { if (decodeSafe64(text).startsWith('---')) { text = decodeSafe64(text); return parse(text.replace(/ !binary/g, ' !!binary')); } else { text = decodeSafe64Bson(text); // remove version byte before deserializing return deserialize(Buffer.from(text, 'base64').slice(1), { promoteBuffers: true }); } } /** * The Ruby version uses url safe base64 encoding. * RFC 4648 specifies + is encoded as - and / is _ * with the trailing = removed. */ function encodeSafe64(data) { return encode64(data).replace(/\+/g, '-') // Convert '+' to '-' .replace(/\//g, '_'); // Convert '/' to '_' // Not we don't remove the trailing '=' as specified in the spec // because ruby's Base64.urlsafe_encode64 does not do this // and we want to maintain compatibility. } function decodeSafe64(base64) { return decode64(base64.replace(/-/g, '+') // Convert '+' to '-' .replace(/_/g, '/')); // Don't bother concatenating an '=' to the result - see above } // tslint:disable-next-line: max-line-length function encodeSafe64Bson(versionByte, artifacts) { var bsonSerialized = Buffer.concat([Buffer.from(versionByte), serialize$1(artifacts)]); var base64Data = bsonSerialized.toString('base64'); return base64Data.replace(/\+/g, '-') // Convert '+' to '-' .replace(/\//g, '_'); // Convert '/' to '_' // Not we don't remove the trailing '=' as specified in the spec // because ruby's Base64.urlsafe_encode64 does not do this // and we want to maintain compatibility. } function decodeSafe64Bson(base64) { return base64.replace(/-/g, '+') // Convert '+' to '-' .replace(/_/g, '/'); // Don't bother concatenating an '=' to the result - see above } function encodeDerivationArtifacts(artifacts) { return encodeSafe64(JSON.stringify(artifacts)); } function decodeDerivationArtifacts(encoded) { return JSON.parse(decodeSafe64(encoded)); } /** * Returns some base64 encoded random bytes that can be used for encryption verification. */ function generateEncryptionVerificationArtifacts() { var token = random.getBytesSync(16); var salt = random.getBytesSync(16); return { token: encodeSafe64(token), salt: encodeSafe64(salt) }; } function keyLengthFromPublicKeyPem(publicKeyPem) { var pk = pki.publicKeyFromPem(publicKeyPem); // Undocumented functionality but was the only way I could find to get // key length out of the public key. // https://github.com/digitalbazaar/forge/blob/master/lib/rsa.js#L1244 var bitLength = pk.n.bitLength(); return bitLength; } function keyLengthFromPrivateKeyPem(privateKey) { var pk = pki.privateKeyFromPem(privateKey); // Undocumented functionality but was the only way I could find to get // key length out of the public key. // https://github.com/digitalbazaar/forge/blob/master/lib/rsa.js#L1244 var bitLength = pk.n.bitLength(); return bitLength; } var EncodingVersions; (function (EncodingVersions) { EncodingVersions["legacy"] = "legacy"; EncodingVersions["latest_version"] = "latest_version"; })(EncodingVersions || (EncodingVersions = {})); /** * SymmetricKey that can be used to encrypt and decrypt data * This wrapper ensures that keys can be safely serialized as JSON (by encoding them as URL-Safe Base64) * and avoids confusion when dealing with converting to and from this encoded format. */ var EncryptionKey = /** @class */ function () { /** * The constructor is intentionally private as we want the user ot be explicit as to whether the value coming * in is raw bytes or a base64 encoded version. * * @param value Value as binary string. Avoid outputting to console but should be used for actual encryption. */ function EncryptionKey(value) { this.value = value; } EncryptionKey.fromSerialized = function (value) { this.checkStringValue(value); return new EncryptionKey(binaryStringToBytes(decodeSafe64(value))); }; EncryptionKey.fromBytes = function (bytes) { this.checkBytesValue(bytes); return new EncryptionKey(bytes); }; EncryptionKey.generateRandom = function (length) { if (length === void 0) { length = 32; } return new EncryptionKey(binaryStringToBytes(random.getBytesSync(length))); }; EncryptionKey.checkStringValue = function (value) { value = value.trim(); if (!value) { throw new Error('bytes are empty or undefined'); } }; EncryptionKey.checkBytesValue = function (value) { if (!value || value.length === 0) { throw new Error('bytes are empty or undefined'); } }; Object.defineProperty(EncryptionKey.prototype, "serialize", { /** * Encode a key in a human-readable and url-safe format. */ get: function get() { return encodeSafe64(bytesToBinaryString(this.value)); }, enumerable: false, configurable: true }); Object.defineProperty(EncryptionKey.prototype, "bytes", { get: function get() { return this.value; }, enumerable: false, configurable: true }); return EncryptionKey; }(); /** * Most of these values are copied directly from the Ruby library */ var MIN_ITERATIONS = 20000; var DEFAULT_LENGTH = 32; var DEFAULT_ITERATION_VARIANCE = 10; var DEFAULT_SALT_LENGTH = 20; var KeyDerivationStrategy; (function (KeyDerivationStrategy) { KeyDerivationStrategy["Pbkdf2Hmac"] = "Pbkdf2Hmac"; })(KeyDerivationStrategy || (KeyDerivationStrategy = {})); /** * Store configuration used for password based key derivation and * serialize/de-serialize it. */ var DerivedKeyOptions = /** @class */ function () { function DerivedKeyOptions(options) { this.salt = options.salt; this.iterations = options.iterations; this.length = options.length; this.strategy = options.strategy; this.hash = options.hash || 'SHA256'; } DerivedKeyOptions.usesDerivedKey = function (serialized) { var parts = serialized.split('.'); if (parts[parts.length - 2] === KeyDerivationStrategy.Pbkdf2Hmac) { return true; } return false; }; DerivedKeyOptions.randomFromOptions = function (_a) { var _b = _a.iterationVariance, iterationVariance = _b === void 0 ? DEFAULT_ITERATION_VARIANCE : _b, _c = _a.length, length = _c === void 0 ? DEFAULT_LENGTH : _c, _d = _a.minIterations, minIterations = _d === void 0 ? MIN_ITERATIONS : _d, _e = _a.strategy, strategy = _e === void 0 ? KeyDerivationStrategy.Pbkdf2Hmac : _e, useSalt = _a.useSalt; var variance = Math.floor(minIterations * (iterationVariance / 100)); var iterations = minIterations + Math.floor(Math.random() * variance); var salt = useSalt || random.getBytesSync(DEFAULT_SALT_LENGTH); return new DerivedKeyOptions({ strategy: strategy, iterations: iterations, salt: salt, length: length }); }; // tslint:disable-next-line: max-line-length DerivedKeyOptions.fromSerialized = function (serialized) { // tslint:disable-next-line: max-line-length var _a = deSerializeDerivedKeyOptions(serialized), derivationStrategy = _a.derivationStrategy, serializationArtifacts = _a.serializationArtifacts; return new DerivedKeyOptions(__assign({ // keys taken from ruby lib strategy: derivationStrategy, salt: bytesBufferToBinaryString(serializationArtifacts.iv), iterations: serializationArtifacts.i, length: serializationArtifacts.l, hash: serializationArtifacts.hash }, serializationArtifacts)); }; DerivedKeyOptions.prototype.serialize = function (serializationVersion) { if (serializationVersion === void 0) { serializationVersion = SerializationFormat.latest_version; } // keys taken from ruby lib return serializeDerivedKeyOptions(this.strategy, { iv: binaryStringToBytesBuffer(this.salt), i: this.iterations, l: this.length, hash: this.hash }, serializationVersion); }; DerivedKeyOptions.prototype.deriveKey = function (key, encodingVersion) { var _this = this; if (encodingVersion === void 0) { encodingVersion = EncodingVersions.latest_version; } var hash = this.hash.toLocaleLowerCase(); var digest = md[hash].create(); key = encodingVersion === EncodingVersions.legacy ? key : encodeUtf8(key); return new Promise(function (resolve, reject) { return pkcs5.pbkdf2(key, _this.salt, _this.iterations, _this.length, digest, function (err, derivedKey) { if (err) { return reject(err); } resolve(EncryptionKey.fromBytes(binaryStringToBytes(derivedKey))); }); }); }; return DerivedKeyOptions; }(); var CipherStrategy; (function (CipherStrategy) { CipherStrategy["AES_GCM"] = "AES-GCM"; // AES_ECB = 'AES-ECB', // Require 16 bytes IV And not tested crosscompatiblity with other cryppo // AES_CBC = 'AES-CBC', // AES_CFB = 'AES-CFB', // AES_OFB = 'AES-OFB', // AES_CTR = 'AES-CTR', // DES_ECB = 'DES-ECB', // DES_CBC = 'DES-CBC', // Not currently suppoted as they have different key size (256 not supported) // THREE_DES_ECB = '3DES-ECB', // THREE_DES_CBC = '3DES-CBC', })(CipherStrategy || (CipherStrategy = {})); /* * Convert an algorithm from a serialized payload (e.g Aes256Gcm.data.artifacts) in the ruby lib's naming * scheme to one that can be used by forge */ var strategyToAlgorithm = function strategyToAlgorithm(algorithm) { return algorithm.split(/[0-9]+/).map(function (v) { return v.toUpperCase(); }).join('-'); }; function decryptWithKeyDerivedFromString(_a) { var serialized = _a.serialized, passphrase = _a.passphrase, _b = _a.encodingVersion, encodingVersion = _b === void 0 ? EncodingVersions.latest_version : _b; return __awaiter(this, void 0, void 0, function () { var derivedKey; return __generator(this, function (_c) { switch (_c.label) { case 0: return [4 /*yield*/ , _deriveKeyWithOptions({ key: passphrase, serializedOptions: serialized, encodingVersion: encodingVersion })]; case 1: derivedKey = _c.sent(); return [4 /*yield*/ , decryptWithKey({ serialized: serialized.split('.').slice(0, 3).join('.'), key: derivedKey })]; case 2: return [2 /*return*/ , _c.sent()]; } }); }); } function decryptWithKey(_a) { var serialized = _a.serialized, key = _a.key; return __awaiter(this, void 0, void 0, function () { var deSerialized, encryptionStrategy, decodedPairs, output, legacyKey, i, data, artifacts, strategy, decrypted, err_1; return __generator(this, function (_b) { switch (_b.label) { case 0: deSerialized = deSerialize(serialized); encryptionStrategy = deSerialized.encryptionStrategy; decodedPairs = deSerialized.decodedPairs; if (decodedPairs[0] === '') { return [2 /*return*/ , null]; } output = null; i = 0; _b.label = 1; case 1: if (!(i < decodedPairs.length)) return [3 /*break*/ , 8]; data = decodedPairs[i]; artifacts = decodedPairs[i + 1]; strategy = strategyToAlgorithm(encryptionStrategy); _b.label = 2; case 2: _b.trys.push([2, 3,, 7]); decrypted = decryptWithKeyUsingArtefacts(legacyKey ? legacyKey : key, data, strategy, artifacts); // ensure correct type output = decrypted ? new Uint8Array(decrypted) : null; return [3 /*break*/ , 7]; case 3: err_1 = _b.sent(); if (!(!legacyKey && encodeUtf8(bytesToBinaryString(key.bytes)) !== bytesToBinaryString(key.bytes) && DerivedKeyOptions.usesDerivedKey(serialized))) return [3 /*break*/ , 5]; return [4 /*yield*/ , _deriveKeyWithOptions({ key: bytesToBinaryString(key.bytes), serializedOptions: serialized, encodingVersion: EncodingVersions.legacy })]; case 4: // Decryption failed with utf-8 key style - retry with legacy utf-16 key format legacyKey = _b.sent(); i -= 2; return [3 /*break*/ , 7]; case 5: // Both utf-8 and utf-16 key formats have failed - bail throw err_1; case 6: return [3 /*break*/ , 7]; case 7: i += 2; return [3 /*break*/ , 1]; case 8: return [2 /*return*/ , output]; } }); }); } /** * Determine if we need to use a derived key or not based on whether or not * we have key derivation options in the serialized payload. */ // tslint:disable-next-line: max-line-length function _deriveKeyWithOptions(_a) { var key = _a.key, serializedOptions = _a.serializedOptions, _b = _a.encodingVersion, encodingVersion = _b === void 0 ? EncodingVersions.latest_version : _b; var derivedKeyOptions = DerivedKeyOptions.fromSerialized(serializedOptions); return derivedKeyOptions.deriveKey(key, encodingVersion); } function decryptWithKeyUsingArtefacts(key, encryptedData, strategy, _a) { var iv = _a.iv, at = _a.at, ad = _a.ad; if (encryptedData === '') { return null; } var decipher = cipher.createDecipher(strategy, util.createBuffer(key.bytes)); var tagLength = 128; var tag = util.createBuffer(at); // authentication tag from encryption var encrypted = util.createBuffer(encryptedData); decipher.start({ iv: util.createBuffer(iv), additionalData: ad, tagLength: tagLength, tag: tag }); decipher.update(encrypted); var pass = decipher.finish(); // pass is false if there was a failure (eg: authentication tag didn't match) if (pass) { return binaryStringToBytesBuffer(decipher.output.data); } throw new Error('Decryption failed'); } /** * Given a password/phrase, derive a fixed-length key from it using Pbkdf2Hmac. * Various derivation arguments can be provided to ensure deterministic results * (i.e. to derive the same key again from the same password/phrase). */ function generateDerivedKey(_a) { var passphrase = _a.passphrase, length = _a.length, minIterations = _a.minIterations, iterationVariance = _a.iterationVariance, useSalt = _a.useSalt; return __awaiter(this, void 0, void 0, function () { var derivedKeyOptions, derivedKey; return __generator(this, function (_b) { switch (_b.label) { case 0: derivedKeyOptions = DerivedKeyOptions.randomFromOptions({ iterationVariance: iterationVariance, length: length, minIterations: minIterations, strategy: KeyDerivationStrategy.Pbkdf2Hmac, useSalt: useSalt }); return [4 /*yield*/ , derivedKeyOptions.deriveKey(passphrase)]; case 1: derivedKey = _b.sent(); return [2 /*return*/ , { key: derivedKey, options: derivedKeyOptions }]; } }); }); } function encryptWithGeneratedKey(_a, serializationVersion) { var data = _a.data, strategy = _a.strategy, keyLength = _a.keyLength, iv = _a.iv; if (serializationVersion === void 0) { serializationVersion = SerializationFormat.latest_version; } return __awaiter(this, void 0, void 0, function () { var key, result; return __generator(this, function (_b) { switch (_b.label) { case 0: key = EncryptionKey.generateRandom(keyLength || 32); return [4 /*yield*/ , encryptWithKey({ key: key, data: data, strategy: strategy, iv: iv }, serializationVersion)]; case 1: result = _b.sent(); return [2 /*return*/ , __assign(__assign({}, result), { generatedKey: key })]; } }); }); } function encryptWithKeyDerivedFromString(_a) { var passphrase = _a.passphrase, data = _a.data, strategy = _a.strategy, iv = _a.iv, _b = _a.serializationVersion, serializationVersion = _b === void 0 ? SerializationFormat.latest_version : _b; return __awaiter(this, void 0, void 0, function () { var derived, result, serializedKey; return __generator(this, function (_c) { switch (_c.label) { case 0: return [4 /*yield*/ , generateDerivedKey({ passphrase: passphrase })]; case 1: derived = _c.sent(); return [4 /*yield*/ , encryptWithKey({ key: derived.key, data: data, strategy: strategy, iv: iv }, serializationVersion)]; case 2: result = _c.sent(); serializedKey = derived.options.serialize(serializationVersion); result.serialized = result.serialized + "." + serializedKey; return [2 /*return*/ , __assign(__assign({}, result), derived)]; } }); }); } function encryptWithKey(_a, serializationVersion) { var key = _a.key, data = _a.data, strategy = _a.strategy, iv = _a.iv; if (serializationVersion === void 0) { serializationVersion = SerializationFormat.latest_version; } return __awaiter(this, void 0, void 0, function () { var output, encrypted, artifacts, keyLengthBits, _b, cipher, mode, serialized; return __generator(this, function (_c) { if (!data || data.length === 0) { return [2 /*return*/ , { encrypted: null, serialized: null }]; } output = encryptWithKeyUsingArtefacts({ key: key, data: data, strategy: strategy, iv: iv }); encrypted = output.encrypted, artifacts = output.artifacts; keyLengthBits = key.bytes.length * 8; _b = strategy.split('-').map(upperWords), cipher = _b[0], mode = _b[1]; serialized = serialize("" + cipher + keyLengthBits + mode, encrypted || '', artifacts, serializationVersion); return [2 /*return*/ , { encrypted: encrypted, serialized: serialized }]; }); }); } /** * UpperCamelCase helper */ var upperWords = function upperWords(val) { return val.slice(0, 1).toUpperCase() + val.slice(1).toLowerCase(); }; function encryptWithKeyUsingArtefacts(_a) { var key = _a.key, data = _a.data, strategy = _a.strategy, iv = _a.iv; if (data.length === 0) { return { encrypted: null }; } var cipher$1 = cipher.createCipher(strategy, util.createBuffer(key.bytes)); iv = iv || random.getBytesSync(12); cipher$1.start({ iv: util.createBuffer(iv), additionalData: 'none', tagLength: 128 }); cipher$1.update(util.createBuffer(data)); cipher$1.finish(); var artifacts = { iv: binaryStringToBytesBuffer(iv) }; if (cipher$1.mode.tag) { artifacts.at = binaryStringToBytesBuffer(cipher$1.mode.tag.data); } artifacts.ad = 'none'; return { encrypted: cipher$1.output.data, artifacts: artifacts }; } function generateRSAKeyPair(bits) { if (bits === void 0) { bits = 4096; } return new Promise(function (resolve, reject) { // -1 workers to estimate number of cores available // https://github.com/digitalbazaar/forge#rsa pki.rsa.generateKeyPair({ bits: bits, workers: 0 }, function (err, keyPair) { if (err) { return reject(err); } resolve({ privateKey: pki.privateKeyToPem(keyPair.privateKey), publicKey: pki.publicKeyToPem(keyPair.publicKey), bits: bits }); }); }); } function encryptPrivateKeyWithPassword(_a) { var privateKeyPem = _a.privateKeyPem, password = _a.password; var publicKey = pki.privateKeyFromPem(privateKeyPem); return pki.encryptRsaPrivateKey(publicKey, password); } function encryptWithPublicKey(_a, serializationFormat) { var publicKeyPem = _a.publicKeyPem, data = _a.data, _b = _a.scheme, scheme = _b === void 0 ? 'RSA-OAEP' : _b; if (serializationFormat === void 0) { serializationFormat = SerializationFormat.latest_version; } return __awaiter(this, void 0, void 0, function () { var pk, encrypted, bitLength, serialized; return __generator(this, function (_c) { pk = pki.publicKeyFromPem(publicKeyPem); encrypted = pk.encrypt(data, scheme); bitLength = keyLengthFromPublicKeyPem(publicKeyPem); serialized = serialize("Rsa" + bitLength, encrypted, {}, serializationFormat); return [2 /*return*/ , { encrypted: encrypted, serialized: serialized }]; }); }); } // compatiblity not tested with other cryppo // | 'RSAES-PKCS1-V1_5' // | 'RSA-OAEP' // | 'RAW' // | 'NONE' // | null // | undefined; function decryptSerializedWithPrivateKey(_a) { var password = _a.password, privateKeyPem = _a.privateKeyPem, serialized = _a.serialized, _b = _a.scheme, scheme = _b === void 0 ? 'RSA-OAEP' : _b; return __awaiter(this, void 0, void 0, function () { var encrypted; return __generator(this, function (_c) { encrypted = deSerialize(serialized).decodedPairs[0]; return [2 /*return*/ , decryptWithPrivateKey({ password: password, privateKeyPem: privateKeyPem, encrypted: encrypted, scheme: scheme })]; }); }); } function decryptWithPrivateKey(_a) { var password = _a.password, privateKeyPem = _a.privateKeyPem, encrypted = _a.encrypted, _b = _a.scheme, scheme = _b === void 0 ? 'RSA-OAEP' : _b; return __awaiter(this, void 0, void 0, function () { var pk; return __generator(this, function (_c) { pk = pki.decryptRsaPrivateKey(privateKeyPem, password); return [2 /*return*/ , pk.decrypt(encrypted, scheme)]; }); }); } function signWithPrivateKey(privateKeyPem, data) { var mdDigest = md.sha256.create(); var key = pki.privateKeyFromPem(privateKeyPem); mdDigest.update(bytesToBinaryString(data)); var signature = key.sign(mdDigest); var keySize = keyLengthFromPrivateKeyPem(privateKeyPem); var serialized = "Sign.Rsa" + keySize + "." + encodeSafe64(signature) + "." + encodeSafe64(bytesToBinaryString(data)); return { signature: signature, data: data, keySize: keySize, serialized: serialized }; } function loadRsaSignature(serializedPayload) { var decomposedPayload = serializedPayload.split('.'); var signed = decomposedPayload[0], signingStrategy = decomposedPayload[1], encodedSignature = decomposedPayload[2], encodedData = decomposedPayload[3]; var regex = /Rsa\d{1,4}/g; if (signed === 'Sign' && regex.test(signingStrategy)) { var bits = parseInt(signingStrategy.replace('Rsa', ''), 10); var data = decodeSafe64(encodedData); return { serialized: serializedPayload, signature: decodeSafe64(encodedSignature), data: binaryStringToBytes(data), keySize: bits }; } else { throw new Error('String is not a serialized RSA signature'); } } function verifyWithPublicKey(publicKeyPem, signatureObj) { var key = pki.publicKeyFromPem(publicKeyPem); var mdDigest = md.sha256.create(); mdDigest.update(bytesToBinaryString(signatureObj.data)); return key.verify(mdDigest.digest().bytes(), signatureObj.signature); } function hmacSha256Digest(key, message) { var hm = hmac.create(); hm.start('sha256', key); hm.update(message); return hm.digest().toHex(); } if (typeof window !== 'undefined' && typeof window.global === 'undefined') { // Ensures browser will run without manual polyfills in Angular window.Buffer = Buffer; window.global = window; } export { CipherStrategy, DerivedKeyOptions, EncryptionKey, KeyDerivationStrategy, binaryStringToBytes, binaryStringToBytesBuffer, bytesBufferToBinaryString, bytesToBinaryString, bytesToUtf16, bytesToUtf8, deSerialize, deSerializeDerivedKeyOptions, decode64, decodeDerivationArtifacts, decodeSafe64, decodeSafe64Bson, decryptSerializedWithPrivateKey, decryptWithKey, decryptWithKeyDerivedFromString, decryptWithKeyUsingArtefacts, decryptWithPrivateKey, encode64, encodeDerivationArtifacts, encodeSafe64, encodeSafe64Bson, encodeUtf8, encryptPrivateKeyWithPassword, encryptWithGeneratedKey, encryptWithKey, encryptWithKeyDerivedFromString, encryptWithKeyUsingArtefacts, encryptWithPublicKey, generateDerivedKey, generateEncryptionVerificationArtifacts, generateRSAKeyPair, generateRandomBytesString, hmacSha256Digest, keyLengthFromPrivateKeyPem, keyLengthFromPublicKeyPem, loadRsaSignature, serialize, serializeDerivedKeyOptions, signWithPrivateKey, strategyToAlgorithm, utf16ToBytes, utf8ToBytes, verifyWithPublicKey };