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.");
52 else if (!encParams.m_credential) {
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 // Set the encryption key.
83 m_cipher->setKey(key);
87 EncryptedData* Encrypter::encryptElement(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
89 // We can reuse the cipher object if the document hasn't changed.
91 if (m_cipher && m_cipher->getDocument()!=element->getOwnerDocument()) {
92 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
97 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(element->getOwnerDocument());
98 m_cipher->setExclusiveC14nSerialisation(false);
102 checkParams(encParams,kencParams);
103 m_cipher->encryptElementDetached(element, ENCRYPT_NONE, encParams.m_algorithm);
104 return decorateAndUnmarshall(encParams, kencParams);
106 catch(XSECException& e) {
107 auto_ptr_char temp(e.getMsg());
108 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
110 catch(XSECCryptoException& e) {
111 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
115 EncryptedData* Encrypter::encryptElementContent(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
117 // We can reuse the cipher object if the document hasn't changed.
119 if (m_cipher && m_cipher->getDocument()!=element->getOwnerDocument()) {
120 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
125 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(element->getOwnerDocument());
126 m_cipher->setExclusiveC14nSerialisation(false);
130 checkParams(encParams,kencParams);
131 m_cipher->encryptElementContentDetached(element, ENCRYPT_NONE, encParams.m_algorithm);
132 return decorateAndUnmarshall(encParams, kencParams);
134 catch(XSECException& e) {
135 auto_ptr_char temp(e.getMsg());
136 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
138 catch(XSECCryptoException& e) {
139 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
143 EncryptedData* Encrypter::encryptStream(istream& input, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
145 // Get a fresh cipher object and document.
148 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
152 DOMDocument* doc=NULL;
154 doc=XMLToolingConfig::getConfig().getParser().newDocument();
155 XercesJanitor<DOMDocument> janitor(doc);
156 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(doc);
157 m_cipher->setExclusiveC14nSerialisation(false);
159 checkParams(encParams,kencParams);
160 StreamInputSource::StreamBinInputStream xstream(input);
161 m_cipher->encryptBinInputStream(&xstream, ENCRYPT_NONE, encParams.m_algorithm);
162 return decorateAndUnmarshall(encParams, kencParams);
164 catch(XSECException& e) {
165 auto_ptr_char temp(e.getMsg());
166 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
168 catch(XSECCryptoException& e) {
169 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
173 EncryptedData* Encrypter::decorateAndUnmarshall(EncryptionParams& encParams, KeyEncryptionParams* kencParams)
175 XENCEncryptedData* encData=m_cipher->getEncryptedData();
177 throw EncryptionException("No EncryptedData element found?");
179 // Unmarshall a tooling version of EncryptedData around the DOM.
180 EncryptedData* xmlEncData=NULL;
181 auto_ptr<XMLObject> xmlObject(XMLObjectBuilder::buildOneFromElement(encData->getElement()));
182 if (!(xmlObject.get()) || !(xmlEncData=dynamic_cast<EncryptedData*>(xmlObject.get())))
183 throw EncryptionException("Unable to unmarshall into EncryptedData object.");
185 // Unbind from DOM so we can divorce this from the original document.
186 xmlEncData->releaseThisAndChildrenDOM();
189 KeyInfo* kinfo = encParams.m_credential ? encParams.m_credential->getKeyInfo(encParams.m_compact) : NULL;
191 xmlEncData->setKeyInfo(kinfo);
193 // Are we doing a key encryption?
195 XSECCryptoKey* kek = kencParams->m_credential.getPublicKey();
197 throw EncryptionException("Credential in KeyEncryptionParams structure did not supply a public key.");
198 if (!kencParams->m_algorithm)
199 kencParams->m_algorithm = getKeyTransportAlgorithm(encParams.m_algorithm);
201 m_cipher->setKEK(kek->clone());
202 // ownership of this belongs to us, for some reason...
203 auto_ptr<XENCEncryptedKey> encKey(
204 m_cipher->encryptKey(encParams.m_keyBuffer, encParams.m_keyBufferSize, ENCRYPT_NONE, kencParams->m_algorithm)
206 EncryptedKey* xmlEncKey=NULL;
207 auto_ptr<XMLObject> xmlObjectKey(XMLObjectBuilder::buildOneFromElement(encKey->getElement()));
208 if (!(xmlObjectKey.get()) || !(xmlEncKey=dynamic_cast<EncryptedKey*>(xmlObjectKey.get())))
209 throw EncryptionException("Unable to unmarshall into EncryptedKey object.");
211 xmlEncKey->releaseThisAndChildrenDOM();
214 if (kencParams->m_recipient)
215 xmlEncKey->setRecipient(kencParams->m_recipient);
218 kinfo = kencParams->m_credential.getKeyInfo(encParams.m_compact);
220 xmlEncKey->setKeyInfo(kinfo);
222 // Add the EncryptedKey inline.
223 if (!xmlEncData->getKeyInfo())
224 xmlEncData->setKeyInfo(KeyInfoBuilder::buildKeyInfo());
225 xmlEncData->getKeyInfo()->getUnknownXMLObjects().push_back(xmlEncKey);
226 xmlObjectKey.release();
233 EncryptedKey* Encrypter::encryptKey(const unsigned char* keyBuffer, unsigned int keyBufferSize, KeyEncryptionParams& kencParams, bool compact)
235 // Get a fresh cipher object and document.
238 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
242 XSECCryptoKey* kek = kencParams.m_credential.getPublicKey();
244 throw EncryptionException("Credential in KeyEncryptionParams structure did not supply a public key.");
246 DOMDocument* doc=NULL;
248 doc=XMLToolingConfig::getConfig().getParser().newDocument();
249 XercesJanitor<DOMDocument> janitor(doc);
250 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(doc);
251 m_cipher->setExclusiveC14nSerialisation(false);
252 m_cipher->setKEK(kek->clone());
253 auto_ptr<XENCEncryptedKey> encKey(m_cipher->encryptKey(keyBuffer, keyBufferSize, ENCRYPT_NONE, kencParams.m_algorithm));
255 EncryptedKey* xmlEncKey=NULL;
256 auto_ptr<XMLObject> xmlObjectKey(XMLObjectBuilder::buildOneFromElement(encKey->getElement()));
257 if (!(xmlObjectKey.get()) || !(xmlEncKey=dynamic_cast<EncryptedKey*>(xmlObjectKey.get())))
258 throw EncryptionException("Unable to unmarshall into EncryptedKey object.");
260 xmlEncKey->releaseThisAndChildrenDOM();
263 if (kencParams.m_recipient)
264 xmlEncKey->setRecipient(kencParams.m_recipient);
267 KeyInfo* kinfo = kencParams.m_credential.getKeyInfo(compact);
269 xmlEncKey->setKeyInfo(kinfo);
271 xmlObjectKey.release();
274 catch(XSECException& e) {
275 auto_ptr_char temp(e.getMsg());
276 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
278 catch(XSECCryptoException& e) {
279 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());