2 * Copyright 2001-2010 Internet2
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 * Methods for encrypting XMLObjects and other data.
24 #include "encryption/Encrypter.h"
25 #include "encryption/Encryption.h"
26 #include "security/Credential.h"
27 #include "signature/KeyInfo.h"
29 #include <xsec/enc/XSECCryptoException.hpp>
30 #include <xsec/framework/XSECException.hpp>
31 #include <xsec/framework/XSECAlgorithmMapper.hpp>
32 #include <xsec/framework/XSECAlgorithmHandler.hpp>
33 #include <xsec/xenc/XENCCipher.hpp>
34 #include <xsec/xenc/XENCEncryptedData.hpp>
35 #include <xsec/xenc/XENCEncryptedKey.hpp>
37 using namespace xmlencryption;
38 using namespace xmlsignature;
39 using namespace xmltooling;
40 using namespace xercesc;
43 Encrypter::EncryptionParams::EncryptionParams(
44 const XMLCh* algorithm, const unsigned char* keyBuffer, unsigned int keyBufferSize, const Credential* credential, bool compact
45 ) : m_algorithm(algorithm), m_keyBuffer(keyBuffer), m_keyBufferSize(keyBufferSize), m_credential(credential), m_compact(compact)
49 Encrypter::EncryptionParams::~EncryptionParams()
53 Encrypter::KeyEncryptionParams::KeyEncryptionParams(const Credential& credential, const XMLCh* algorithm, const XMLCh* recipient)
54 : m_credential(credential), m_algorithm(algorithm), m_recipient(recipient)
58 Encrypter::KeyEncryptionParams::~KeyEncryptionParams()
62 Encrypter::Encrypter() : m_cipher(nullptr)
66 Encrypter::~Encrypter()
68 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
69 memset(m_keyBuffer,0,32);
72 void Encrypter::checkParams(EncryptionParams& encParams, KeyEncryptionParams* kencParams)
74 if (encParams.m_keyBufferSize==0) {
75 if (encParams.m_credential) {
77 throw EncryptionException("Generating EncryptedKey inline requires the encryption key in raw form.");
81 throw EncryptionException("Using a generated encryption key requires a KeyEncryptionParams object.");
83 // We're generating a random key. The maximum supported length is AES-256, so we need 32 bytes.
84 if (XSECPlatformUtils::g_cryptoProvider->getRandom(m_keyBuffer,32)<32)
85 throw EncryptionException("Unable to generate random data; was PRNG seeded?");
86 encParams.m_keyBuffer=m_keyBuffer;
87 encParams.m_keyBufferSize=32;
91 XSECCryptoKey* key=nullptr;
92 if (encParams.m_credential) {
93 key = encParams.m_credential->getPrivateKey();
95 throw EncryptionException("Credential in EncryptionParams structure did not supply a private/secret key.");
96 // Set the encryption key.
97 m_cipher->setKey(key->clone());
100 // We have to have a raw key now, so we need to build a wrapper around it.
101 XSECAlgorithmHandler* handler =XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(encParams.m_algorithm);
102 if (handler != nullptr)
103 key = handler->createKeyForURI(
104 encParams.m_algorithm,const_cast<unsigned char*>(encParams.m_keyBuffer),encParams.m_keyBufferSize
108 throw EncryptionException("Unable to build wrapper for key, unknown algorithm?");
109 // Overwrite the length if known.
110 switch (static_cast<XSECCryptoSymmetricKey*>(key)->getSymmetricKeyType()) {
111 case XSECCryptoSymmetricKey::KEY_3DES_192:
112 encParams.m_keyBufferSize = 192/8;
114 case XSECCryptoSymmetricKey::KEY_AES_128:
115 encParams.m_keyBufferSize = 128/8;
117 case XSECCryptoSymmetricKey::KEY_AES_192:
118 encParams.m_keyBufferSize = 192/8;
120 case XSECCryptoSymmetricKey::KEY_AES_256:
121 encParams.m_keyBufferSize = 256/8;
124 // Set the encryption key.
125 m_cipher->setKey(key);
129 EncryptedData* Encrypter::encryptElement(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
131 // We can reuse the cipher object if the document hasn't changed.
133 if (m_cipher && m_cipher->getDocument()!=element->getOwnerDocument()) {
134 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
139 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(element->getOwnerDocument());
140 m_cipher->setExclusiveC14nSerialisation(false);
144 checkParams(encParams,kencParams);
145 m_cipher->encryptElementDetached(element, ENCRYPT_NONE, encParams.m_algorithm);
146 return decorateAndUnmarshall(encParams, kencParams);
148 catch(XSECException& e) {
149 auto_ptr_char temp(e.getMsg());
150 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
152 catch(XSECCryptoException& e) {
153 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
157 EncryptedData* Encrypter::encryptElementContent(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
159 // We can reuse the cipher object if the document hasn't changed.
161 if (m_cipher && m_cipher->getDocument()!=element->getOwnerDocument()) {
162 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
167 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(element->getOwnerDocument());
168 m_cipher->setExclusiveC14nSerialisation(false);
172 checkParams(encParams,kencParams);
173 m_cipher->encryptElementContentDetached(element, ENCRYPT_NONE, encParams.m_algorithm);
174 return decorateAndUnmarshall(encParams, kencParams);
176 catch(XSECException& e) {
177 auto_ptr_char temp(e.getMsg());
178 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
180 catch(XSECCryptoException& e) {
181 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
185 EncryptedData* Encrypter::encryptStream(istream& input, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
187 // Get a fresh cipher object and document.
190 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
194 DOMDocument* doc=nullptr;
196 doc=XMLToolingConfig::getConfig().getParser().newDocument();
197 XercesJanitor<DOMDocument> janitor(doc);
198 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(doc);
199 m_cipher->setExclusiveC14nSerialisation(false);
201 checkParams(encParams,kencParams);
202 StreamInputSource::StreamBinInputStream xstream(input);
203 m_cipher->encryptBinInputStream(&xstream, ENCRYPT_NONE, encParams.m_algorithm);
204 return decorateAndUnmarshall(encParams, kencParams);
206 catch(XSECException& e) {
207 auto_ptr_char temp(e.getMsg());
208 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
210 catch(XSECCryptoException& e) {
211 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
215 EncryptedData* Encrypter::decorateAndUnmarshall(EncryptionParams& encParams, KeyEncryptionParams* kencParams)
217 XENCEncryptedData* encData=m_cipher->getEncryptedData();
219 throw EncryptionException("No EncryptedData element found?");
221 // Unmarshall a tooling version of EncryptedData around the DOM.
222 EncryptedData* xmlEncData=nullptr;
223 auto_ptr<XMLObject> xmlObject(XMLObjectBuilder::buildOneFromElement(encData->getElement()));
224 if (!(xmlObject.get()) || !(xmlEncData=dynamic_cast<EncryptedData*>(xmlObject.get())))
225 throw EncryptionException("Unable to unmarshall into EncryptedData object.");
227 // Unbind from DOM so we can divorce this from the original document.
228 xmlEncData->releaseThisAndChildrenDOM();
231 KeyInfo* kinfo = encParams.m_credential ? encParams.m_credential->getKeyInfo(encParams.m_compact) : nullptr;
233 xmlEncData->setKeyInfo(kinfo);
235 // Are we doing a key encryption?
237 XSECCryptoKey* kek = kencParams->m_credential.getPublicKey();
239 throw EncryptionException("Credential in KeyEncryptionParams structure did not supply a public key.");
240 if (!kencParams->m_algorithm)
241 kencParams->m_algorithm = getKeyTransportAlgorithm(kencParams->m_credential, encParams.m_algorithm);
242 if (!kencParams->m_algorithm)
243 throw EncryptionException("Unable to derive a supported key encryption algorithm.");
245 m_cipher->setKEK(kek->clone());
246 // ownership of this belongs to us, for some reason...
247 auto_ptr<XENCEncryptedKey> encKey(
248 m_cipher->encryptKey(encParams.m_keyBuffer, encParams.m_keyBufferSize, ENCRYPT_NONE, kencParams->m_algorithm)
250 EncryptedKey* xmlEncKey=nullptr;
251 auto_ptr<XMLObject> xmlObjectKey(XMLObjectBuilder::buildOneFromElement(encKey->getElement()));
252 if (!(xmlObjectKey.get()) || !(xmlEncKey=dynamic_cast<EncryptedKey*>(xmlObjectKey.get())))
253 throw EncryptionException("Unable to unmarshall into EncryptedKey object.");
255 xmlEncKey->releaseThisAndChildrenDOM();
258 if (kencParams->m_recipient)
259 xmlEncKey->setRecipient(kencParams->m_recipient);
262 kinfo = kencParams->m_credential.getKeyInfo(encParams.m_compact);
264 xmlEncKey->setKeyInfo(kinfo);
266 // Add the EncryptedKey inline.
267 if (!xmlEncData->getKeyInfo())
268 xmlEncData->setKeyInfo(KeyInfoBuilder::buildKeyInfo());
269 xmlEncData->getKeyInfo()->getUnknownXMLObjects().push_back(xmlEncKey);
270 xmlObjectKey.release();
277 EncryptedKey* Encrypter::encryptKey(
278 const unsigned char* keyBuffer, unsigned int keyBufferSize, KeyEncryptionParams& kencParams, bool compact
281 if (!kencParams.m_algorithm)
282 throw EncryptionException("KeyEncryptionParams structure did not include a key encryption algorithm.");
284 // Get a fresh cipher object and document.
287 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
291 XSECCryptoKey* kek = kencParams.m_credential.getPublicKey();
293 throw EncryptionException("Credential in KeyEncryptionParams structure did not supply a public key.");
295 DOMDocument* doc=nullptr;
297 doc=XMLToolingConfig::getConfig().getParser().newDocument();
298 XercesJanitor<DOMDocument> janitor(doc);
299 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(doc);
300 m_cipher->setExclusiveC14nSerialisation(false);
301 m_cipher->setKEK(kek->clone());
302 auto_ptr<XENCEncryptedKey> encKey(m_cipher->encryptKey(keyBuffer, keyBufferSize, ENCRYPT_NONE, kencParams.m_algorithm));
304 EncryptedKey* xmlEncKey=nullptr;
305 auto_ptr<XMLObject> xmlObjectKey(XMLObjectBuilder::buildOneFromElement(encKey->getElement()));
306 if (!(xmlObjectKey.get()) || !(xmlEncKey=dynamic_cast<EncryptedKey*>(xmlObjectKey.get())))
307 throw EncryptionException("Unable to unmarshall into EncryptedKey object.");
309 xmlEncKey->releaseThisAndChildrenDOM();
312 if (kencParams.m_recipient)
313 xmlEncKey->setRecipient(kencParams.m_recipient);
316 KeyInfo* kinfo = kencParams.m_credential.getKeyInfo(compact);
318 xmlEncKey->setKeyInfo(kinfo);
320 xmlObjectKey.release();
323 catch(XSECException& e) {
324 auto_ptr_char temp(e.getMsg());
325 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
327 catch(XSECCryptoException& e) {
328 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
332 const XMLCh* Encrypter::getKeyTransportAlgorithm(const Credential& credential, const XMLCh* encryptionAlg)
334 XMLToolingConfig& conf = XMLToolingConfig::getConfig();
335 const char* alg = credential.getAlgorithm();
336 if (!alg || !strcmp(alg, "RSA")) {
337 if (XMLString::equals(encryptionAlg,DSIGConstants::s_unicodeStrURI3DES_CBC)) {
338 if (conf.isXMLAlgorithmSupported(DSIGConstants::s_unicodeStrURIRSA_1_5, XMLToolingConfig::ALGTYPE_KEYENCRYPT))
339 return DSIGConstants::s_unicodeStrURIRSA_1_5;
340 else if (conf.isXMLAlgorithmSupported(DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1, XMLToolingConfig::ALGTYPE_KEYENCRYPT))
341 return DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1;
344 if (conf.isXMLAlgorithmSupported(DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1, XMLToolingConfig::ALGTYPE_KEYENCRYPT))
345 return DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1;
346 else if (conf.isXMLAlgorithmSupported(DSIGConstants::s_unicodeStrURIRSA_1_5, XMLToolingConfig::ALGTYPE_KEYENCRYPT))
347 return DSIGConstants::s_unicodeStrURIRSA_1_5;
350 else if (!strcmp(alg, "AES")) {
351 const XMLCh* ret = nullptr;
352 switch (credential.getKeySize()) {
354 ret = DSIGConstants::s_unicodeStrURIKW_AES128;
356 ret = DSIGConstants::s_unicodeStrURIKW_AES192;
358 ret = DSIGConstants::s_unicodeStrURIKW_AES256;
362 if (conf.isXMLAlgorithmSupported(ret, XMLToolingConfig::ALGTYPE_KEYENCRYPT))
365 else if (!strcmp(alg, "DESede")) {
366 if (conf.isXMLAlgorithmSupported(DSIGConstants::s_unicodeStrURIKW_3DES, XMLToolingConfig::ALGTYPE_KEYENCRYPT))
367 return DSIGConstants::s_unicodeStrURIKW_3DES;