Skip to content

Commit aadda00

Browse files
authored
Merge pull request #53 from cpgo/custom-key-lookup
Add option to pass a custom key lookup function
2 parents aa4cc1e + 974243e commit aadda00

File tree

2 files changed

+56
-10
lines changed

2 files changed

+56
-10
lines changed

nodejs/ece.js

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,13 @@ function webpushSecret(header, mode) {
176176
SHA_256_LENGTH));
177177
}
178178

179-
function extractSecret(header, mode) {
179+
function extractSecret(header, mode, keyLookupCallback) {
180+
if (keyLookupCallback) {
181+
if (!isFunction(keyLookupCallback)) {
182+
throw new Error('Callback is not a function')
183+
}
184+
}
185+
180186
if (header.key) {
181187
if (header.key.length !== KEY_LENGTH) {
182188
throw new Error('An explicit key must be ' + KEY_LENGTH + ' bytes');
@@ -186,7 +192,11 @@ function extractSecret(header, mode) {
186192

187193
if (!header.privateKey) {
188194
// Lookup based on keyid
189-
var key = header.keymap && header.keymap[header.keyid];
195+
if (!keyLookupCallback) {
196+
var key = header.keymap && header.keymap[header.keyid];
197+
} else {
198+
var key = keyLookupCallback(header.keyid)
199+
}
190200
if (!key) {
191201
throw new Error('No saved key (keyid: "' + header.keyid + '")');
192202
}
@@ -196,7 +206,7 @@ function extractSecret(header, mode) {
196206
return webpushSecret(header, mode);
197207
}
198208

199-
function deriveKeyAndNonce(header, mode) {
209+
function deriveKeyAndNonce(header, mode, lookupKeyCallback) {
200210
if (!header.salt) {
201211
throw new Error('must include a salt parameter for ' + header.version);
202212
}
@@ -207,18 +217,18 @@ function deriveKeyAndNonce(header, mode) {
207217
// really old
208218
keyInfo = 'Content-Encoding: aesgcm128';
209219
nonceInfo = 'Content-Encoding: nonce';
210-
secret = extractSecretAndContext(header, mode).secret;
220+
secret = extractSecretAndContext(header, mode, lookupKeyCallback).secret;
211221
} else if (header.version === 'aesgcm') {
212222
// old
213-
var s = extractSecretAndContext(header, mode);
223+
var s = extractSecretAndContext(header, mode, lookupKeyCallback);
214224
keyInfo = info('aesgcm', s.context);
215225
nonceInfo = info('nonce', s.context);
216226
secret = s.secret;
217227
} else if (header.version === 'aes128gcm') {
218228
// latest
219229
keyInfo = Buffer.from('Content-Encoding: aes128gcm\0');
220230
nonceInfo = Buffer.from('Content-Encoding: nonce\0');
221-
secret = extractSecret(header, mode);
231+
secret = extractSecret(header, mode, lookupKeyCallback);
222232
} else {
223233
throw new Error('Unable to set context for mode ' + params.version);
224234
}
@@ -361,13 +371,13 @@ function decryptRecord(key, counter, buffer, header, last) {
361371
*
362372
* The |params.privateKey| includes the private key of the receiver.
363373
*/
364-
function decrypt(buffer, params) {
374+
function decrypt(buffer, params, keyLookupCallback) {
365375
var header = parseParams(params);
366376
if (header.version === 'aes128gcm') {
367377
var headerLength = readHeader(buffer, header);
368378
buffer = buffer.slice(headerLength);
369379
}
370-
var key = deriveKeyAndNonce(header, MODE_DECRYPT);
380+
var key = deriveKeyAndNonce(header, MODE_DECRYPT, keyLookupCallback);
371381
var start = 0;
372382
var result = new Buffer(0);
373383

@@ -454,7 +464,7 @@ function writeHeader(header) {
454464
* receiver. |params.privateKey| is used to establish a shared secret. Key
455465
* pairs can be created using |crypto.createECDH()|.
456466
*/
457-
function encrypt(buffer, params) {
467+
function encrypt(buffer, params, keyLookupCallback) {
458468
if (!Buffer.isBuffer(buffer)) {
459469
throw new Error('buffer argument must be a Buffer');
460470
}
@@ -475,7 +485,7 @@ function encrypt(buffer, params) {
475485
result = new Buffer(0);
476486
}
477487

478-
var key = deriveKeyAndNonce(header, MODE_ENCRYPT);
488+
var key = deriveKeyAndNonce(header, MODE_ENCRYPT, keyLookupCallback);
479489
var start = 0;
480490
var padSize = PAD_SIZE[header.version];
481491
var overhead = padSize;
@@ -516,6 +526,11 @@ function encrypt(buffer, params) {
516526
return result;
517527
}
518528

529+
530+
function isFunction(object) {
531+
return typeof(object) === 'function';
532+
}
533+
519534
module.exports = {
520535
decrypt: decrypt,
521536
encrypt: encrypt

nodejs/test.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,36 @@ function checkExamples(version) {
366366
});
367367
}
368368

369+
function useCustomCallback(version) {
370+
const customCallback = (keyId) => {
371+
let keys = [
372+
{
373+
keyId: '123456',
374+
key: '1928375791029'
375+
},
376+
{
377+
keyId: '999',
378+
key: '9999999999'
379+
}
380+
]
381+
return keys.find(x => { return x.keyId === keyId.toString() }).key
382+
}
383+
384+
let input = generateInput()
385+
var parameters = {
386+
keyid: '123456',
387+
};
388+
log('Testing custom function')
389+
390+
var encrypted = ece.encrypt(input, parameters, customCallback);
391+
logbuf('encrypted', encrypted)
392+
393+
var decrypted = ece.decrypt(encrypted, parameters, customCallback);
394+
logbuf('decrypted', decrypted)
395+
396+
assert.equal(Buffer.compare(decrypted, input), 0)
397+
}
398+
369399
validate();
370400
filterTests([ 'aesgcm128', 'aesgcm', 'aes128gcm' ])
371401
.forEach(function(version) {
@@ -376,6 +406,7 @@ filterTests([ 'aesgcm128', 'aesgcm', 'aes128gcm' ])
376406
detectTruncation,
377407
useDH,
378408
checkExamples,
409+
useCustomCallback
379410
])
380411
.forEach(function(test) {
381412
log(version + ' Test: ' + test.name);

0 commit comments

Comments
 (0)