blockstack
Version:
The Blockstack Javascript library for authentication, identity, and storage.
124 lines • 5.07 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const cryptoUtils_1 = require("./cryptoUtils");
class NodeCryptoPbkdf2 {
constructor(nodePbkdf2) {
this.nodePbkdf2 = nodePbkdf2;
}
derive(password, salt, iterations, keyLength, digest) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
if (digest !== 'sha512' && digest !== 'sha256') {
throw new Error(`Unsupported digest "${digest}" for Pbkdf2`);
}
return new Promise((resolve, reject) => {
this.nodePbkdf2(password, salt, iterations, keyLength, digest, (error, result) => {
if (error) {
reject(error);
}
resolve(result);
});
});
});
}
}
exports.NodeCryptoPbkdf2 = NodeCryptoPbkdf2;
class WebCryptoPbkdf2 {
constructor(subtleCrypto) {
this.subtleCrypto = subtleCrypto;
}
derive(password, salt, iterations, keyLength, digest) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let algo;
if (digest === 'sha256') {
algo = 'SHA-256';
}
else if (digest === 'sha512') {
algo = 'SHA-512';
}
else {
throw new Error(`Unsupported Pbkdf2 digest algorithm "${digest}"`);
}
let result;
const passwordBytes = Buffer.from(password, 'utf8');
try {
const key = yield this.subtleCrypto.importKey('raw', passwordBytes, 'PBKDF2', false, ['deriveBits']);
result = yield this.subtleCrypto.deriveBits({
name: 'PBKDF2', salt, iterations, hash: { name: algo }
}, key, keyLength * 8);
}
catch (error) {
// Browser appears to support WebCrypto but missing pbkdf2 support.
const partialWebCrypto = new WebCryptoPartialPbkdf2(this.subtleCrypto);
return partialWebCrypto.derive(password, salt, iterations, keyLength, digest);
}
return Buffer.from(result);
});
}
}
exports.WebCryptoPbkdf2 = WebCryptoPbkdf2;
class WebCryptoPartialPbkdf2 {
constructor(subtleCrypto) {
this.subtleCrypto = subtleCrypto;
}
derive(password, salt, iterations, keyLength, digest) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
if (digest !== 'sha512' && digest !== 'sha256') {
throw new Error(`Unsupported digest "${digest}" for Pbkdf2`);
}
const key = Buffer.from(password, 'utf8');
const algo = digest === 'sha512' ? 'SHA-512' : 'SHA-256';
const algoOpts = { name: 'HMAC', hash: algo };
const hmacDigest = (key, data) => this.subtleCrypto
.importKey('raw', key, algoOpts, true, ['sign'])
.then(cryptoKey => this.subtleCrypto.sign(algoOpts, cryptoKey, data))
.then(result => new Uint8Array(result));
const DK = new Uint8Array(keyLength);
const saltLength = salt.length;
const block1 = new Uint8Array(saltLength + 4);
block1.set(salt);
let destPos = 0;
const hLen = digest === 'sha512' ? 64 : 32;
const l = Math.ceil(keyLength / hLen);
function writeUInt32BE(data, value, offset) {
value = +value;
offset >>>= 0;
data[offset] = (value >>> 24);
data[offset + 1] = (value >>> 16);
data[offset + 2] = (value >>> 8);
data[offset + 3] = (value & 0xff);
return offset + 4;
}
for (let i = 1; i <= l; i++) {
writeUInt32BE(block1, i, saltLength);
// eslint-disable-next-line no-await-in-loop
const T = yield hmacDigest(key, block1);
let U = T;
for (let j = 1; j < iterations; j++) {
// eslint-disable-next-line no-await-in-loop
U = yield hmacDigest(key, U);
for (let k = 0; k < hLen; k++) {
T[k] ^= U[k];
}
}
DK.set(T.subarray(0, DK.byteLength - destPos), destPos);
destPos += hLen;
}
return Buffer.from(DK.buffer);
});
}
}
exports.WebCryptoPartialPbkdf2 = WebCryptoPartialPbkdf2;
function createPbkdf2() {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const cryptoLib = yield cryptoUtils_1.getCryptoLib();
if (cryptoLib.name === 'subtleCrypto') {
return new WebCryptoPbkdf2(cryptoLib.lib);
}
else {
return new NodeCryptoPbkdf2(cryptoLib.lib.pbkdf2);
}
});
}
exports.createPbkdf2 = createPbkdf2;
//# sourceMappingURL=pbkdf2.js.map