2 * Copyright 2001-2007 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 "security/Credential.h"
27 #include <xsec/enc/XSECCryptoException.hpp>
28 #include <xsec/framework/XSECException.hpp>
29 #include <xsec/framework/XSECAlgorithmMapper.hpp>
30 #include <xsec/framework/XSECAlgorithmHandler.hpp>
31 #include <xsec/xenc/XENCEncryptedData.hpp>
32 #include <xsec/xenc/XENCEncryptedKey.hpp>
34 using namespace xmlencryption;
35 using namespace xmlsignature;
36 using namespace xmltooling;
39 Encrypter::~Encrypter()
41 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
42 memset(m_keyBuffer,0,32);
45 void Encrypter::checkParams(EncryptionParams& encParams, KeyEncryptionParams* kencParams)
47 if (encParams.m_keyBufferSize==0) {
48 if (encParams.m_credential) {
50 throw EncryptionException("Generating EncryptedKey inline requires the encryption key in raw form.");
54 throw EncryptionException("Using a generated encryption key requires a KeyEncryptionParams object.");
56 // We're generating a random key. The maximum supported length is AES-256, so we need 32 bytes.
57 if (XSECPlatformUtils::g_cryptoProvider->getRandom(m_keyBuffer,32)<32)
58 throw EncryptionException("Unable to generate random data; was PRNG seeded?");
59 encParams.m_keyBuffer=m_keyBuffer;
60 encParams.m_keyBufferSize=32;
64 XSECCryptoKey* key=NULL;
65 if (encParams.m_credential) {
66 key = encParams.m_credential->getPrivateKey();
68 throw EncryptionException("Credential in EncryptionParams structure did not supply a private/secret key.");
69 // Set the encryption key.
70 m_cipher->setKey(key->clone());
73 // We have to have a raw key now, so we need to build a wrapper around it.
74 XSECAlgorithmHandler* handler =XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(encParams.m_algorithm);
76 key = handler->createKeyForURI(
77 encParams.m_algorithm,const_cast<unsigned char*>(encParams.m_keyBuffer),encParams.m_keyBufferSize
81 throw EncryptionException("Unable to build wrapper for key, unknown algorithm?");
82 // Overwrite the length if known.
83 switch (static_cast<XSECCryptoSymmetricKey*>(key)->getSymmetricKeyType()) {
84 case XSECCryptoSymmetricKey::KEY_3DES_192:
85 encParams.m_keyBufferSize = 192/8;
87 case XSECCryptoSymmetricKey::KEY_AES_128:
88 encParams.m_keyBufferSize = 128/8;
90 case XSECCryptoSymmetricKey::KEY_AES_192:
91 encParams.m_keyBufferSize = 192/8;
93 case XSECCryptoSymmetricKey::KEY_AES_256:
94 encParams.m_keyBufferSize = 256/8;
97 // Set the encryption key.
98 m_cipher->setKey(key);
102 EncryptedData* Encrypter::encryptElement(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
104 // We can reuse the cipher object if the document hasn't changed.
106 if (m_cipher && m_cipher->getDocument()!=element->getOwnerDocument()) {
107 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
112 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(element->getOwnerDocument());
113 m_cipher->setExclusiveC14nSerialisation(false);
117 checkParams(encParams,kencParams);
118 m_cipher->encryptElementDetached(element, ENCRYPT_NONE, encParams.m_algorithm);
119 return decorateAndUnmarshall(encParams, kencParams);
121 catch(XSECException& e) {
122 auto_ptr_char temp(e.getMsg());
123 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
125 catch(XSECCryptoException& e) {
126 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
130 EncryptedData* Encrypter::encryptElementContent(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
132 // We can reuse the cipher object if the document hasn't changed.
134 if (m_cipher && m_cipher->getDocument()!=element->getOwnerDocument()) {
135 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
140 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(element->getOwnerDocument());
141 m_cipher->setExclusiveC14nSerialisation(false);
145 checkParams(encParams,kencParams);
146 m_cipher->encryptElementContentDetached(element, ENCRYPT_NONE, encParams.m_algorithm);
147 return decorateAndUnmarshall(encParams, kencParams);
149 catch(XSECException& e) {
150 auto_ptr_char temp(e.getMsg());
151 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
153 catch(XSECCryptoException& e) {
154 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
158 EncryptedData* Encrypter::encryptStream(istream& input, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
160 // Get a fresh cipher object and document.
163 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
167 DOMDocument* doc=NULL;
169 doc=XMLToolingConfig::getConfig().getParser().newDocument();
170 XercesJanitor<DOMDocument> janitor(doc);
171 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(doc);
172 m_cipher->setExclusiveC14nSerialisation(false);
174 checkParams(encParams,kencParams);
175 StreamInputSource::StreamBinInputStream xstream(input);
176 m_cipher->encryptBinInputStream(&xstream, ENCRYPT_NONE, encParams.m_algorithm);
177 return decorateAndUnmarshall(encParams, kencParams);
179 catch(XSECException& e) {
180 auto_ptr_char temp(e.getMsg());
181 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
183 catch(XSECCryptoException& e) {
184 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
188 EncryptedData* Encrypter::decorateAndUnmarshall(EncryptionParams& encParams, KeyEncryptionParams* kencParams)
190 XENCEncryptedData* encData=m_cipher->getEncryptedData();
192 throw EncryptionException("No EncryptedData element found?");
194 // Unmarshall a tooling version of EncryptedData around the DOM.
195 EncryptedData* xmlEncData=NULL;
196 auto_ptr<XMLObject> xmlObject(XMLObjectBuilder::buildOneFromElement(encData->getElement()));
197 if (!(xmlObject.get()) || !(xmlEncData=dynamic_cast<EncryptedData*>(xmlObject.get())))
198 throw EncryptionException("Unable to unmarshall into EncryptedData object.");
200 // Unbind from DOM so we can divorce this from the original document.
201 xmlEncData->releaseThisAndChildrenDOM();
204 KeyInfo* kinfo = encParams.m_credential ? encParams.m_credential->getKeyInfo(encParams.m_compact) : NULL;
206 xmlEncData->setKeyInfo(kinfo);
208 // Are we doing a key encryption?
210 XSECCryptoKey* kek = kencParams->m_credential.getPublicKey();
212 throw EncryptionException("Credential in KeyEncryptionParams structure did not supply a public key.");
213 if (!kencParams->m_algorithm)
214 kencParams->m_algorithm = getKeyTransportAlgorithm(kencParams->m_credential, encParams.m_algorithm);
216 m_cipher->setKEK(kek->clone());
217 // ownership of this belongs to us, for some reason...
218 auto_ptr<XENCEncryptedKey> encKey(
219 m_cipher->encryptKey(encParams.m_keyBuffer, encParams.m_keyBufferSize, ENCRYPT_NONE, kencParams->m_algorithm)
221 EncryptedKey* xmlEncKey=NULL;
222 auto_ptr<XMLObject> xmlObjectKey(XMLObjectBuilder::buildOneFromElement(encKey->getElement()));
223 if (!(xmlObjectKey.get()) || !(xmlEncKey=dynamic_cast<EncryptedKey*>(xmlObjectKey.get())))
224 throw EncryptionException("Unable to unmarshall into EncryptedKey object.");
226 xmlEncKey->releaseThisAndChildrenDOM();
229 if (kencParams->m_recipient)
230 xmlEncKey->setRecipient(kencParams->m_recipient);
233 kinfo = kencParams->m_credential.getKeyInfo(encParams.m_compact);
235 xmlEncKey->setKeyInfo(kinfo);
237 // Add the EncryptedKey inline.
238 if (!xmlEncData->getKeyInfo())
239 xmlEncData->setKeyInfo(KeyInfoBuilder::buildKeyInfo());
240 xmlEncData->getKeyInfo()->getUnknownXMLObjects().push_back(xmlEncKey);
241 xmlObjectKey.release();
248 EncryptedKey* Encrypter::encryptKey(
249 const unsigned char* keyBuffer, unsigned int keyBufferSize, KeyEncryptionParams& kencParams, bool compact
252 // Get a fresh cipher object and document.
255 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
259 XSECCryptoKey* kek = kencParams.m_credential.getPublicKey();
261 throw EncryptionException("Credential in KeyEncryptionParams structure did not supply a public key.");
263 DOMDocument* doc=NULL;
265 doc=XMLToolingConfig::getConfig().getParser().newDocument();
266 XercesJanitor<DOMDocument> janitor(doc);
267 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(doc);
268 m_cipher->setExclusiveC14nSerialisation(false);
269 m_cipher->setKEK(kek->clone());
270 auto_ptr<XENCEncryptedKey> encKey(m_cipher->encryptKey(keyBuffer, keyBufferSize, ENCRYPT_NONE, kencParams.m_algorithm));
272 EncryptedKey* xmlEncKey=NULL;
273 auto_ptr<XMLObject> xmlObjectKey(XMLObjectBuilder::buildOneFromElement(encKey->getElement()));
274 if (!(xmlObjectKey.get()) || !(xmlEncKey=dynamic_cast<EncryptedKey*>(xmlObjectKey.get())))
275 throw EncryptionException("Unable to unmarshall into EncryptedKey object.");
277 xmlEncKey->releaseThisAndChildrenDOM();
280 if (kencParams.m_recipient)
281 xmlEncKey->setRecipient(kencParams.m_recipient);
284 KeyInfo* kinfo = kencParams.m_credential.getKeyInfo(compact);
286 xmlEncKey->setKeyInfo(kinfo);
288 xmlObjectKey.release();
291 catch(XSECException& e) {
292 auto_ptr_char temp(e.getMsg());
293 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
295 catch(XSECCryptoException& e) {
296 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
300 const XMLCh* Encrypter::getKeyTransportAlgorithm(const Credential& credential, const XMLCh* encryptionAlg)
302 const char* alg = credential.getAlgorithm();
303 if (!alg || !strcmp(alg, "RSA")) {
304 if (XMLString::equals(encryptionAlg,DSIGConstants::s_unicodeStrURI3DES_CBC))
305 return DSIGConstants::s_unicodeStrURIRSA_1_5;
307 return DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1;
309 else if (!strcmp(alg, "AES")) {
310 switch (credential.getKeySize()) {
312 return DSIGConstants::s_unicodeStrURIKW_AES128;
314 return DSIGConstants::s_unicodeStrURIKW_AES192;
316 return DSIGConstants::s_unicodeStrURIKW_AES256;
319 else if (!strcmp(alg, "DESede")) {
320 return DSIGConstants::s_unicodeStrURIKW_3DES;