1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 /*
21 * XSEC
22 *
23 * XSECCryptoSymmetricKey := Bulk encryption algorithms should all be
24 * implemented via this interface
25 *
26 * Author(s): Milan Tomic
27 *
28 */
29
30 #include <xsec/framework/XSECDefs.hpp>
31 #include <xsec/utils/XSECPlatformUtils.hpp>
32 #include <xsec/enc/NSS/NSSCryptoProvider.hpp>
33 #include <xsec/enc/NSS/NSSCryptoSymmetricKey.hpp>
34 #include <xsec/framework/XSECError.hpp>
35 #include <xsec/enc/XSECCryptoException.hpp>
36
37 #include <xercesc/util/Janitor.hpp>
38
39 #if defined (XSEC_HAVE_NSS)
40
41 #include "prerror.h"
42
43 XERCES_CPP_NAMESPACE_USE
44
45 // --------------------------------------------------------------------------------
46 // Constructor
47 // --------------------------------------------------------------------------------
48
NSSCryptoSymmetricKey(XSECCryptoSymmetricKey::SymmetricKeyType type)49 NSSCryptoSymmetricKey::NSSCryptoSymmetricKey(XSECCryptoSymmetricKey::SymmetricKeyType type) :
50 m_keyType(type),
51 m_keyMode(MODE_NONE),
52 m_initialised(false),
53 mp_k(NULL)
54 {
55
56
57
58 }
59
60 // --------------------------------------------------------------------------------
61 // Destructor
62 // --------------------------------------------------------------------------------
63
~NSSCryptoSymmetricKey()64 NSSCryptoSymmetricKey::~NSSCryptoSymmetricKey() {
65
66 if (mp_k != 0)
67 PK11_FreeSymKey(mp_k);
68
69 }
70
71 // --------------------------------------------------------------------------------
72 // Get key type
73 // --------------------------------------------------------------------------------
74
getSymmetricKeyType() const75 XSECCryptoSymmetricKey::SymmetricKeyType NSSCryptoSymmetricKey::getSymmetricKeyType() const {
76
77 return m_keyType;
78
79 }
80
81 // --------------------------------------------------------------------------------
82 // Get provider name
83 // --------------------------------------------------------------------------------
84
getProviderName() const85 const XMLCh * NSSCryptoSymmetricKey::getProviderName() const {
86
87 return DSIGConstants::s_unicodeStrPROVNSS;
88
89 }
90
91 // --------------------------------------------------------------------------------
92 // Replicate key
93 // --------------------------------------------------------------------------------
94
clone() const95 XSECCryptoKey * NSSCryptoSymmetricKey::clone() const {
96
97 NSSCryptoSymmetricKey * ret;
98
99 XSECnew(ret, NSSCryptoSymmetricKey(m_keyType));
100
101 if (mp_k != 0) {
102
103 ret->mp_k = PK11_ReferenceSymKey(mp_k);
104
105 }
106
107 ret->m_keyType = m_keyType;
108
109 return ret;
110
111 }
112
113 // --------------------------------------------------------------------------------
114 // Store the key value
115 // --------------------------------------------------------------------------------
116
setKey(const unsigned char * key,unsigned int keyLen)117 void NSSCryptoSymmetricKey::setKey(const unsigned char * key, unsigned int keyLen) {
118
119 if (mp_k != 0) {
120 PK11_FreeSymKey(mp_k);
121 mp_k = 0;
122 }
123
124 CK_MECHANISM_TYPE cipherMech;
125
126 switch (m_keyType) {
127
128 case (XSECCryptoSymmetricKey::KEY_3DES_192) :
129
130 cipherMech = CKM_DES3_CBC_PAD;
131 break;
132
133 case (XSECCryptoSymmetricKey::KEY_AES_128) :
134 case (XSECCryptoSymmetricKey::KEY_AES_192) :
135 case (XSECCryptoSymmetricKey::KEY_AES_256) :
136
137 cipherMech = CKM_AES_CBC_PAD;
138 break;
139
140 default:
141
142 throw XSECCryptoException(XSECCryptoException::SymmetricError,
143 "NSS:SymmetricKey - Unknown key type");
144
145 }
146
147 // Turn the raw key into a SECItem
148 SECItem keyItem;
149 keyItem.data = (unsigned char*)key;
150 keyItem.len = keyLen;
151
152 PK11SlotInfo * slot = PK11_GetBestSlot(cipherMech, NULL);
153
154 // Turn the SECItem into a key object
155 mp_k = PK11_ImportSymKey(slot,
156 cipherMech,
157 PK11_OriginUnwrap,
158 CKA_ENCRYPT,
159 &keyItem,
160 NULL);
161
162 if (slot)
163 PK11_FreeSlot(slot);
164
165 }
166
167 // --------------------------------------------------------------------------------
168 // Decrypt context initialisation
169 // --------------------------------------------------------------------------------
170
decryptCtxInit(const unsigned char * iv)171 int NSSCryptoSymmetricKey::decryptCtxInit(const unsigned char * iv) {
172
173 // Returns amount of IV data used (in bytes)
174 // Sets m_initialised if the key is OK and the IV is OK.
175
176 if (m_initialised)
177 return 0;
178
179 if (mp_k == 0) {
180 throw XSECCryptoException(XSECCryptoException::SymmetricError,
181 "NSS:SymmetricKey - Cannot initialise without key");
182 }
183 else if (m_keyMode == MODE_NONE) {
184 throw XSECCryptoException(XSECCryptoException::SymmetricError,
185 "NSS:SymmetricKey - Cannot initialise without mode");
186 }
187
188 // Set up the context according to the required cipher type
189
190 switch (m_keyType) {
191
192 case (XSECCryptoSymmetricKey::KEY_3DES_192) :
193
194 // A 3DES key
195
196 if (m_keyMode == MODE_CBC) {
197
198 if (iv == NULL) {
199
200 return 0; // Cannot initialise without an IV
201
202 }
203
204 SECItem ivItem;
205 ivItem.data = (unsigned char*)iv;
206 ivItem.len = 8;
207 int encryptAlg = (m_doPad == true ? CKM_DES3_CBC_PAD : CKM_DES3_CBC);
208
209 SECItem * secParam = PK11_ParamFromIV(encryptAlg, &ivItem);
210 mp_ctx = PK11_CreateContextBySymKey(encryptAlg, CKA_DECRYPT, mp_k, secParam);
211
212 if (secParam)
213 SECITEM_FreeItem(secParam, PR_TRUE);
214
215 m_ivSize = 8;
216 }
217 else if (m_keyMode == MODE_ECB) {
218 SECItem * secParam = PK11_ParamFromIV(CKM_DES3_ECB, NULL);
219 mp_ctx = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_DECRYPT, mp_k, secParam);
220 if (secParam)
221 SECITEM_FreeItem(secParam, PR_TRUE);
222 m_ivSize = 0;
223 }
224 else {
225 throw XSECCryptoException(XSECCryptoException::SymmetricError,
226 "NSS:SymmetricKey - Unrecognized cipher mode");
227 }
228
229 break;
230
231 case (XSECCryptoSymmetricKey::KEY_AES_128) :
232 case (XSECCryptoSymmetricKey::KEY_AES_192) :
233 case (XSECCryptoSymmetricKey::KEY_AES_256) :
234
235 // An AES key
236
237 if (m_keyMode == MODE_CBC) {
238
239 if (iv == NULL) {
240
241 return 0; // Cannot initialise without an IV
242
243 }
244
245 SECItem ivItem;
246 ivItem.data = (unsigned char*)iv;
247 ivItem.len = 16;
248
249 SECItem * secParam = PK11_ParamFromIV(CKM_AES_CBC_PAD, &ivItem);
250 mp_ctx = PK11_CreateContextBySymKey(CKM_AES_CBC_PAD, CKA_DECRYPT, mp_k, secParam);
251
252 if (secParam)
253 SECITEM_FreeItem(secParam, PR_TRUE);
254
255 m_ivSize = 16;
256
257 }
258 else if (m_keyMode == MODE_ECB) {
259
260 SECItem * secParam = PK11_ParamFromIV(CKM_AES_ECB, NULL);
261 mp_ctx = PK11_CreateContextBySymKey(CKM_AES_ECB, CKA_DECRYPT, mp_k, secParam);
262 if (secParam)
263 SECITEM_FreeItem(secParam, PR_TRUE);
264
265 m_ivSize = 0;
266
267 }
268 else {
269 throw XSECCryptoException(XSECCryptoException::SymmetricError,
270 "NSS:SymmetricKey - Unrecognized cipher mode");
271 }
272
273 break;
274
275 default :
276
277 // Cannot do this without an IV
278 throw XSECCryptoException(XSECCryptoException::SymmetricError,
279 "NSS:SymmetricKey - Unknown key type");
280
281 }
282
283 // Reset some parameters
284 m_initialised = true;
285
286 // Return number of bytes chewed up by IV
287 return m_ivSize;
288 }
289
290 // --------------------------------------------------------------------------------
291 // Decrypt initialisation
292 // --------------------------------------------------------------------------------
293
decryptInit(bool doPad,SymmetricKeyMode mode,const unsigned char * iv,const unsigned char * tag,unsigned int taglen)294 bool NSSCryptoSymmetricKey::decryptInit(bool doPad,
295 SymmetricKeyMode mode,
296 const unsigned char * iv,
297 const unsigned char* tag,
298 unsigned int taglen) {
299
300 m_initialised = false;
301 m_ivSent = iv == NULL;
302 m_doPad = doPad;
303 m_keyMode = mode;
304 decryptCtxInit(iv);
305 return true;
306
307 }
308
309 // --------------------------------------------------------------------------------
310 // Decrypt
311 // --------------------------------------------------------------------------------
312
decrypt(const unsigned char * inBuf,unsigned char * plainBuf,unsigned int inLength,unsigned int maxOutLength)313 unsigned int NSSCryptoSymmetricKey::decrypt(const unsigned char * inBuf,
314 unsigned char * plainBuf,
315 unsigned int inLength,
316 unsigned int maxOutLength) {
317
318 // NOTE: This won't actually stop NSS blowing the buffer, so the onus is
319 // on the caller.
320
321 unsigned int offset = 0;
322 if (!m_initialised) {
323 offset = decryptCtxInit(inBuf);
324 if (offset > inLength) {
325 throw XSECCryptoException(XSECCryptoException::SymmetricError,
326 "NSS:SymmetricKey - Not enough data passed in to get IV");
327 }
328 }
329
330 int outl = inLength - offset;
331
332 SECStatus s = PK11_CipherOp(mp_ctx, plainBuf, &outl, maxOutLength, (unsigned char*)inBuf, inLength);
333
334 if (s != SECSuccess) {
335
336 throw XSECCryptoException(XSECCryptoException::SymmetricError,
337 "NSS:SymmetricKey - Error during NSS decrypt");
338
339 }
340
341 // remove IV
342 if (m_ivSent) {
343 memmove(plainBuf, &plainBuf[m_ivSize], outl);
344 outl -= m_ivSize;
345 m_ivSent = false;
346 }
347
348 return outl;
349
350 }
351
352 // --------------------------------------------------------------------------------
353 // Decrypt finalisation
354 // --------------------------------------------------------------------------------
355
decryptFinish(unsigned char * plainBuf,unsigned int maxOutLength)356 unsigned int NSSCryptoSymmetricKey::decryptFinish(unsigned char * plainBuf,
357 unsigned int maxOutLength) {
358
359 unsigned int outl = 0;
360
361 SECStatus s = PK11_DigestFinal(mp_ctx, plainBuf, &outl, maxOutLength);
362
363 if (s != SECSuccess) {
364
365 throw XSECCryptoException(XSECCryptoException::SymmetricError,
366 "NSS:SymmetricKey - Error during NSS decrypt finalisation");
367
368 }
369
370 PK11_DestroyContext(mp_ctx, PR_TRUE);
371 mp_ctx = NULL;
372 m_initialised = false;
373
374 return outl;
375 }
376
377 // --------------------------------------------------------------------------------
378 // Encrypt initialisation
379 // --------------------------------------------------------------------------------
380
encryptInit(bool doPad,SymmetricKeyMode mode,const unsigned char * iv)381 bool NSSCryptoSymmetricKey::encryptInit(bool doPad,
382 SymmetricKeyMode mode,
383 const unsigned char * iv) {
384
385 if (m_initialised == true)
386 return true;
387
388 m_doPad = doPad;
389 m_keyMode = mode;
390
391 if (mp_k == 0) {
392 throw XSECCryptoException(XSECCryptoException::SymmetricError,
393 "NSS:SymmetricKey - Cannot initialise without key");
394 }
395 else if (m_keyMode == MODE_NONE) {
396 throw XSECCryptoException(XSECCryptoException::SymmetricError,
397 "NSS:SymmetricKey - Cannot initialise without mode");
398 }
399
400 // Do some parameter initialisation
401 m_initialised = true;
402
403 // Set up the context according to the required cipher type
404
405 const unsigned char * usedIV = NULL;
406 unsigned char genIV[256];
407
408 // Tell the library that the IV still has to be sent
409
410 m_ivSent = false;
411
412 switch (m_keyType) {
413
414 case (XSECCryptoSymmetricKey::KEY_3DES_192) :
415
416 // A 3DES key
417
418 if (m_keyMode == MODE_CBC) {
419
420 if (iv == NULL) {
421
422 SECStatus s = PK11_GenerateRandom(genIV, 8);
423
424 if (s != SECSuccess) {
425
426 throw XSECCryptoException(XSECCryptoException::SymmetricError,
427 "NSS:SymmetricKey - Error generating random IV");
428
429 }
430
431 usedIV = genIV;
432
433 }
434 else
435 usedIV = iv;
436
437 SECItem ivItem;
438 ivItem.data = (unsigned char*)usedIV;
439 ivItem.len = 8;
440 int encryptAlg = (m_doPad == true ? CKM_DES3_CBC_PAD : CKM_DES3_CBC);
441
442 SECItem * secParam = PK11_ParamFromIV(encryptAlg, &ivItem);
443 mp_ctx = PK11_CreateContextBySymKey(encryptAlg, CKA_ENCRYPT, mp_k, secParam);
444
445 if (secParam)
446 SECITEM_FreeItem(secParam, PR_TRUE);
447
448 m_ivSize = 8;
449 }
450 else if (m_keyMode == MODE_ECB) {
451 mp_ctx = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, mp_k, NULL);
452
453 m_ivSize = 0;
454 }
455 else {
456 throw XSECCryptoException(XSECCryptoException::SymmetricError,
457 "NSS:SymmetricKey - Unsupported DES3 cipher mode");
458 }
459
460 break;
461
462 case (XSECCryptoSymmetricKey::KEY_AES_128) :
463 case (XSECCryptoSymmetricKey::KEY_AES_192) :
464 case (XSECCryptoSymmetricKey::KEY_AES_256) :
465
466 // An AES key
467
468 if (m_keyMode == MODE_CBC) {
469
470 if (iv == NULL) {
471
472 SECStatus s = PK11_GenerateRandom(genIV, 16);
473
474 if (s != SECSuccess) {
475
476 throw XSECCryptoException(XSECCryptoException::SymmetricError,
477 "NSS:SymmetricKey - Error generating random IV");
478
479 }
480
481 usedIV = genIV;
482
483 }
484 else
485 usedIV = iv;
486
487 SECItem ivItem;
488 ivItem.data = (unsigned char*)usedIV;
489 ivItem.len = 16;
490
491 SECItem * secParam = PK11_ParamFromIV(CKM_AES_CBC_PAD, &ivItem);
492 mp_ctx = PK11_CreateContextBySymKey(CKM_AES_CBC_PAD, CKA_ENCRYPT, mp_k, secParam);
493
494 if (secParam)
495 SECITEM_FreeItem(secParam, PR_TRUE);
496
497 m_ivSize = 16;
498 }
499 else if (m_keyMode == MODE_ECB) {
500 SECItem * secParam = PK11_ParamFromIV(CKM_AES_ECB, NULL);
501 mp_ctx = PK11_CreateContextBySymKey(CKM_AES_ECB, CKA_ENCRYPT, mp_k, secParam);
502 if (secParam)
503 SECITEM_FreeItem(secParam, PR_TRUE);
504
505 m_ivSize = 0;
506 }
507 else {
508 throw XSECCryptoException(XSECCryptoException::SymmetricError,
509 "NSS:SymmetricKey - Unsupported AES cipher mode");
510 }
511
512 break;
513
514 default :
515
516 throw XSECCryptoException(XSECCryptoException::SymmetricError,
517 "NSS:SymmetricKey - Unknown key type");
518
519 }
520
521 // Add IV
522 if (m_keyMode == MODE_CBC || m_keyMode == MODE_GCM) {
523
524 memcpy(m_lastBlock, usedIV, m_ivSize);
525
526 }
527
528 return true;
529
530 }
531
532 // --------------------------------------------------------------------------------
533 // Encrypt
534 // --------------------------------------------------------------------------------
535
encrypt(const unsigned char * inBuf,unsigned char * cipherBuf,unsigned int inLength,unsigned int maxOutLength)536 unsigned int NSSCryptoSymmetricKey::encrypt(const unsigned char * inBuf,
537 unsigned char * cipherBuf,
538 unsigned int inLength,
539 unsigned int maxOutLength) {
540
541 if (m_initialised == false) {
542
543 encryptInit();
544
545 }
546
547 // NOTE: This won't actually stop NSS blowing the buffer, so the onus is
548 // on the caller.
549
550 unsigned int offset = 0;
551 if (m_ivSent == false && m_ivSize > 0) {
552
553 memcpy(cipherBuf, m_lastBlock, m_ivSize);
554 m_ivSent = true;
555
556 offset = m_ivSize;
557
558 }
559
560 int outl = 0;
561
562 if (inLength + offset > maxOutLength) {
563
564 throw XSECCryptoException(XSECCryptoException::SymmetricError,
565 "NSS:SymmetricKey - Not enough space in output buffer for encrypt");
566
567 }
568
569 SECStatus s = PK11_CipherOp(mp_ctx,
570 &cipherBuf[offset],
571 &outl,
572 maxOutLength - offset,
573 (unsigned char*)inBuf,
574 inLength);
575
576 if (s != SECSuccess) {
577
578 throw XSECCryptoException(XSECCryptoException::SymmetricError,
579 "NSS:SymmetricKey - Error during NSS encrypt");
580
581 }
582
583 return outl + offset;
584
585 }
586
587 // --------------------------------------------------------------------------------
588 // Encrypt finalisation
589 // --------------------------------------------------------------------------------
590
encryptFinish(unsigned char * cipherBuf,unsigned int maxOutLength,unsigned int taglen)591 unsigned int NSSCryptoSymmetricKey::encryptFinish(unsigned char * cipherBuf,
592 unsigned int maxOutLength,
593 unsigned int taglen) {
594
595 unsigned int outl = 0;
596
597 SECStatus s = PK11_DigestFinal(mp_ctx, cipherBuf, &outl, maxOutLength);
598
599 if (s != SECSuccess) {
600
601 throw XSECCryptoException(XSECCryptoException::SymmetricError,
602 "NSS:SymmetricKey - Error during NSS encrypt");
603
604 }
605
606 PK11_DestroyContext(mp_ctx, PR_TRUE);
607 mp_ctx = NULL;
608
609 // Setup so can be re-used
610 m_initialised = false;
611
612 return outl;
613
614 }
615
616 #endif /* XSEC_HAVE_NSS */
617