* prepare injection of encryption functions (https://github.com/lesspass/lesspass/issues/223) * reduce bundle size by 80%pull/342/head
@@ -1,6 +1,6 @@ | |||
{ | |||
"name": "lesspass", | |||
"version": "6.1.0", | |||
"version": "7.0.0", | |||
"description": "LessPass node module used to generate LessPass passwords", | |||
"keywords": [ | |||
"crypto", | |||
@@ -13,8 +13,13 @@ | |||
"dist", | |||
"src" | |||
], | |||
"main": "dist/lesspass.min.js", | |||
"main": "src/lesspass.js", | |||
"browser": { | |||
"./src/pbkdf2.js": "./src/pbkdf2.browser.js", | |||
"./src/hmac.js": "./src/hmac.browser.js" | |||
}, | |||
"module": "src/lesspass.js", | |||
"jsnext:main": "src/lesspass.js", | |||
"repository": "lesspass/core", | |||
"scripts": { | |||
"precommit": "npm test && lint-staged", | |||
@@ -27,11 +32,9 @@ | |||
}, | |||
"dependencies": { | |||
"big-integer": "^1.6.22", | |||
"buffer": "^5.0.6", | |||
"create-hmac": "^1.1.4", | |||
"es6-promise": "^4.1.0", | |||
"lodash.assign": "^4.2.0", | |||
"pbkdf2": "^3.0.9" | |||
"unibabel": "^2.1.4" | |||
}, | |||
"devDependencies": { | |||
"browserify": "^14.3.0", | |||
@@ -0,0 +1,31 @@ | |||
require("unibabel"); | |||
require("unibabel/unibabel.hex"); | |||
module.exports = function(digest, string, salt) { | |||
var algorithms = { | |||
sha1: "SHA-1", | |||
"sha-1": "SHA-1", | |||
sha256: "SHA-256", | |||
"sha-256": "SHA-256", | |||
sha512: "SHA-512", | |||
"sha-512": "SHA-512" | |||
}; | |||
return window.crypto.subtle | |||
.importKey( | |||
"raw", | |||
Unibabel.utf8ToBuffer(string), | |||
{ | |||
name: "HMAC", | |||
hash: { name: algorithms[digest.toLowerCase()] } | |||
}, | |||
true, | |||
["sign", "verify"] | |||
) | |||
.then(function(key) { | |||
return window.crypto.subtle | |||
.sign({ name: "HMAC" }, key, Unibabel.utf8ToBuffer(salt || "")) | |||
.then(function(signature) { | |||
return Unibabel.bufferToHex(new Uint8Array(signature)); | |||
}); | |||
}); | |||
}; |
@@ -0,0 +1,9 @@ | |||
var crypto = require("crypto"); | |||
var Promise = require("es6-promise").Promise; | |||
module.exports = function(digest, string, salt) { | |||
return new Promise(function(resolve) { | |||
var hmac = crypto.createHmac(digest, string); | |||
resolve(hmac.update(salt || "").digest("hex")); | |||
}); | |||
}; |
@@ -1,8 +1,6 @@ | |||
var v1 = require("./v1"); | |||
var v2 = require("./v2"); | |||
var createHMAC = require("create-hmac"); | |||
var Buffer = require("buffer/").Buffer; | |||
var Promise = require("es6-promise").Promise; | |||
var hmac = require("./hmac"); | |||
module.exports = { | |||
generatePassword: function(site, login, masterPassword, options) { | |||
@@ -12,8 +10,6 @@ module.exports = { | |||
return v2.generatePassword(site, login, masterPassword, options); | |||
}, | |||
createFingerprint: function(str) { | |||
return new Promise(function(resolve) { | |||
resolve(createHMAC("sha256", new Buffer(str)).digest("hex")); | |||
}); | |||
return hmac("sha256", str); | |||
} | |||
}; |
@@ -0,0 +1,42 @@ | |||
require("unibabel"); | |||
require("unibabel/unibabel.hex"); | |||
module.exports = function(password, salt, iterations, keylen, digest) { | |||
var algorithms = { | |||
sha1: "SHA-1", | |||
"sha-1": "SHA-1", | |||
sha256: "SHA-256", | |||
"sha-256": "SHA-256", | |||
sha512: "SHA-512", | |||
"sha-512": "SHA-512" | |||
}; | |||
return window.crypto.subtle | |||
.importKey("raw", Unibabel.utf8ToBuffer(password), "PBKDF2", false, [ | |||
"deriveKey" | |||
]) | |||
.then(function(key) { | |||
var algo = { | |||
name: "PBKDF2", | |||
salt: Unibabel.utf8ToBuffer(salt), | |||
iterations: iterations, | |||
hash: algorithms[digest.toLowerCase()] | |||
}; | |||
return window.crypto.subtle.deriveKey( | |||
algo, | |||
key, | |||
{ | |||
name: "AES-CTR", | |||
length: keylen * 8 | |||
}, | |||
true, | |||
["encrypt", "decrypt"] | |||
); | |||
}) | |||
.then(function(derivedKey) { | |||
return window.crypto.subtle | |||
.exportKey("raw", derivedKey) | |||
.then(function(keyArray) { | |||
return Unibabel.bufferToHex(new Uint8Array(keyArray)); | |||
}); | |||
}); | |||
}; |
@@ -1,54 +1,9 @@ | |||
var pbkdf2 = require("pbkdf2"); | |||
var Buffer = require("buffer/").Buffer; | |||
const crypto = require("crypto"); | |||
var Promise = require("es6-promise").Promise; | |||
function shouldUseNative() { | |||
return !!(typeof window !== "undefined" && | |||
window.crypto && | |||
window.crypto.subtle); | |||
} | |||
function pbkdf2WebCrypto(password, salt, iterations, keylen, digest) { | |||
var algorithms = { | |||
sha1: "SHA-1", | |||
"sha-1": "SHA-1", | |||
sha256: "SHA-256", | |||
"sha-256": "SHA-256", | |||
sha512: "SHA-512", | |||
"sha-512": "SHA-512" | |||
}; | |||
return window.crypto.subtle | |||
.importKey("raw", new Buffer(password), "PBKDF2", false, ["deriveKey"]) | |||
.then(function(key) { | |||
var algo = { | |||
name: "PBKDF2", | |||
salt: new Buffer(salt), | |||
iterations: iterations, | |||
hash: algorithms[digest.toLowerCase()] | |||
}; | |||
return window.crypto.subtle.deriveKey( | |||
algo, | |||
key, | |||
{ | |||
name: "AES-CTR", | |||
length: keylen * 8 | |||
}, | |||
true, | |||
["encrypt", "decrypt"] | |||
); | |||
}) | |||
.then(function(derivedKey) { | |||
return window.crypto.subtle | |||
.exportKey("raw", derivedKey) | |||
.then(function(keyArray) { | |||
return new Buffer(keyArray).toString("hex"); | |||
}); | |||
}); | |||
} | |||
function pbkdf2Browserified(password, salt, iterations, keylen, digest) { | |||
module.exports = function(password, salt, iterations, keylen, digest) { | |||
return new Promise(function(resolve, reject) { | |||
pbkdf2.pbkdf2(password, salt, iterations, keylen, digest, function( | |||
crypto.pbkdf2(password, salt, iterations, keylen, digest, function( | |||
error, | |||
key | |||
) { | |||
@@ -59,6 +14,4 @@ function pbkdf2Browserified(password, salt, iterations, keylen, digest) { | |||
} | |||
}); | |||
}); | |||
} | |||
module.exports = shouldUseNative() ? pbkdf2WebCrypto : pbkdf2Browserified; | |||
}; |
@@ -1,6 +1,6 @@ | |||
var pbkdf2 = require("./pbkdf2"); | |||
var assign = require("lodash.assign"); | |||
var createHMAC = require("create-hmac"); | |||
var hmac = require("./hmac"); | |||
module.exports = { | |||
generatePassword: generatePassword, | |||
@@ -58,11 +58,7 @@ function renderPassword(encryptedLogin, site, passwordOptions) { | |||
function createHmac(encryptedLogin, salt) { | |||
return new Promise(function(resolve) { | |||
resolve( | |||
createHMAC("sha256", new Buffer(encryptedLogin)) | |||
.update(salt) | |||
.digest("hex") | |||
); | |||
resolve(hmac("sha256", encryptedLogin, salt)); | |||
}); | |||
} | |||
@@ -0,0 +1,21 @@ | |||
var assert = require("assert"); | |||
var createHmac = require("../src/hmac"); | |||
describe("hmac", function() { | |||
it("createHmac", function() { | |||
return createHmac("sha256", "password").then(function(fingerprint) { | |||
assert.equal( | |||
"e56a207acd1e6714735487c199c6f095844b7cc8e5971d86c003a7b6f36ef51e", | |||
fingerprint | |||
); | |||
}); | |||
}); | |||
it("createHmac and update", function() { | |||
return createHmac("sha256", "password", "salt").then(function(fingerprint) { | |||
assert.equal( | |||
"fc328232993ff34ca56631e4a101d60393cad12171997ee0b562bf7852b2fed0", | |||
fingerprint | |||
); | |||
}); | |||
}); | |||
}); |