Implement key length constraints

This commit is contained in:
Jeremy Stashewsky 2014-01-03 18:26:13 -08:00
Родитель 3eb64528f3
Коммит 927e6b93fc
2 изменённых файлов: 63 добавлений и 26 удалений

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

@ -14,18 +14,23 @@ const ACTIVE_DURATION = 1000 * 60 * 5;
const KDF_ENC = 'cookiesession-encryption';
const KDF_MAC = 'cookiesession-signature';
const ENCRYPTION_ALGORITHMS = [
'aes128', // implicit CBC mode
'aes192',
'aes256'
];
/* map from cipher algorithm to exact key byte length */
const ENCRYPTION_ALGORITHMS = {
aes128: 16, // implicit CBC mode
aes192: 24,
aes256: 32
};
const DEFAULT_ENCRYPTION_ALGO = 'aes256';
const SIGNATURE_ALGORITHMS = [
'sha256', 'sha256-drop128',
'sha384', 'sha384-drop192',
'sha512', 'sha512-drop256'
];
/* map from hmac algorithm to _minimum_ key byte length */
const SIGNATURE_ALGORITHMS = {
'sha256': 32,
'sha256-drop128': 32,
'sha384': 48,
'sha384-drop192': 48,
'sha512': 64,
'sha512-drop256': 64
};
const DEFAULT_SIGNATURE_ALGO = 'sha256';
function isObject(val) {
@ -94,6 +99,37 @@ function setupKeys(opts) {
}
}
function keyConstraints(opts) {
if (!Buffer.isBuffer(opts.encryptionKey)) {
throw new Error('encryptionKey must be a Buffer');
}
if (!Buffer.isBuffer(opts.signatureKey)) {
throw new Error('signatureKey must be a Buffer');
}
if (constantTimeEquals(opts.encryptionKey, opts.signatureKey)) {
throw new Error('Encryption and Signature keys must be different');
}
var encAlgo = opts.encryptionAlgorithm;
var required = ENCRYPTION_ALGORITHMS[encAlgo];
if (opts.encryptionKey.length !== required) {
throw new Error(
'Encryption Key for '+encAlgo+' must be exactly '+required+' bytes '+
'('+(required*8)+' bits)'
);
}
var sigAlgo = opts.signatureAlgorithm;
var minimum = SIGNATURE_ALGORITHMS[sigAlgo];
if (opts.signatureKey.length < minimum) {
throw new Error(
'Encryption Key for '+sigAlgo+' must be at least '+minimum+' bytes '+
'('+(minimum*8)+' bits)'
);
}
}
function constantTimeEquals(a, b) {
// Ideally this would be a native function, so it's less sensitive to how the
// JS engine might optimize.
@ -475,7 +511,6 @@ Object.defineProperty(Session.prototype, 'content', {
}
});
function clientSessionFactory(opts) {
if (!opts) {
throw new Error("no options provided, some are required");
@ -494,17 +529,17 @@ function clientSessionFactory(opts) {
var encAlg = opts.encryptionAlgorithm || DEFAULT_ENCRYPTION_ALGO;
encAlg = encAlg.toLowerCase();
if (ENCRYPTION_ALGORITHMS.indexOf(encAlg) === -1) {
if (!ENCRYPTION_ALGORITHMS[encAlg]) {
throw new Error('invalid encryptionAlgorithm, supported are: '+
ENCRYPTION_ALGORITHMS.join(', '));
Object.keys(ENCRYPTION_ALGORITHMS).join(', '));
}
opts.encryptionAlgorithm = encAlg;
var sigAlg = opts.signatureAlgorithm || DEFAULT_SIGNATURE_ALGO;
sigAlg = sigAlg.toLowerCase();
if (SIGNATURE_ALGORITHMS.indexOf(sigAlg) === -1) {
if (!SIGNATURE_ALGORITHMS[sigAlg]) {
throw new Error('invalid signatureAlgorithm, supported are: '+
SIGNATURE_ALGORITHMS.join(', '));
Object.keys(SIGNATURE_ALGORITHMS).join(', '));
}
opts.signatureAlgorithm = sigAlg;
@ -523,6 +558,7 @@ function clientSessionFactory(opts) {
*/
setupKeys(opts);
keyConstraints(opts);
const propertyName = opts.requestKey || opts.cookieName;

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

@ -1186,33 +1186,34 @@ suite.addBatch({
}
});
var sixtyFourByteKey = new Buffer(
'0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
'binary'
);
var HMAC_EXPECT = {
// aligned so you can see the dropN effect:
'sha256':
'ib46vUCBTNOcEl9P6dRwlxZNGNQMHDMulJEc+sAcET8=',
'PRYaxV/8RkMyIT/Ib+tIUOWiSn+0EvodJ5rtG1FQHz0=',
'sha256-drop128':
'ib46vUCBTNOcEl9P6dRwlw==',
'PRYaxV/8RkMyIT/Ib+tIUA==',
'sha384':
'JRnBFUT/W+/EjpBdWmQ/hctq1g1/IUaD6Sqyi9qGH4R2a8uv+86vZXvY72fYNTYw',
'MND9nz6pxbQC5m41ZPRXhJIuqTj9/hu4gtWZ8t8LgdFLQFWQfC8jhijB0NHLpeA7',
'sha384-drop192':
'JRnBFUT/W+/EjpBdWmQ/hctq1g1/IUaD',
'MND9nz6pxbQC5m41ZPRXhJIuqTj9/hu4',
'sha512':
'l4D3LI09OMccrCXQcXl/biDZM1t1yDHEqZbz5DXb1IxUnX956imItOBuJu/bP0Zr'+
'wzWl2vJxNvOBWpfdA9xl4Q==',
'Hr4KLVLyglIwQ43C9U2bmieWBVLnD/F+lzCSF072Ds2b87MK+gbnR0p75A+I+5ez+aiemMGuMZyKVAUWfMMaUA==',
'sha512-drop256':
'l4D3LI09OMccrCXQcXl/biDZM1t1yDHEqZbz5DXb1Iw='
'Hr4KLVLyglIwQ43C9U2bmieWBVLnD/F+lzCSF072Ds0='
};
function testHmac(algo) {
var block = {};
block.topic = function() {
var sixteen = new Buffer('0123456789abcdef','binary');
var opts = {
signatureAlgorithm: algo,
signatureKey: sixteen
signatureKey: sixtyFourByteKey
};
var iv = sixteen;
var iv = new Buffer('01234567890abcdef','binary'); // 128-bits
var ciphertext = new Buffer('0123456789abcdef0123','binary');
var duration = 876543210;
var createdAt = 1234567890;