removed keystretch.js
This commit is contained in:
Родитель
abf68d70ec
Коммит
0879b14770
|
@ -5,7 +5,7 @@
|
|||
var crypto = require('crypto')
|
||||
var P = require('p-promise')
|
||||
var ClientApi = require('./api')
|
||||
var keyStretch = require('../crypto/keystretch')
|
||||
var butil = require('../crypto/butil')
|
||||
var pbkdf2 = require('../crypto/pbkdf2')
|
||||
var hkdf = require('../crypto/hkdf')
|
||||
var tokens = require('../tokens')({ trace: function () {}})
|
||||
|
@ -34,7 +34,7 @@ Client.Api = ClientApi
|
|||
|
||||
Client.prototype.setupCredentials = function (email, password) {
|
||||
this.email = email
|
||||
return pbkdf2.derive(Buffer(password), keyStretch.KWE('quickStretch', email), 1000, 32)
|
||||
return pbkdf2.derive(Buffer(password), hkdf.KWE('quickStretch', email), 1000, 32)
|
||||
.then(
|
||||
function (stretch) {
|
||||
return hkdf(stretch, 'authPW', null, 32)
|
||||
|
@ -218,7 +218,7 @@ Client.prototype.changePassword = function (newPassword) {
|
|||
)
|
||||
.then(
|
||||
function () {
|
||||
this.wrapKb = keyStretch.xor(this.kB, this.unwrapBKey)
|
||||
this.wrapKb = butil.xorBuffers(this.kB, this.unwrapBKey)
|
||||
return this.api.passwordChangeFinish(this.passwordChangeToken, this.authPW, this.wrapKb)
|
||||
}.bind(this)
|
||||
)
|
||||
|
@ -251,7 +251,7 @@ Client.prototype.keys = function () {
|
|||
this.keyFetchToken = null
|
||||
this.kA = keys.kA
|
||||
this.wrapKb = keys.wrapKb
|
||||
this.kB = keys.kB = keyStretch.xor(this.wrapKb, this.unwrapBKey)
|
||||
this.kB = keys.kB = butil.xorBuffers(this.wrapKb, this.unwrapBKey)
|
||||
return keys
|
||||
}.bind(this),
|
||||
function (err) {
|
||||
|
|
|
@ -5,15 +5,21 @@
|
|||
var HKDF = require('hkdf')
|
||||
var P = require('p-promise')
|
||||
|
||||
function kw(name) {
|
||||
return 'identity.mozilla.com/picl/v1/' + name
|
||||
const NAMESPACE = 'identity.mozilla.com/picl/v1/'
|
||||
|
||||
function KWE(name, email) {
|
||||
return Buffer(NAMESPACE + name + ':' + email)
|
||||
}
|
||||
|
||||
function KW(name) {
|
||||
return Buffer(NAMESPACE + name)
|
||||
}
|
||||
|
||||
function hkdf(km, info, salt, len) {
|
||||
var d = P.defer()
|
||||
var df = new HKDF('sha256', salt, km)
|
||||
df.derive(
|
||||
kw(info),
|
||||
KW(info),
|
||||
len,
|
||||
function(key) {
|
||||
d.resolve(key)
|
||||
|
@ -22,4 +28,7 @@ function hkdf(km, info, salt, len) {
|
|||
return d.promise
|
||||
}
|
||||
|
||||
hkdf.KW = KW
|
||||
hkdf.KWE = KWE
|
||||
|
||||
module.exports = hkdf
|
||||
|
|
|
@ -1,128 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var P = require('p-promise')
|
||||
var pbkdf2 = require('./pbkdf2')
|
||||
var scrypt = require('./scrypt')
|
||||
var hkdf = require('./hkdf')
|
||||
|
||||
// The namespace for the salt functions
|
||||
const NAMESPACE = 'identity.mozilla.com/picl/v1/'
|
||||
const SCRYPT_HELPER = 'https://scrypt-accounts.dev.lcip.org/'
|
||||
const ITERATIONS = 20000
|
||||
const LENGTH = 8 * 32
|
||||
|
||||
/** Derive a key from an email and password pair
|
||||
*
|
||||
* @param {Buffer} email The email hex buffer of the user
|
||||
* @param {Buffer} password The password of the user
|
||||
* @param {String} saltHex The salt to derive hkdf as a hex string
|
||||
* @return p.promise object - It will resolve with
|
||||
* {Buffer} srpPw srp password
|
||||
* {Buffer} unwrapBKey unwrapBKey
|
||||
* or fail with {object} err
|
||||
*/
|
||||
function derive(email, password, saltHex) {
|
||||
var p = P.defer()
|
||||
|
||||
if (!password || !email || !saltHex) {
|
||||
p.reject('Bad password, salt or email input')
|
||||
return p.promise
|
||||
}
|
||||
|
||||
var salt = Buffer(saltHex, 'hex')
|
||||
// derive the first key from pbkdf2
|
||||
pbkdf2
|
||||
.derive(password, KWE('first-PBKDF', email), ITERATIONS, LENGTH)
|
||||
.then(
|
||||
function(K1) {
|
||||
// request a hash from scrypt based on the first key
|
||||
return scrypt.hash(K1, KW("scrypt"), module.exports.SCRYPT_HELPER)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (K2) {
|
||||
// combine the K2 hex string and a password UTF8 into a bit array
|
||||
var scryptPassword = Buffer.concat([
|
||||
Buffer(K2, 'hex'),
|
||||
password
|
||||
])
|
||||
// derive the second key from pbkdf2
|
||||
return pbkdf2.derive(scryptPassword, KWE('second-PBKDF', email), ITERATIONS, LENGTH)
|
||||
}
|
||||
)
|
||||
.then(
|
||||
function (stretchedPw) {
|
||||
var input = new Buffer (stretchedPw, 'hex')
|
||||
var lengthHkdf = 2 * 32
|
||||
|
||||
return hkdf(input, 'mainKDF', salt, lengthHkdf)
|
||||
}
|
||||
)
|
||||
.done(
|
||||
function (hkdfResult) {
|
||||
var hkdfResultHex = hkdfResult.toString('hex')
|
||||
var srpPw = Buffer(hkdfResultHex.substring(0,64), 'hex')
|
||||
var unwrapBKey = Buffer(hkdfResultHex.substring(64,128), 'hex')
|
||||
|
||||
p.resolve({ srpPw: srpPw, unwrapBKey: unwrapBKey })
|
||||
},
|
||||
function (err) {
|
||||
p.reject(err)
|
||||
}
|
||||
)
|
||||
|
||||
return p.promise
|
||||
}
|
||||
|
||||
/** XOR
|
||||
*
|
||||
* @param {Buffer|String} input1 first value of the buffer as a hex string or a buffer
|
||||
* @param {Buffer|String} input2 second value of the buffer as hex string or a buffer
|
||||
* @return {Buffer} xorResult Result XOR buffer
|
||||
*/
|
||||
function xor(input1, input2) {
|
||||
var buf1 = Buffer.isBuffer(input1) ? input1 : Buffer(input1, 'hex')
|
||||
var buf2 = Buffer.isBuffer(input2) ? input2 : Buffer(input2, 'hex')
|
||||
var xorResult = Buffer(buf1.length)
|
||||
|
||||
if (buf1.length !== buf2.length) {
|
||||
throw new Error(
|
||||
'XOR buffers must be same length %d != %d',
|
||||
buf1.length,
|
||||
buf2.length
|
||||
)
|
||||
}
|
||||
for (var i = 0; i < xorResult.length; i++) {
|
||||
xorResult[i] = buf2[i] ^ buf1[i]
|
||||
}
|
||||
|
||||
return xorResult
|
||||
}
|
||||
|
||||
|
||||
/** KWE
|
||||
*
|
||||
* @param {String} name The name of the salt
|
||||
* @param {Buffer} email The email of the user.
|
||||
* @return {Buffer} the salt combination with the namespace
|
||||
*/
|
||||
function KWE(name, email) {
|
||||
return Buffer(NAMESPACE + name + ':' + email)
|
||||
}
|
||||
|
||||
/** KW
|
||||
*
|
||||
* @param {String} name The name of the salt
|
||||
* @return {Buffer} the salt combination with the namespace
|
||||
*/
|
||||
function KW(name) {
|
||||
return Buffer(NAMESPACE + name)
|
||||
}
|
||||
|
||||
module.exports.SCRYPT_HELPER = SCRYPT_HELPER
|
||||
module.exports.derive = derive
|
||||
module.exports.xor = xor
|
||||
module.exports.KWE = KWE
|
||||
module.exports.KW = KW
|
|
@ -1,166 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var test = require('../ptaptest')
|
||||
var keyStretch = require('../../crypto/keystretch')
|
||||
|
||||
test(
|
||||
'basic key stretching, test vectors',
|
||||
function (t) {
|
||||
var emailBuf = Buffer('andré@example.org')
|
||||
var password = Buffer('pässwörd')
|
||||
var salt = '00f000000000000000000000000000000000000000000000000000000000034d'
|
||||
return keyStretch.derive(emailBuf, password, salt)
|
||||
.then(
|
||||
function (result) {
|
||||
t.equal(result.srpPw.toString('hex'), '00f9b71800ab5337d51177d8fbc682a3653fa6dae5b87628eeec43a18af59a9d')
|
||||
t.equal(result.unwrapBKey.toString('hex'), '6ea660be9c89ec355397f89afb282ea0bf21095760c8c5009bbcc894155bbe2a')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'basic key stretching, longer credentials',
|
||||
function (t) {
|
||||
var salt = '00f000000000000000000000000000000000000000000000000000000000034d'
|
||||
var email = 'ijqmkkafer3xsj5rzoq+msnxsacvkmqxabtsvxvj@some-test-domain-with-a-long-name-example.org'
|
||||
var emailBuf = Buffer(email)
|
||||
var password = Buffer('mSnxsacVkMQxAbtSVxVjCCoWArNUsFhiJqmkkafER3XSJ5rzoQ')
|
||||
return keyStretch.derive(emailBuf, password, salt)
|
||||
.then(
|
||||
function (result) {
|
||||
t.equal(result.srpPw.toString('hex'), '261559a74f7b7199fef846c8138db08333bbcc7f5177194da5c965ba953a346b')
|
||||
t.equal(result.unwrapBKey.toString('hex'), 'cf48fbc1613a46c794d37c2fe5423c7813b70e5b6c525d5c4463056f267959ff')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'false input both',
|
||||
function (t) {
|
||||
return keyStretch.derive('', '', '')
|
||||
.then(
|
||||
function (stretchedPassword) {
|
||||
t.fail('Got a stretchedPassword from false input')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err, 'Bad password, salt or email input')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'false input email',
|
||||
function (t) {
|
||||
var email = 'me@example.org'
|
||||
return keyStretch.derive(email, '', '')
|
||||
.then(
|
||||
function (stretchedPassword) {
|
||||
t.fail('Got a stretchedPassword from false input')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err, 'Bad password, salt or email input')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'false input password',
|
||||
function (t) {
|
||||
var email = ''
|
||||
var password = 'password'
|
||||
var salt = ''
|
||||
return keyStretch.derive(email, password, salt)
|
||||
.then(
|
||||
function (stretchedPassword) {
|
||||
t.fail('Got a stretchedPassword from false input')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err, 'Bad password, salt or email input')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'undefined input',
|
||||
function (t) {
|
||||
var email
|
||||
var password
|
||||
var salt
|
||||
return keyStretch.derive(email, password, salt)
|
||||
.then(
|
||||
function (stretchedPassword) {
|
||||
t.fail('Got a stretchedPassword from false input')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err, 'Bad password, salt or email input')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'not enough arguments',
|
||||
function (t) {
|
||||
return keyStretch.derive()
|
||||
.then(
|
||||
function (stretchedPassword) {
|
||||
t.fail('Got a stretchedPassword from false input')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err, 'Bad password, salt or email input')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'one argument',
|
||||
function (t) {
|
||||
return keyStretch.derive(Buffer('andré@example.org'))
|
||||
.then(
|
||||
function (stretchedPassword) {
|
||||
t.fail('Got a stretchedPassword from false input')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err, 'Bad password, salt or email input')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'null input',
|
||||
function (t) {
|
||||
return keyStretch.derive(null, null, null)
|
||||
.then(
|
||||
function (stretchedPassword) {
|
||||
t.fail('Got a stretchedPassword from false input')
|
||||
},
|
||||
function (err) {
|
||||
t.equal(err, 'Bad password, salt or email input')
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test(
|
||||
'wrapkB xor string and buffer test',
|
||||
function (t) {
|
||||
var wrapkB = '404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f'
|
||||
var unwrapBKey = '6ea660be9c89ec355397f89afb282ea0bf21095760c8c5009bbcc894155bbe2a'
|
||||
var kBgood = '2ee722fdd8ccaa721bdeb2d1b76560efef705b04349d9357c3e592cf4906e075'
|
||||
var kBResult = keyStretch.xor(wrapkB, unwrapBKey)
|
||||
var kBResultBuffer = keyStretch.xor(Buffer(wrapkB, 'hex'), Buffer(unwrapBKey, 'hex'))
|
||||
|
||||
t.equal(kBResult.toString('hex'), kBgood)
|
||||
t.equal(kBResultBuffer.toString('hex'), kBgood)
|
||||
t.end()
|
||||
}
|
||||
)
|
Загрузка…
Ссылка в новой задаче