UNPKG

@meeco/cryppo

Version:

In-browser encryption and decryption. Clone of Ruby Cryppo

88 lines 3.59 kB
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