@meeco/cryppo
Version:
In-browser encryption and decryption. Clone of Ruby Cryppo
88 lines • 3.59 kB
JavaScript
import forge from 'node-forge';
import { EncodingVersions } from '../encoding-versions.js';
import { EncryptionKey } from '../encryption-key.js';
import { SerializationFormat } from '../serialization-versions.js';
import { binaryStringToBytes, binaryStringToBytesBuffer, bytesBufferToBinaryString, deSerializeDerivedKeyOptions, encodeUtf8, serializeDerivedKeyOptions, } from '../util.js';
const { md, pkcs5, random } = forge;
/**
* Most of these values are copied directly from the Ruby library
*/
const MIN_ITERATIONS = 20000;
const DEFAULT_LENGTH = 32;
const DEFAULT_ITERATION_VARIANCE = 10;
const DEFAULT_SALT_LENGTH = 20;
export var KeyDerivationStrategy;
(function (KeyDerivationStrategy) {
KeyDerivationStrategy["Pbkdf2Hmac"] = "Pbkdf2Hmac";
})(KeyDerivationStrategy || (KeyDerivationStrategy = {}));
/**
* Store configuration used for password based key derivation and
* serialize/de-serialize it.
*/
export class DerivedKeyOptions {
static usesDerivedKey(serialized) {
const parts = serialized.split('.');
if (parts[parts.length - 2] === KeyDerivationStrategy.Pbkdf2Hmac) {
return true;
}
return false;
}
static randomFromOptions({ iterationVariance = DEFAULT_ITERATION_VARIANCE, length = DEFAULT_LENGTH, minIterations = MIN_ITERATIONS, strategy = KeyDerivationStrategy.Pbkdf2Hmac, useSalt, }) {
const variance = Math.floor(minIterations * (iterationVariance / 100));
const iterations = minIterations + Math.floor(Math.random() * variance);
const salt = useSalt || random.getBytesSync(DEFAULT_SALT_LENGTH);
return new DerivedKeyOptions({
strategy,
iterations,
salt,
length,
});
}
static fromSerialized(serialized) {
const { derivationStrategy, serializationArtifacts } = deSerializeDerivedKeyOptions(serialized);
return new DerivedKeyOptions({
// keys taken from ruby lib
strategy: derivationStrategy,
salt: bytesBufferToBinaryString(serializationArtifacts.iv),
iterations: serializationArtifacts.i,
length: serializationArtifacts.l,
hash: serializationArtifacts.hash,
...serializationArtifacts,
});
}
salt;
iterations;
length;
strategy;
hash;
constructor(options) {
this.salt = options.salt;
this.iterations = options.iterations;
this.length = options.length;
this.strategy = options.strategy;
this.hash = options.hash || 'SHA256';
}
serialize(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);
}
deriveKey(key, encodingVersion = EncodingVersions.latest_version) {
const hash = this.hash.toLocaleLowerCase();
const digest = md[hash].create();
key = encodingVersion === EncodingVersions.legacy ? key : encodeUtf8(key);
return new Promise((resolve, reject) => {
return pkcs5.pbkdf2(key, this.salt, this.iterations, this.length, digest, (err, derivedKey) => {
if (err) {
return reject(err);
}
resolve(EncryptionKey.fromBytes(binaryStringToBytes(derivedKey)));
});
});
}
}
//# sourceMappingURL=derived-key.js.map