2 * Licensed to the University Corporation for Advanced Internet
3 * Development, Inc. (UCAID) under one or more contributor license
4 * agreements. See the NOTICE file distributed with this work for
5 * additional information regarding copyright ownership.
7 * UCAID licenses this file to you under the Apache License,
8 * Version 2.0 (the "License"); you may not use this file except
9 * in compliance with the License. You may obtain a copy of the
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17 * either express or implied. See the License for the specific
18 * language governing permissions and limitations under the License.
24 * Methods for encrypting XMLObjects and other data.
28 #include "encryption/Encrypter.h"
29 #include "encryption/Encryption.h"
30 #include "security/Credential.h"
31 #include "signature/KeyInfo.h"
33 #include <xsec/enc/XSECCryptoException.hpp>
34 #include <xsec/framework/XSECException.hpp>
35 #include <xsec/framework/XSECAlgorithmMapper.hpp>
36 #include <xsec/framework/XSECAlgorithmHandler.hpp>
37 #include <xsec/xenc/XENCCipher.hpp>
38 #include <xsec/xenc/XENCEncryptedData.hpp>
39 #include <xsec/xenc/XENCEncryptedKey.hpp>
41 using namespace xmlencryption;
42 using namespace xmlsignature;
43 using namespace xmltooling;
44 using namespace xercesc;
47 Encrypter::EncryptionParams::EncryptionParams(
48 const XMLCh* algorithm, const unsigned char* keyBuffer, unsigned int keyBufferSize, const Credential* credential, bool compact
49 ) : m_algorithm(algorithm), m_keyBuffer(keyBuffer), m_keyBufferSize(keyBufferSize), m_credential(credential), m_compact(compact)
53 Encrypter::EncryptionParams::~EncryptionParams()
57 Encrypter::KeyEncryptionParams::KeyEncryptionParams(const Credential& credential, const XMLCh* algorithm, const XMLCh* recipient)
58 : m_credential(credential), m_algorithm(algorithm), m_recipient(recipient)
62 Encrypter::KeyEncryptionParams::~KeyEncryptionParams()
66 Encrypter::Encrypter() : m_cipher(nullptr)
70 Encrypter::~Encrypter()
72 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
73 memset(m_keyBuffer,0,32);
76 void Encrypter::checkParams(EncryptionParams& encParams, KeyEncryptionParams* kencParams)
78 if (encParams.m_keyBufferSize==0) {
79 if (encParams.m_credential) {
81 throw EncryptionException("Generating EncryptedKey inline requires the encryption key in raw form.");
85 throw EncryptionException("Using a generated encryption key requires a KeyEncryptionParams object.");
87 // We're generating a random key. The maximum supported length is AES-256, so we need 32 bytes.
88 if (XSECPlatformUtils::g_cryptoProvider->getRandom(m_keyBuffer,32)<32)
89 throw EncryptionException("Unable to generate random data; was PRNG seeded?");
90 encParams.m_keyBuffer=m_keyBuffer;
91 encParams.m_keyBufferSize=32;
95 XSECCryptoKey* key=nullptr;
96 if (encParams.m_credential) {
97 key = encParams.m_credential->getPrivateKey();
99 throw EncryptionException("Credential in EncryptionParams structure did not supply a private/secret key.");
100 // Set the encryption key.
101 m_cipher->setKey(key->clone());
104 // We have to have a raw key now, so we need to build a wrapper around it.
105 XSECAlgorithmHandler* handler =XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(encParams.m_algorithm);
106 if (handler != nullptr)
107 key = handler->createKeyForURI(
108 encParams.m_algorithm,const_cast<unsigned char*>(encParams.m_keyBuffer),encParams.m_keyBufferSize
112 throw EncryptionException("Unable to build wrapper for key, unknown algorithm?");
113 // Overwrite the length if known.
114 switch (static_cast<XSECCryptoSymmetricKey*>(key)->getSymmetricKeyType()) {
115 case XSECCryptoSymmetricKey::KEY_3DES_192:
116 encParams.m_keyBufferSize = 192/8;
118 case XSECCryptoSymmetricKey::KEY_AES_128:
119 encParams.m_keyBufferSize = 128/8;
121 case XSECCryptoSymmetricKey::KEY_AES_192:
122 encParams.m_keyBufferSize = 192/8;
124 case XSECCryptoSymmetricKey::KEY_AES_256:
125 encParams.m_keyBufferSize = 256/8;
128 // Set the encryption key.
129 m_cipher->setKey(key);
133 EncryptedData* Encrypter::encryptElement(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
135 // We can reuse the cipher object if the document hasn't changed.
137 if (m_cipher && m_cipher->getDocument()!=element->getOwnerDocument()) {
138 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
143 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(element->getOwnerDocument());
144 m_cipher->setExclusiveC14nSerialisation(false);
148 checkParams(encParams,kencParams);
149 m_cipher->encryptElementDetached(element, ENCRYPT_NONE, encParams.m_algorithm);
150 return decorateAndUnmarshall(encParams, kencParams);
152 catch(XSECException& e) {
153 auto_ptr_char temp(e.getMsg());
154 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
156 catch(XSECCryptoException& e) {
157 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
161 EncryptedData* Encrypter::encryptElementContent(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
163 // We can reuse the cipher object if the document hasn't changed.
165 if (m_cipher && m_cipher->getDocument()!=element->getOwnerDocument()) {
166 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
171 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(element->getOwnerDocument());
172 m_cipher->setExclusiveC14nSerialisation(false);
176 checkParams(encParams,kencParams);
177 m_cipher->encryptElementContentDetached(element, ENCRYPT_NONE, encParams.m_algorithm);
178 return decorateAndUnmarshall(encParams, kencParams);
180 catch(XSECException& e) {
181 auto_ptr_char temp(e.getMsg());
182 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
184 catch(XSECCryptoException& e) {
185 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
189 EncryptedData* Encrypter::encryptStream(istream& input, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
191 // Get a fresh cipher object and document.
194 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
198 DOMDocument* doc=nullptr;
200 doc=XMLToolingConfig::getConfig().getParser().newDocument();
201 XercesJanitor<DOMDocument> janitor(doc);
202 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(doc);
203 m_cipher->setExclusiveC14nSerialisation(false);
205 checkParams(encParams,kencParams);
206 StreamInputSource::StreamBinInputStream xstream(input);
207 m_cipher->encryptBinInputStream(&xstream, ENCRYPT_NONE, encParams.m_algorithm);
208 return decorateAndUnmarshall(encParams, kencParams);
210 catch(XSECException& e) {
211 auto_ptr_char temp(e.getMsg());
212 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
214 catch(XSECCryptoException& e) {
215 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
219 EncryptedData* Encrypter::decorateAndUnmarshall(EncryptionParams& encParams, KeyEncryptionParams* kencParams)
221 XENCEncryptedData* encData=m_cipher->getEncryptedData();
223 throw EncryptionException("No EncryptedData element found?");
225 // Unmarshall a tooling version of EncryptedData around the DOM.
226 EncryptedData* xmlEncData=nullptr;
227 auto_ptr<XMLObject> xmlObject(XMLObjectBuilder::buildOneFromElement(encData->getElement()));
228 if (!(xmlObject.get()) || !(xmlEncData=dynamic_cast<EncryptedData*>(xmlObject.get())))
229 throw EncryptionException("Unable to unmarshall into EncryptedData object.");
231 // Unbind from DOM so we can divorce this from the original document.
232 xmlEncData->releaseThisAndChildrenDOM();
235 KeyInfo* kinfo = encParams.m_credential ? encParams.m_credential->getKeyInfo(encParams.m_compact) : nullptr;
237 xmlEncData->setKeyInfo(kinfo);
239 // Are we doing a key encryption?
241 XSECCryptoKey* kek = kencParams->m_credential.getPublicKey();
243 throw EncryptionException("Credential in KeyEncryptionParams structure did not supply a public key.");
244 if (!kencParams->m_algorithm)
245 kencParams->m_algorithm = getKeyTransportAlgorithm(kencParams->m_credential, encParams.m_algorithm);
246 if (!kencParams->m_algorithm)
247 throw EncryptionException("Unable to derive a supported key encryption algorithm.");
249 m_cipher->setKEK(kek->clone());
250 // ownership of this belongs to us, for some reason...
251 auto_ptr<XENCEncryptedKey> encKey(
252 m_cipher->encryptKey(encParams.m_keyBuffer, encParams.m_keyBufferSize, ENCRYPT_NONE, kencParams->m_algorithm)
254 EncryptedKey* xmlEncKey=nullptr;
255 auto_ptr<XMLObject> xmlObjectKey(XMLObjectBuilder::buildOneFromElement(encKey->getElement()));
256 if (!(xmlObjectKey.get()) || !(xmlEncKey=dynamic_cast<EncryptedKey*>(xmlObjectKey.get())))
257 throw EncryptionException("Unable to unmarshall into EncryptedKey object.");
259 xmlEncKey->releaseThisAndChildrenDOM();
262 if (kencParams->m_recipient)
263 xmlEncKey->setRecipient(kencParams->m_recipient);
266 kinfo = kencParams->m_credential.getKeyInfo(encParams.m_compact);
268 xmlEncKey->setKeyInfo(kinfo);
270 // Add the EncryptedKey inline.
271 if (!xmlEncData->getKeyInfo())
272 xmlEncData->setKeyInfo(KeyInfoBuilder::buildKeyInfo());
273 xmlEncData->getKeyInfo()->getUnknownXMLObjects().push_back(xmlEncKey);
274 xmlObjectKey.release();
281 EncryptedKey* Encrypter::encryptKey(
282 const unsigned char* keyBuffer, unsigned int keyBufferSize, KeyEncryptionParams& kencParams, bool compact
285 if (!kencParams.m_algorithm)
286 throw EncryptionException("KeyEncryptionParams structure did not include a key encryption algorithm.");
288 // Get a fresh cipher object and document.
291 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
295 XSECCryptoKey* kek = kencParams.m_credential.getPublicKey();
297 throw EncryptionException("Credential in KeyEncryptionParams structure did not supply a public key.");
299 DOMDocument* doc=nullptr;
301 doc=XMLToolingConfig::getConfig().getParser().newDocument();
302 XercesJanitor<DOMDocument> janitor(doc);
303 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(doc);
304 m_cipher->setExclusiveC14nSerialisation(false);
305 m_cipher->setKEK(kek->clone());
306 auto_ptr<XENCEncryptedKey> encKey(m_cipher->encryptKey(keyBuffer, keyBufferSize, ENCRYPT_NONE, kencParams.m_algorithm));
308 EncryptedKey* xmlEncKey=nullptr;
309 auto_ptr<XMLObject> xmlObjectKey(XMLObjectBuilder::buildOneFromElement(encKey->getElement()));
310 if (!(xmlObjectKey.get()) || !(xmlEncKey=dynamic_cast<EncryptedKey*>(xmlObjectKey.get())))
311 throw EncryptionException("Unable to unmarshall into EncryptedKey object.");
313 xmlEncKey->releaseThisAndChildrenDOM();
316 if (kencParams.m_recipient)
317 xmlEncKey->setRecipient(kencParams.m_recipient);
320 KeyInfo* kinfo = kencParams.m_credential.getKeyInfo(compact);
322 xmlEncKey->setKeyInfo(kinfo);
324 xmlObjectKey.release();
327 catch(XSECException& e) {
328 auto_ptr_char temp(e.getMsg());
329 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
331 catch(XSECCryptoException& e) {
332 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
336 const XMLCh* Encrypter::getKeyTransportAlgorithm(const Credential& credential, const XMLCh* encryptionAlg)
338 XMLToolingConfig& conf = XMLToolingConfig::getConfig();
339 const char* alg = credential.getAlgorithm();
340 if (!alg || !strcmp(alg, "RSA")) {
341 if (XMLString::equals(encryptionAlg,DSIGConstants::s_unicodeStrURI3DES_CBC)) {
342 if (conf.isXMLAlgorithmSupported(DSIGConstants::s_unicodeStrURIRSA_1_5, XMLToolingConfig::ALGTYPE_KEYENCRYPT))
343 return DSIGConstants::s_unicodeStrURIRSA_1_5;
344 else if (conf.isXMLAlgorithmSupported(DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1, XMLToolingConfig::ALGTYPE_KEYENCRYPT))
345 return DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1;
348 if (conf.isXMLAlgorithmSupported(DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1, XMLToolingConfig::ALGTYPE_KEYENCRYPT))
349 return DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1;
350 else if (conf.isXMLAlgorithmSupported(DSIGConstants::s_unicodeStrURIRSA_1_5, XMLToolingConfig::ALGTYPE_KEYENCRYPT))
351 return DSIGConstants::s_unicodeStrURIRSA_1_5;
354 else if (!strcmp(alg, "AES")) {
355 const XMLCh* ret = nullptr;
356 switch (credential.getKeySize()) {
358 ret = DSIGConstants::s_unicodeStrURIKW_AES128;
360 ret = DSIGConstants::s_unicodeStrURIKW_AES192;
362 ret = DSIGConstants::s_unicodeStrURIKW_AES256;
366 if (conf.isXMLAlgorithmSupported(ret, XMLToolingConfig::ALGTYPE_KEYENCRYPT))
369 else if (!strcmp(alg, "DESede")) {
370 if (conf.isXMLAlgorithmSupported(DSIGConstants::s_unicodeStrURIKW_3DES, XMLToolingConfig::ALGTYPE_KEYENCRYPT))
371 return DSIGConstants::s_unicodeStrURIKW_3DES;