1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.opensaml.xml.encryption;
18
19 import java.security.Key;
20 import java.security.KeyException;
21 import java.security.NoSuchAlgorithmException;
22 import java.security.interfaces.DSAPublicKey;
23 import java.util.ArrayList;
24 import java.util.Iterator;
25 import java.util.List;
26
27 import javax.crypto.SecretKey;
28
29 import org.apache.xml.security.Init;
30 import org.apache.xml.security.encryption.XMLCipher;
31 import org.apache.xml.security.encryption.XMLEncryptionException;
32 import org.opensaml.xml.Configuration;
33 import org.opensaml.xml.XMLObject;
34 import org.opensaml.xml.XMLObjectBuilderFactory;
35 import org.opensaml.xml.io.Marshaller;
36 import org.opensaml.xml.io.MarshallingException;
37 import org.opensaml.xml.io.Unmarshaller;
38 import org.opensaml.xml.io.UnmarshallerFactory;
39 import org.opensaml.xml.io.UnmarshallingException;
40 import org.opensaml.xml.security.SecurityException;
41 import org.opensaml.xml.security.SecurityHelper;
42 import org.opensaml.xml.security.keyinfo.KeyInfoGenerator;
43 import org.opensaml.xml.signature.DigestMethod;
44 import org.opensaml.xml.signature.KeyInfo;
45 import org.opensaml.xml.signature.SignatureConstants;
46 import org.opensaml.xml.signature.XMLSignatureBuilder;
47 import org.opensaml.xml.util.DatatypeHelper;
48 import org.opensaml.xml.util.XMLConstants;
49 import org.opensaml.xml.util.XMLHelper;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52 import org.w3c.dom.Document;
53 import org.w3c.dom.Element;
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85 public class Encrypter {
86
87
88 private final Logger log = LoggerFactory.getLogger(Encrypter.class);
89
90
91 private Unmarshaller encryptedDataUnmarshaller;
92
93
94 private Unmarshaller encryptedKeyUnmarshaller;
95
96
97 private XMLSignatureBuilder<KeyInfo> keyInfoBuilder;
98
99
100 private String jcaProviderName;
101
102
103
104
105
106 public Encrypter() {
107 UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
108 encryptedDataUnmarshaller = unmarshallerFactory.getUnmarshaller(EncryptedData.DEFAULT_ELEMENT_NAME);
109 encryptedKeyUnmarshaller = unmarshallerFactory.getUnmarshaller(EncryptedKey.DEFAULT_ELEMENT_NAME);
110
111 XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory();
112 keyInfoBuilder = (XMLSignatureBuilder<KeyInfo>) builderFactory.getBuilder(KeyInfo.DEFAULT_ELEMENT_NAME);
113
114 jcaProviderName = null;
115 }
116
117
118
119
120
121
122
123
124
125
126 public String getJCAProviderName() {
127 return jcaProviderName;
128 }
129
130
131
132
133
134
135
136
137
138
139 public void setJCAProviderName(String providerName) {
140 jcaProviderName = providerName;
141 }
142
143
144
145
146
147
148
149
150
151
152 public EncryptedData encryptElement(XMLObject xmlObject, EncryptionParameters encParams)
153 throws EncryptionException {
154 List<KeyEncryptionParameters> emptyKEKParamsList = new ArrayList<KeyEncryptionParameters>();
155 return encryptElement(xmlObject, encParams, emptyKEKParamsList, false);
156 }
157
158
159
160
161
162
163
164
165
166
167
168
169 public EncryptedData encryptElement(XMLObject xmlObject, EncryptionParameters encParams,
170 KeyEncryptionParameters kekParams) throws EncryptionException {
171 List<KeyEncryptionParameters> kekParamsList = new ArrayList<KeyEncryptionParameters>();
172 kekParamsList.add(kekParams);
173 return encryptElement(xmlObject, encParams, kekParamsList, false);
174 }
175
176
177
178
179
180
181
182
183
184
185
186
187 public EncryptedData encryptElement(XMLObject xmlObject, EncryptionParameters encParams,
188 List<KeyEncryptionParameters> kekParamsList) throws EncryptionException {
189 return encryptElement(xmlObject, encParams, kekParamsList, false);
190 }
191
192
193
194
195
196
197
198
199
200
201 public EncryptedData encryptElementContent(XMLObject xmlObject, EncryptionParameters encParams)
202 throws EncryptionException {
203 List<KeyEncryptionParameters> emptyKEKParamsList = new ArrayList<KeyEncryptionParameters>();
204 return encryptElement(xmlObject, encParams, emptyKEKParamsList, true);
205 }
206
207
208
209
210
211
212
213
214
215
216
217
218 public EncryptedData encryptElementContent(XMLObject xmlObject, EncryptionParameters encParams,
219 KeyEncryptionParameters kekParams) throws EncryptionException {
220 List<KeyEncryptionParameters> kekParamsList = new ArrayList<KeyEncryptionParameters>();
221 kekParamsList.add(kekParams);
222 return encryptElement(xmlObject, encParams, kekParamsList, true);
223 }
224
225
226
227
228
229
230
231
232
233
234
235
236 public EncryptedData encryptElementContent(XMLObject xmlObject, EncryptionParameters encParams,
237 List<KeyEncryptionParameters> kekParamsList) throws EncryptionException {
238 return encryptElement(xmlObject, encParams, kekParamsList, true);
239 }
240
241
242
243
244
245
246
247
248
249
250
251
252
253 public List<EncryptedKey> encryptKey(Key key, List<KeyEncryptionParameters> kekParamsList,
254 Document containingDocument) throws EncryptionException {
255
256 checkParams(kekParamsList, false);
257
258 List<EncryptedKey> encKeys = new ArrayList<EncryptedKey>();
259
260 for (KeyEncryptionParameters kekParam : kekParamsList) {
261 encKeys.add(encryptKey(key, kekParam, containingDocument));
262 }
263 return encKeys;
264 }
265
266
267
268
269
270
271
272
273
274
275
276
277 public EncryptedKey encryptKey(Key key, KeyEncryptionParameters kekParams, Document containingDocument)
278 throws EncryptionException {
279
280 checkParams(kekParams, false);
281
282 Key encryptionKey = SecurityHelper.extractEncryptionKey(kekParams.getEncryptionCredential());
283 String encryptionAlgorithmURI = kekParams.getAlgorithm();
284
285 EncryptedKey encryptedKey = encryptKey(key, encryptionKey, encryptionAlgorithmURI, containingDocument);
286
287 if (kekParams.getKeyInfoGenerator() != null) {
288 KeyInfoGenerator generator = kekParams.getKeyInfoGenerator();
289 log.debug("Dynamically generating KeyInfo from Credential for EncryptedKey using generator: {}",
290 generator.getClass().getName());
291 try {
292 encryptedKey.setKeyInfo(generator.generate(kekParams.getEncryptionCredential()));
293 } catch (SecurityException e) {
294 log.error("Error during EncryptedKey KeyInfo generation", e);
295 throw new EncryptionException("Error during EncryptedKey KeyInfo generation", e);
296 }
297 }
298
299 if (kekParams.getRecipient() != null) {
300 encryptedKey.setRecipient(kekParams.getRecipient());
301 }
302
303 return encryptedKey;
304 }
305
306
307
308
309
310
311
312
313
314
315
316 protected EncryptedKey encryptKey(Key targetKey, Key encryptionKey, String encryptionAlgorithmURI,
317 Document containingDocument) throws EncryptionException {
318
319 if (targetKey == null) {
320 log.error("Target key for key encryption was null");
321 throw new EncryptionException("Target key was null");
322 }
323 if (encryptionKey == null) {
324 log.error("Encryption key for key encryption was null");
325 throw new EncryptionException("Encryption key was null");
326 }
327
328 log.debug("Encrypting encryption key with algorithm: {}", encryptionAlgorithmURI);
329 XMLCipher xmlCipher;
330 try {
331 if (getJCAProviderName() != null) {
332 xmlCipher = XMLCipher.getProviderInstance(encryptionAlgorithmURI, getJCAProviderName());
333 } else {
334 xmlCipher = XMLCipher.getInstance(encryptionAlgorithmURI);
335 }
336 xmlCipher.init(XMLCipher.WRAP_MODE, encryptionKey);
337 } catch (XMLEncryptionException e) {
338 log.error("Error initializing cipher instance on key encryption", e);
339 throw new EncryptionException("Error initializing cipher instance on key encryption", e);
340 }
341
342 org.apache.xml.security.encryption.EncryptedKey apacheEncryptedKey;
343 try {
344 apacheEncryptedKey = xmlCipher.encryptKey(containingDocument, targetKey);
345 postProcessApacheEncryptedKey(apacheEncryptedKey, targetKey, encryptionKey,
346 encryptionAlgorithmURI, containingDocument);
347 } catch (XMLEncryptionException e) {
348 log.error("Error encrypting element on key encryption", e);
349 throw new EncryptionException("Error encrypting element on key encryption", e);
350 }
351
352 EncryptedKey encryptedKey;
353 try {
354 Element encKeyElement = xmlCipher.martial(containingDocument, apacheEncryptedKey);
355 encryptedKey = (EncryptedKey) encryptedKeyUnmarshaller.unmarshall(encKeyElement);
356 } catch (UnmarshallingException e) {
357 log.error("Error unmarshalling EncryptedKey element", e);
358 throw new EncryptionException("Error unmarshalling EncryptedKey element");
359 }
360
361 return encryptedKey;
362 }
363
364
365
366
367
368
369
370
371
372
373
374
375
376 protected void postProcessApacheEncryptedKey(org.apache.xml.security.encryption.EncryptedKey apacheEncryptedKey,
377 Key targetKey, Key encryptionKey, String encryptionAlgorithmURI, Document containingDocument)
378 throws EncryptionException {
379
380
381
382
383 if (EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP.equals(encryptionAlgorithmURI)) {
384 boolean sawDigestMethod = false;
385 Iterator childIter = apacheEncryptedKey.getEncryptionMethod().getEncryptionMethodInformation();
386 while (childIter.hasNext()) {
387 Element child = (Element) childIter.next();
388 if (DigestMethod.DEFAULT_ELEMENT_NAME.equals(XMLHelper.getNodeQName(child))) {
389 sawDigestMethod = true;
390 break;
391 }
392 }
393 if (! sawDigestMethod) {
394 Element digestMethodElem = XMLHelper.constructElement(containingDocument,
395 DigestMethod.DEFAULT_ELEMENT_NAME);
396 XMLHelper.appendNamespaceDeclaration(digestMethodElem,
397 XMLConstants.XMLSIG_NS, XMLConstants.XMLSIG_PREFIX);
398 digestMethodElem.setAttributeNS(null, DigestMethod.ALGORITHM_ATTRIB_NAME,
399 SignatureConstants.ALGO_ID_DIGEST_SHA1);
400 apacheEncryptedKey.getEncryptionMethod().addEncryptionMethodInformation(digestMethodElem);
401 }
402 }
403
404 }
405
406
407
408
409
410
411
412
413
414
415
416 protected EncryptedData encryptElement(XMLObject xmlObject, Key encryptionKey, String encryptionAlgorithmURI,
417 boolean encryptContentMode) throws EncryptionException {
418
419 if (xmlObject == null) {
420 log.error("XMLObject for encryption was null");
421 throw new EncryptionException("XMLObject was null");
422 }
423 if (encryptionKey == null) {
424 log.error("Encryption key for key encryption was null");
425 throw new EncryptionException("Encryption key was null");
426 }
427 log.debug("Encrypting XMLObject using algorithm URI {} with content mode {}", encryptionAlgorithmURI,
428 encryptContentMode);
429
430 checkAndMarshall(xmlObject);
431
432 Element targetElement = xmlObject.getDOM();
433 Document ownerDocument = targetElement.getOwnerDocument();
434
435 XMLCipher xmlCipher;
436 try {
437 if (getJCAProviderName() != null) {
438 xmlCipher = XMLCipher.getProviderInstance(encryptionAlgorithmURI, getJCAProviderName());
439 } else {
440 xmlCipher = XMLCipher.getInstance(encryptionAlgorithmURI);
441 }
442 xmlCipher.init(XMLCipher.ENCRYPT_MODE, encryptionKey);
443 } catch (XMLEncryptionException e) {
444 log.error("Error initializing cipher instance on XMLObject encryption", e);
445 throw new EncryptionException("Error initializing cipher instance", e);
446 }
447
448 org.apache.xml.security.encryption.EncryptedData apacheEncryptedData;
449 try {
450 apacheEncryptedData = xmlCipher.encryptData(ownerDocument, targetElement, encryptContentMode);
451 } catch (Exception e) {
452 log.error("Error encrypting XMLObject", e);
453 throw new EncryptionException("Error encrypting XMLObject", e);
454 }
455
456 EncryptedData encryptedData;
457 try {
458 Element encDataElement = xmlCipher.martial(ownerDocument, apacheEncryptedData);
459 encryptedData = (EncryptedData) encryptedDataUnmarshaller.unmarshall(encDataElement);
460 } catch (UnmarshallingException e) {
461 log.error("Error unmarshalling EncryptedData element", e);
462 throw new EncryptionException("Error unmarshalling EncryptedData element", e);
463 }
464
465 return encryptedData;
466 }
467
468
469
470
471
472
473
474
475
476
477
478
479
480 private EncryptedData encryptElement(XMLObject xmlObject, EncryptionParameters encParams,
481 List<KeyEncryptionParameters> kekParamsList, boolean encryptContentMode) throws EncryptionException {
482
483 checkParams(encParams, kekParamsList);
484
485 String encryptionAlgorithmURI = encParams.getAlgorithm();
486 Key encryptionKey = SecurityHelper.extractEncryptionKey(encParams.getEncryptionCredential());
487 if (encryptionKey == null) {
488 encryptionKey = generateEncryptionKey(encryptionAlgorithmURI);
489 }
490
491 EncryptedData encryptedData = encryptElement(xmlObject, encryptionKey, encryptionAlgorithmURI,
492 encryptContentMode);
493 Document ownerDocument = encryptedData.getDOM().getOwnerDocument();
494
495 if (encParams.getKeyInfoGenerator() != null) {
496 KeyInfoGenerator generator = encParams.getKeyInfoGenerator();
497 log.debug("Dynamically generating KeyInfo from Credential for EncryptedData using generator: {}",
498 generator.getClass().getName());
499 try {
500 encryptedData.setKeyInfo(generator.generate(encParams.getEncryptionCredential()));
501 } catch (SecurityException e) {
502 log.error("Error during EncryptedData KeyInfo generation", e);
503 throw new EncryptionException("Error during EncryptedData KeyInfo generation", e);
504 }
505 }
506
507 for (KeyEncryptionParameters kekParams : kekParamsList) {
508 EncryptedKey encryptedKey = encryptKey(encryptionKey, kekParams, ownerDocument);
509 if (encryptedData.getKeyInfo() == null) {
510 KeyInfo keyInfo = keyInfoBuilder.buildObject();
511 encryptedData.setKeyInfo(keyInfo);
512 }
513 encryptedData.getKeyInfo().getEncryptedKeys().add(encryptedKey);
514 }
515
516 return encryptedData;
517 }
518
519
520
521
522
523
524
525 protected void checkAndMarshall(XMLObject xmlObject) throws EncryptionException {
526 Element targetElement = xmlObject.getDOM();
527 if (targetElement == null) {
528 Marshaller marshaller = Configuration.getMarshallerFactory().getMarshaller(xmlObject);
529 try {
530 targetElement = marshaller.marshall(xmlObject);
531 } catch (MarshallingException e) {
532 log.error("Error marshalling target XMLObject", e);
533 throw new EncryptionException("Error marshalling target XMLObject", e);
534 }
535 }
536 }
537
538
539
540
541
542
543
544
545 protected void checkParams(EncryptionParameters encParams) throws EncryptionException {
546 if (encParams == null) {
547 log.error("Data encryption parameters are required");
548 throw new EncryptionException("Data encryption parameters are required");
549 }
550 if (DatatypeHelper.isEmpty(encParams.getAlgorithm())) {
551 log.error("Data encryption algorithm URI is required");
552 throw new EncryptionException("Data encryption algorithm URI is required");
553 }
554 }
555
556
557
558
559
560
561
562
563
564 protected void checkParams(KeyEncryptionParameters kekParams, boolean allowEmpty) throws EncryptionException {
565 if (kekParams == null) {
566 if (allowEmpty) {
567 return;
568 } else {
569 log.error("Key encryption parameters are required");
570 throw new EncryptionException("Key encryption parameters are required");
571 }
572 }
573 Key key = SecurityHelper.extractEncryptionKey(kekParams.getEncryptionCredential());
574 if (key == null) {
575 log.error("Key encryption credential and contained key are required");
576 throw new EncryptionException("Key encryption credential and contained key are required");
577 }
578 if (key instanceof DSAPublicKey) {
579 log.error("Attempt made to use DSA key for encrypted key transport");
580 throw new EncryptionException("DSA keys may not be used for encrypted key transport");
581 }
582 if (DatatypeHelper.isEmpty(kekParams.getAlgorithm())) {
583 log.error("Key encryption algorithm URI is required");
584 throw new EncryptionException("Key encryption algorithm URI is required");
585 }
586 }
587
588
589
590
591
592
593
594
595
596 protected void checkParams(List<KeyEncryptionParameters> kekParamsList, boolean allowEmpty)
597 throws EncryptionException {
598 if (kekParamsList == null || kekParamsList.isEmpty()) {
599 if (allowEmpty) {
600 return;
601 } else {
602 log.error("Key encryption parameters list may not be empty");
603 throw new EncryptionException("Key encryption parameters list may not be empty");
604 }
605 }
606 for (KeyEncryptionParameters kekParams : kekParamsList) {
607 checkParams(kekParams, false);
608 }
609 }
610
611
612
613
614
615
616
617
618 protected void checkParams(EncryptionParameters encParams, List<KeyEncryptionParameters> kekParamsList)
619 throws EncryptionException {
620
621 checkParams(encParams);
622 checkParams(kekParamsList, true);
623
624 if (SecurityHelper.extractEncryptionKey(encParams.getEncryptionCredential()) == null
625 && (kekParamsList == null || kekParamsList.isEmpty())) {
626 log.error("Using a generated encryption key requires a KeyEncryptionParameters "
627 + "object and key encryption key");
628 throw new EncryptionException("Using a generated encryption key requires a KeyEncryptionParameters "
629 + "object and key encryption key");
630 }
631 }
632
633
634
635
636
637
638
639
640 protected SecretKey generateEncryptionKey(String encryptionAlgorithmURI) throws EncryptionException {
641 try {
642 log.debug("Generating random symmetric data encryption key from algorithm URI: {}",
643 encryptionAlgorithmURI);
644 return SecurityHelper.generateSymmetricKey(encryptionAlgorithmURI);
645 } catch (NoSuchAlgorithmException e) {
646 log.error("Could not generate encryption key, algorithm URI was invalid: " + encryptionAlgorithmURI);
647 throw new EncryptionException("Could not generate encryption key, algorithm URI was invalid: "
648 + encryptionAlgorithmURI);
649 } catch (KeyException e) {
650 log.error("Could not generate encryption key from algorithm URI: " + encryptionAlgorithmURI);
651 throw new EncryptionException("Could not generate encryption key from algorithm URI: "
652 + encryptionAlgorithmURI);
653 }
654 }
655
656
657
658
659 static {
660 if (!Init.isInitialized()) {
661 Init.init();
662 }
663 }
664
665 }