From 3363db7760a9b969270e829654acf5edbc8148b0 Mon Sep 17 00:00:00 2001 From: Arnaud Betremieux Date: Mon, 25 Sep 2017 11:37:21 +0200 Subject: [PATCH] Add support for aes128-gcm and aes256-gcm --- lib/xmlenc.js | 50 ++++++++++++++++++++++++++++++------- test/xmlenc.encryptedkey.js | 12 +++++++++ 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/lib/xmlenc.js b/lib/xmlenc.js index 4eb04fb..b00b41a 100644 --- a/lib/xmlenc.js +++ b/lib/xmlenc.js @@ -68,6 +68,12 @@ function encrypt(content, options, callback) { case 'http://www.w3.org/2001/04/xmlenc#aes256-cbc': crypto.randomBytes(32, cb); // generate a symmetric random key 32 bytes length break; + case 'http://www.w3.org/2009/xmlenc11#aes128-gcm': + crypto.randomBytes(16, cb); // generate a symmetric random key 16 bytes length + break; + case 'http://www.w3.org/2009/xmlenc11#aes256-gcm': + crypto.randomBytes(32, cb); // generate a symmetric random key 32 bytes length + break; case 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc': crypto.randomBytes(24, cb); // generate a symmetric random key 24 bytes (192 bits) length break; @@ -89,6 +95,18 @@ function encrypt(content, options, callback) { cb(null, symmetricKey, encryptedContent); }); break; + case 'http://www.w3.org/2009/xmlenc11#aes128-gcm': + encryptWithAlgorithm('aes-128-gcm', symmetricKey, 12, content, options.input_encoding, function (err, encryptedContent) { + if (err) return cb(err); + cb(null, symmetricKey, encryptedContent); + }); + break; + case 'http://www.w3.org/2009/xmlenc11#aes256-gcm': + encryptWithAlgorithm('aes-256-gcm', symmetricKey, 12, content, options.input_encoding, function (err, encryptedContent) { + if (err) return cb(err); + cb(null, symmetricKey, encryptedContent); + }); + break; case 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc': encryptWithAlgorithm('des-ede3-cbc', symmetricKey, 8, content, options.input_encoding, function (err, encryptedContent) { if (err) return cb(err); @@ -139,6 +157,10 @@ function decrypt(xml, options, callback) { return callback(null, decryptWithAlgorithm('aes-128-cbc', symmetricKey, 16, encrypted)); case 'http://www.w3.org/2001/04/xmlenc#aes256-cbc': return callback(null, decryptWithAlgorithm('aes-256-cbc', symmetricKey, 16, encrypted)); + case 'http://www.w3.org/2009/xmlenc11#aes128-gcm': + return callback(null, decryptWithAlgorithm('aes-128-gcm', symmetricKey, 12, encrypted)); + case 'http://www.w3.org/2009/xmlenc11#aes256-gcm': + return callback(null, decryptWithAlgorithm('aes-256-gcm', symmetricKey, 12, encrypted)); case 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc': return callback(null, decryptWithAlgorithm('des-ede3-cbc', symmetricKey, 8, encrypted)); default: @@ -201,23 +223,33 @@ function encryptWithAlgorithm(algorithm, symmetricKey, ivLength, content, encodi var cipher = crypto.createCipheriv(algorithm, symmetricKey, iv); // encrypted content var encrypted = cipher.update(content, encoding, 'binary') + cipher.final('binary'); - return callback(null, Buffer.concat([iv, new Buffer(encrypted, 'binary')])); + var authTag = algorithm.slice(-3) === "gcm" ? cipher.getAuthTag() : new Buffer(""); + + return callback(null, Buffer.concat([iv, new Buffer(encrypted, 'binary'), authTag])); }); } function decryptWithAlgorithm(algorithm, symmetricKey, ivLength, content) { var decipher = crypto.createDecipheriv(algorithm, symmetricKey, content.slice(0,ivLength)); - decipher.setAutoPadding(false); + if (algorithm.slice(-3)=="gcm") { + decipher.setAutoPadding(true); + decipher.setAuthTag(content.slice(-16)); + content = content.slice(0,-16); + } else { + decipher.setAutoPadding(false); + } var decrypted = decipher.update(content.slice(ivLength), null, 'binary') + decipher.final('binary'); - // Remove padding bytes equal to the value of the last byte of the returned data. - var padding = decrypted.charCodeAt(decrypted.length - 1); - if (1 <= padding && padding <= ivLength) { - decrypted = decrypted.substr(0, decrypted.length - padding); - } else { - callback(new Error('padding length invalid')); - return; + if (algorithm.slice(-3)!=="gcm") { + // Remove padding bytes equal to the value of the last byte of the returned data. + var padding = decrypted.charCodeAt(decrypted.length - 1); + if (1 <= padding && padding <= ivLength) { + decrypted = decrypted.substr(0, decrypted.length - padding); + } else { + callback(new Error('padding length invalid')); + return; + } } return new Buffer(decrypted, 'binary').toString('utf8'); diff --git a/test/xmlenc.encryptedkey.js b/test/xmlenc.encryptedkey.js index 7017826..66216d8 100644 --- a/test/xmlenc.encryptedkey.js +++ b/test/xmlenc.encryptedkey.js @@ -20,6 +20,18 @@ describe('encrypt', function() { encryptionAlgorithm: 'http://www.w3.org/2001/04/xmlenc#aes128-cbc', keyEncryptionAlgorighm: 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p' } + }, { + name: 'aes-256-gcm', + encryptionOptions: { + encryptionAlgorithm: 'http://www.w3.org/2009/xmlenc11#aes256-gcm', + keyEncryptionAlgorighm: 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p' + } + }, { + name: 'aes-128-gcm', + encryptionOptions: { + encryptionAlgorithm: 'http://www.w3.org/2009/xmlenc11#aes128-gcm', + keyEncryptionAlgorighm: 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p' + } }, { name: 'des-ede3-cbc', encryptionOptions: {