rearranged cryptic ;) code. added a lazy email validator

This commit is contained in:
Danny Coates 2014-01-07 10:55:12 -08:00
Родитель 1cbbca3206
Коммит abf68d70ec
16 изменённых файлов: 69 добавлений и 125 удалений

Просмотреть файл

@ -5,9 +5,9 @@
var crypto = require('crypto') var crypto = require('crypto')
var P = require('p-promise') var P = require('p-promise')
var ClientApi = require('./api') var ClientApi = require('./api')
var keyStretch = require('./keystretch') var keyStretch = require('../crypto/keystretch')
var pbkdf2 = require('./pbkdf2') var pbkdf2 = require('../crypto/pbkdf2')
var hkdf = require('../hkdf') var hkdf = require('../crypto/hkdf')
var tokens = require('../tokens')({ trace: function () {}}) var tokens = require('../tokens')({ trace: function () {}})
var Bundle = tokens.Bundle var Bundle = tokens.Bundle

25
crypto/butil.js Normal file
Просмотреть файл

@ -0,0 +1,25 @@
module.exports.buffersAreEqual = function buffersAreEqual(buffer1, buffer2) {
var mismatch = buffer1.length - buffer2.length
if (mismatch) {
return false
}
for (var i = 0; i < buffer1.length; i++) {
mismatch |= buffer1[i] ^ buffer2[i]
}
return mismatch === 0
}
module.exports.xorBuffers = function xorBuffers(buffer1, buffer2) {
if (buffer1.length !== buffer2.length) {
throw new Error(
'XOR buffers must be same length (%d != %d)',
buffer1.length,
buffer2.length
)
}
var result = Buffer(buffer1.length)
for (var i = 0; i < buffer1.length; i++) {
result[i] = buffer1[i] ^ buffer2[i]
}
return result
}

Просмотреть файл

Просмотреть файл

