@meeco/cryppo
Version:
In-browser encryption and decryption. Clone of Ruby Cryppo
990 lines (866 loc) • 30.1 kB
JavaScript
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 };