@@ -78,6 +78,12 @@ function encrypt(content, options, callback) {
78
78
case 'http://www.w3.org/2001/04/xmlenc#aes256-cbc' :
79
79
crypto . randomBytes ( 32 , cb ) ; // generate a symmetric random key 32 bytes length
80
80
break ;
81
+ case 'http://www.w3.org/2009/xmlenc11#aes128-gcm' :
82
+ crypto . randomBytes ( 16 , cb ) ; // generate a symmetric random key 16 bytes length
83
+ break ;
84
+ case 'http://www.w3.org/2009/xmlenc11#aes256-gcm' :
85
+ crypto . randomBytes ( 32 , cb ) ; // generate a symmetric random key 32 bytes length
86
+ break ;
81
87
case 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc' :
82
88
crypto . randomBytes ( 24 , cb ) ; // generate a symmetric random key 24 bytes (192 bits) length
83
89
break ;
@@ -100,6 +106,18 @@ function encrypt(content, options, callback) {
100
106
cb ( null , encryptedContent ) ;
101
107
} ) ;
102
108
break ;
109
+ case 'http://www.w3.org/2009/xmlenc11#aes128-gcm' :
110
+ encryptWithAlgorithm ( 'aes-128-gcm' , symmetricKey , 12 , content , options . input_encoding , function ( err , encryptedContent ) {
111
+ if ( err ) return cb ( err ) ;
112
+ cb ( null , encryptedContent ) ;
113
+ } ) ;
114
+ break ;
115
+ case 'http://www.w3.org/2009/xmlenc11#aes256-gcm' :
116
+ encryptWithAlgorithm ( 'aes-256-gcm' , symmetricKey , 12 , content , options . input_encoding , function ( err , encryptedContent ) {
117
+ if ( err ) return cb ( err ) ;
118
+ cb ( null , encryptedContent ) ;
119
+ } ) ;
120
+ break ;
103
121
case 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc' :
104
122
encryptWithAlgorithm ( 'des-ede3-cbc' , symmetricKey , 8 , content , options . input_encoding , function ( err , encryptedContent ) {
105
123
if ( err ) return cb ( err ) ;
@@ -114,7 +132,6 @@ function encrypt(content, options, callback) {
114
132
function encrypt_key ( symmetricKey , encryptedContent , cb ) {
115
133
encryptKeyInfo ( symmetricKey , options , function ( err , keyInfo ) {
116
134
if ( err ) return cb ( err ) ;
117
-
118
135
var result = utils . renderTemplate ( 'encrypted-key' , {
119
136
encryptedContent : encryptedContent . toString ( 'base64' ) ,
120
137
keyInfo : keyInfo ,
@@ -170,14 +187,17 @@ function decrypt(xml, options, callback) {
170
187
var encryptedContent = xpath . select ( "//*[local-name(.)='EncryptedData']/*[local-name(.)='CipherData']/*[local-name(.)='CipherValue']" , doc ) [ 0 ] ;
171
188
172
189
var encrypted = Buffer . from ( encryptedContent . textContent , 'base64' ) ;
173
-
174
190
switch ( encryptionAlgorithm ) {
175
191
case 'http://www.w3.org/2001/04/xmlenc#aes128-cbc' :
176
192
return callback ( null , decryptWithAlgorithm ( 'aes-128-cbc' , symmetricKey , 16 , encrypted ) ) ;
177
193
case 'http://www.w3.org/2001/04/xmlenc#aes256-cbc' :
178
194
return callback ( null , decryptWithAlgorithm ( 'aes-256-cbc' , symmetricKey , 16 , encrypted ) ) ;
179
195
case 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc' :
180
196
return callback ( null , decryptWithAlgorithm ( 'des-ede3-cbc' , symmetricKey , 8 , encrypted ) ) ;
197
+ case 'http://www.w3.org/2009/xmlenc11#aes128-gcm' :
198
+ return callback ( null , decryptWithAlgorithm ( 'aes-128-gcm' , symmetricKey , 12 , encrypted ) ) ;
199
+ case 'http://www.w3.org/2009/xmlenc11#aes256-gcm' :
200
+ return callback ( null , decryptWithAlgorithm ( 'aes-256-gcm' , symmetricKey , 12 , encrypted ) ) ;
181
201
default :
182
202
return callback ( new Error ( 'encryption algorithm ' + encryptionAlgorithm + ' not supported' ) ) ;
183
203
}
@@ -237,24 +257,34 @@ function encryptWithAlgorithm(algorithm, symmetricKey, ivLength, content, encodi
237
257
var cipher = crypto . createCipheriv ( algorithm , symmetricKey , iv ) ;
238
258
// encrypted content
239
259
var encrypted = cipher . update ( content , encoding , 'binary' ) + cipher . final ( 'binary' ) ;
240
- return callback ( null , Buffer . concat ( [ iv , Buffer . from ( encrypted , 'binary' ) ] ) ) ;
260
+ var authTag = algorithm . slice ( - 3 ) === "gcm" ? cipher . getAuthTag ( ) : Buffer . from ( "" ) ;
261
+ //Format mentioned: https://www.w3.org/TR/xmlenc-core1/#sec-AES-GCM
262
+ var r = Buffer . concat ( [ iv , Buffer . from ( encrypted , 'binary' ) , authTag ] ) ;
263
+ return callback ( null , r ) ;
241
264
} ) ;
242
265
}
243
266
244
267
function decryptWithAlgorithm ( algorithm , symmetricKey , ivLength , content ) {
245
268
var decipher = crypto . createDecipheriv ( algorithm , symmetricKey , content . slice ( 0 , ivLength ) ) ;
246
269
decipher . setAutoPadding ( false ) ;
247
270
271
+ if ( algorithm . slice ( - 3 ) === "gcm" ) {
272
+ decipher . setAuthTag ( content . slice ( - 16 ) ) ;
273
+ content = content . slice ( 0 , - 16 ) ;
274
+ }
248
275
var decrypted = decipher . update ( content . slice ( ivLength ) , null , 'binary' ) + decipher . final ( 'binary' ) ;
249
276
277
+ if ( algorithm . slice ( - 3 ) !== "gcm" ) {
250
278
// Remove padding bytes equal to the value of the last byte of the returned data.
279
+ // Padding for GCM not required per: https://www.w3.org/TR/xmlenc-core1/#sec-AES-GCM
251
280
var padding = decrypted . charCodeAt ( decrypted . length - 1 ) ;
252
281
if ( 1 <= padding && padding <= ivLength ) {
253
282
decrypted = decrypted . substr ( 0 , decrypted . length - padding ) ;
254
283
} else {
255
284
callback ( new Error ( 'padding length invalid' ) ) ;
256
285
return ;
257
286
}
287
+ }
258
288
259
289
return Buffer . from ( decrypted , 'binary' ) . toString ( 'utf8' ) ;
260
290
}
0 commit comments