@ -4,8 +4,8 @@
var P = require('p-promise') var P = require('p-promise')
var pbkdf2 = require('./pbkdf2') var pbkdf2 = require('./pbkdf2')
var scrypt = require('../scrypt') var scrypt = require('./scrypt')
var hkdf = require('../hkdf') var hkdf = require('./hkdf')
// The namespace for the salt functions // The namespace for the salt functions
const NAMESPACE = 'identity.mozilla.com/picl/v1/' const NAMESPACE = 'identity.mozilla.com/picl/v1/'

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -3,37 +3,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var HEX_STRING = require('./validators').HEX_STRING var HEX_STRING = require('./validators').HEX_STRING
var HEX_EMAIL = require('./validators').HEX_EMAIL var LAZY_EMAIL = require('./validators').LAZY_EMAIL
var P = require('p-promise') var P = require('p-promise')
var scrypt = require('../scrypt') var scrypt = require('../crypto/scrypt')
var hkdf = require('../hkdf') var hkdf = require('../crypto/hkdf')
var butil = require('../crypto/butil')
function buffersAreEqual(buffer1, buffer2) {
var mismatch = buffer1.length - buffer2.length
if (mismatch) {
return false
}
for (var i = 0; i < buffer1.length; i++) {
mismatch |= buffer1[i] ^ buffer2[i]
}
return mismatch === 0
}
function xorBuffers(buffer1, buffer2) {
if (buffer1.length !== buffer2.length) {
throw new Error(
'XOR buffers must be same length (%d != %d)',
buffer1.length,
buffer2.length
)
}
var result = Buffer(buffer1.length)
for (var i = 0; i < buffer1.length; i++) {
result[i] = buffer1[i] ^ buffer2[i]
}
return result
}
module.exports = function (log, crypto, P, uuid, isA, error, db, mailer, isProduction) { module.exports = function (log, crypto, P, uuid, isA, error, db, mailer, isProduction) {
@ -49,7 +24,7 @@ module.exports = function (log, crypto, P, uuid, isA, error, db, mailer, isProdu
tags: ["srp", "account"], tags: ["srp", "account"],
validate: { validate: {
payload: { payload: {
email: isA.String().max(1024).required(), email: isA.String().max(255).regex(LAZY_EMAIL).required(),
authPW: isA.String().min(64).max(64).regex(HEX_STRING).required(), authPW: isA.String().min(64).max(64).regex(HEX_STRING).required(),
preVerified: isA.Boolean(), preVerified: isA.Boolean(),
service: isA.String().max(16).alphanum().optional(), service: isA.String().max(16).alphanum().optional(),
@ -157,7 +132,7 @@ module.exports = function (log, crypto, P, uuid, isA, error, db, mailer, isProdu
return hkdf(stretched, 'verifyHash', null, 32) return hkdf(stretched, 'verifyHash', null, 32)
.then( .then(
function (verifyHash) { function (verifyHash) {
if (!buffersAreEqual(verifyHash, emailRecord.verifyHash)) { if (!butil.buffersAreEqual(verifyHash, emailRecord.verifyHash)) {
throw error.incorrectPassword(emailRecord.rawEmail) throw error.incorrectPassword(emailRecord.rawEmail)
} }
return db.createSessionToken( return db.createSessionToken(
@ -192,7 +167,7 @@ module.exports = function (log, crypto, P, uuid, isA, error, db, mailer, isProdu
return hkdf(stretched, 'wrapwrapKey', null, 32) return hkdf(stretched, 'wrapwrapKey', null, 32)
.then( .then(
function (wrapWrapKey) { function (wrapWrapKey) {
return xorBuffers(wrapWrapKey, emailRecord.wrapWrapKb) return butil.xorBuffers(wrapWrapKey, emailRecord.wrapWrapKb)
} }
) )
.then( .then(
@ -239,7 +214,7 @@ module.exports = function (log, crypto, P, uuid, isA, error, db, mailer, isProdu
}, },
validate: { validate: {
payload: { payload: {
email: isA.String().max(255).required(), email: isA.String().max(255).regex(LAZY_EMAIL).required(),
authPW: isA.String().min(64).max(64).regex(HEX_STRING).required() authPW: isA.String().min(64).max(64).regex(HEX_STRING).required()
}, },
response: { response: {
@ -348,7 +323,7 @@ module.exports = function (log, crypto, P, uuid, isA, error, db, mailer, isProdu
validate: { validate: {
response: { response: {
schema: { schema: {
email: isA.String().required(), email: isA.String().regex(LAZY_EMAIL).required(),
verified: isA.Boolean().required() verified: isA.Boolean().required()
} }
} }
@ -517,7 +492,7 @@ module.exports = function (log, crypto, P, uuid, isA, error, db, mailer, isProdu
}, },
validate: { validate: {
payload: { payload: {
email: isA.String().max(255).required(), email: isA.String().max(255).regex(LAZY_EMAIL).required(),
authPW: isA.String().min(64).max(64).regex(HEX_STRING).required() authPW: isA.String().min(64).max(64).regex(HEX_STRING).required()
} }
} }

Просмотреть файл

@ -2,38 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var HEX_EMAIL = require('./validators').HEX_EMAIL
var HEX_STRING = require('./validators').HEX_STRING var HEX_STRING = require('./validators').HEX_STRING
var LAZY_EMAIL = require('./validators').LAZY_EMAIL
var crypto = require('crypto') var crypto = require('crypto')
var scrypt = require('../scrypt') var scrypt = require('../crypto/scrypt')
var hkdf = require('../hkdf') var hkdf = require('../crypto/hkdf')
var butil = require('../crypto/butil')
function buffersAreEqual(buffer1, buffer2) {
var mismatch = buffer1.length - buffer2.length
if (mismatch) {
return false
}
for (var i = 0; i < buffer1.length; i++) {
mismatch |= buffer1[i] ^ buffer2[i]
}
return mismatch === 0
}
function xorBuffers(buffer1, buffer2) {
if (buffer1.length !== buffer2.length) {
throw new Error(
'XOR buffers must be same length (%d != %d)',
buffer1.length,
buffer2.length
)
}
var result = Buffer(buffer1.length)
for (var i = 0; i < buffer1.length; i++) {
result[i] = buffer1[i] ^ buffer2[i]
}
return result
}
module.exports = function (log, isA, error, db, mailer) { module.exports = function (log, isA, error, db, mailer) {
@ -70,7 +45,7 @@ module.exports = function (log, isA, error, db, mailer) {
return hkdf(oldStretched, 'verifyHash', null, 32) return hkdf(oldStretched, 'verifyHash', null, 32)
.then( .then(
function (verifyHash) { function (verifyHash) {
if(!buffersAreEqual(verifyHash, emailRecord.verifyHash)) { if(!butil.buffersAreEqual(verifyHash, emailRecord.verifyHash)) {
throw error.incorrectPassword() throw error.incorrectPassword()
} }
} }
@ -80,7 +55,7 @@ module.exports = function (log, isA, error, db, mailer) {
return hkdf(oldStretched, 'wrapwrapKey', null, 32) return hkdf(oldStretched, 'wrapwrapKey', null, 32)
.then( .then(
function (wrapWrapKey) { function (wrapWrapKey) {
return xorBuffers(wrapWrapKey, emailRecord.wrapWrapKb) return butil.xorBuffers(wrapWrapKey, emailRecord.wrapWrapKb)
} }
) )
} }
@ -134,7 +109,7 @@ module.exports = function (log, isA, error, db, mailer) {
}, },
validate: { validate: {
payload: { payload: {
email: isA.String().max(255).required(), email: isA.String().max(255).regex(LAZY_EMAIL).required(),
oldAuthPW: isA.String().min(64).max(64).regex(HEX_STRING).required() oldAuthPW: isA.String().min(64).max(64).regex(HEX_STRING).required()
} }
} }
@ -164,7 +139,7 @@ module.exports = function (log, isA, error, db, mailer) {
return hkdf(stretched, 'wrapwrapKey', null, 32) return hkdf(stretched, 'wrapwrapKey', null, 32)
.then( .then(
function (wrapWrapKey) { function (wrapWrapKey) {
return xorBuffers(wrapWrapKey, wrapKb) return butil.xorBuffers(wrapWrapKey, wrapKb)
} }
) )
.then( .then(
@ -247,7 +222,7 @@ module.exports = function (log, isA, error, db, mailer) {
}, },
validate: { validate: {
payload: { payload: {
email: isA.String().max(1024).required() email: isA.String().max(255).regex(LAZY_EMAIL).required()
}, },
response: { response: {
schema: { schema: {
@ -295,7 +270,7 @@ module.exports = function (log, isA, error, db, mailer) {
}, },
validate: { validate: {
payload: { payload: {
email: isA.String().max(1024).required() email: isA.String().max(255).regex(LAZY_EMAIL).required()
}, },
response: { response: {
schema: { schema: {

Просмотреть файл

@ -10,3 +10,5 @@ module.exports.HEX_STRING = /^(?:[a-fA-F0-9]{2})+$/
// This is a pretty coarse match - basically /.+@.+/ on a hex string. // This is a pretty coarse match - basically /.+@.+/ on a hex string.
module.exports.HEX_EMAIL = /^(?:[a-fA-F0-9]{2})+40(?:[a-fA_F0-9]{2})+$/ module.exports.HEX_EMAIL = /^(?:[a-fA-F0-9]{2})+40(?:[a-fA_F0-9]{2})+$/
module.exports.LAZY_EMAIL = /^[^@\s]+@[^@\s]+$/

Просмотреть файл

@ -75,7 +75,7 @@ TestServer.start(config.publicUrl)
) )
} }
) )
/*/
test( test(
'/account/create with malformed email address', '/account/create with malformed email address',
function (t) { function (t) {
@ -90,12 +90,12 @@ TestServer.start(config.publicUrl)
) )
} }
) )
/*/
test( test(
'signup with same email, different case', 'signup with same email, different case',
function (t) { function (t) {
var email = 'TEST@EXAMPLE.COM' var email = Math.random() + 'TEST@EXAMPLE.COM'
var email2 = 'test@example.com' var email2 = email.toLowerCase()
var password = 'abcdef' var password = 'abcdef'
return Client.create(config.publicUrl, email, password, { preVerified: true }) return Client.create(config.publicUrl, email, password, { preVerified: true })
.then( .then(
@ -116,8 +116,8 @@ TestServer.start(config.publicUrl)
test( test(
'the rawEmail is returned in the error on Incorrect Password errors', 'the rawEmail is returned in the error on Incorrect Password errors',
function (t) { function (t) {
var signupEmail = 'TestX@example.com' var signupEmail = Math.random() + 'Test@example.com'
var loginEmail = 'testx@example.com' var loginEmail = signupEmail.toLowerCase()
var password = 'abcdef' var password = 'abcdef'
return Client.create(config.publicUrl, signupEmail, password, { preVerified: true}) return Client.create(config.publicUrl, signupEmail, password, { preVerified: true})
.then( .then(

Просмотреть файл

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var test = require('../ptaptest') var test = require('../ptaptest')
var hkdf = require('../../hkdf') var hkdf = require('../../crypto/hkdf')
test( test(
'hkdf basic', 'hkdf basic',

Просмотреть файл

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var test = require('../ptaptest') var test = require('../ptaptest')
var keyStretch = require('../../client/keystretch') var keyStretch = require('../../crypto/keystretch')
test( test(
'basic key stretching, test vectors', 'basic key stretching, test vectors',

Просмотреть файл

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var test = require('../ptaptest') var test = require('../ptaptest')
var pbkdf2 = require('../../client/pbkdf2') var pbkdf2 = require('../../crypto/pbkdf2')
var test = require('../ptaptest') var test = require('../ptaptest')
var ITERATIONS = 20000 var ITERATIONS = 20000
var LENGTH = 8 * 32 var LENGTH = 8 * 32

Просмотреть файл

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var test = require('../ptaptest') var test = require('../ptaptest')
var scrypt = require('../../scrypt') var scrypt = require('../../crypto/scrypt')
test( test(
'scrypt basic', 'scrypt basic',

Просмотреть файл

@ -24,7 +24,7 @@
*/ */
module.exports = function (crypto, P, hkdf, error) { module.exports = function (crypto, P, hkdf, butil, error) {
var HASH_ALGORITHM = 'sha256' var HASH_ALGORITHM = 'sha256'
@ -39,7 +39,7 @@ module.exports = function (crypto, P, hkdf, error) {
return deriveBundleKeys(key, keyInfo, payload.length) return deriveBundleKeys(key, keyInfo, payload.length)
.then( .then(
function (keys) { function (keys) {
var ciphertext = xorBuffers(payload, keys[1]) var ciphertext = butil.xorBuffers(payload, keys[1])
var hmac = crypto.createHmac(HASH_ALGORITHM, keys[0]) var hmac = crypto.createHmac(HASH_ALGORITHM, keys[0])
hmac.update(ciphertext) hmac.update(ciphertext)
var mac = hmac.digest() var mac = hmac.digest()
@ -61,10 +61,10 @@ module.exports = function (crypto, P, hkdf, error) {
var hmac = crypto.createHmac(HASH_ALGORITHM, keys[0]) var hmac = crypto.createHmac(HASH_ALGORITHM, keys[0])
hmac.update(ciphertext) hmac.update(ciphertext)
var mac = hmac.digest() var mac = hmac.digest()
if (!buffersAreEqual(mac, expectedHmac)) { if (!butil.buffersAreEqual(mac, expectedHmac)) {
throw error.invalidSignature() throw error.invalidSignature()
} }
return xorBuffers(ciphertext, keys[1]) return butil.xorBuffers(ciphertext, keys[1])
} }
) )
} }
@ -83,39 +83,5 @@ module.exports = function (crypto, P, hkdf, error) {
) )
} }
// Xor the contents of two equal-sized buffers.
//
function xorBuffers(buffer1, buffer2) {
if (buffer1.length !== buffer2.length) {
throw new Error(
'XOR buffers must be same length (%d != %d)',
buffer1.length,
buffer2.length
)
}
var result = Buffer(buffer1.length)
for (var i = 0; i < buffer1.length; i++) {
result[i] = buffer1[i] ^ buffer2[i]
}
return result
}
// Time-invariant buffer comparison.
// For checking hmacs without timing attacks.
//
function buffersAreEqual(buffer1, buffer2) {
var mismatch = buffer1.length - buffer2.length
if (mismatch) {
return false
}
for (var i = 0; i < buffer1.length; i++) {
mismatch |= buffer1[i] ^ buffer2[i]
}
return mismatch === 0
}
return Bundle return Bundle
} }

Просмотреть файл

@ -6,13 +6,14 @@ var crypto = require('crypto')
var inherits = require('util').inherits var inherits = require('util').inherits
var P = require('p-promise') var P = require('p-promise')
var hkdf = require('../hkdf') var hkdf = require('../crypto/hkdf')
var butil = require('../crypto/butil')
var error = require('./error') var error = require('./error')
module.exports = function (log) { module.exports = function (log) {
var Bundle = require('./bundle')(crypto, P, hkdf, error) var Bundle = require('./bundle')(crypto, P, hkdf, butil, error)
var Token = require('./token')(log, crypto, P, hkdf, Bundle, error) var Token = require('./token')(log, crypto, P, hkdf, Bundle, error)
var KeyFetchToken = require('./key_fetch_token')(log, inherits, Token, error) var KeyFetchToken = require('./key_fetch_token')(log, inherits, Token, error)