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;
37 using namespace xercesc;
40 Encrypter::~Encrypter()
42 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
43 memset(m_keyBuffer,0,32);
46 void Encrypter::checkParams(EncryptionParams& encParams, KeyEncryptionParams* kencParams)
48 if (encParams.m_keyBufferSize==0) {
49 if (encParams.m_credential) {
51 throw EncryptionException("Generating EncryptedKey inline requires the encryption key in raw form.");
55 throw EncryptionException("Using a generated encryption key requires a KeyEncryptionParams object.");
57 // We're generating a random key. The maximum supported length is AES-256, so we need 32 bytes.
58 if (XSECPlatformUtils::g_cryptoProvider->getRandom(m_keyBuffer,32)<32)
59 throw EncryptionException("Unable to generate random data; was PRNG seeded?");
60 encParams.m_keyBuffer=m_keyBuffer;
61 encParams.m_keyBufferSize=32;
65 XSECCryptoKey* key=NULL;
66 if (encParams.m_credential) {
67 key = encParams.m_credential->getPrivateKey();
69 throw EncryptionException("Credential in EncryptionParams structure did not supply a private/secret key.");
70 // Set the encryption key.
71 m_cipher->setKey(key->clone());
74 // We have to have a raw key now, so we need to build a wrapper around it.
75 XSECAlgorithmHandler* handler =XSECPlatformUtils::g_algorithmMapper->mapURIToHandler(encParams.m_algorithm);
77 key = handler->createKeyForURI(
78 encParams.m_algorithm,const_cast<unsigned char*>(encParams.m_keyBuffer),encParams.m_keyBufferSize
82 throw EncryptionException("Unable to build wrapper for key, unknown algorithm?");
83 // Overwrite the length if known.
84 switch (static_cast<XSECCryptoSymmetricKey*>(key)->getSymmetricKeyType()) {
85 case XSECCryptoSymmetricKey::KEY_3DES_192:
86 encParams.m_keyBufferSize = 192/8;
88 case XSECCryptoSymmetricKey::KEY_AES_128:
89 encParams.m_keyBufferSize = 128/8;
91 case XSECCryptoSymmetricKey::KEY_AES_192:
92 encParams.m_keyBufferSize = 192/8;
94 case XSECCryptoSymmetricKey::KEY_AES_256:
95 encParams.m_keyBufferSize = 256/8;
98 // Set the encryption key.
99 m_cipher->setKey(key);
103 EncryptedData* Encrypter::encryptElement(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
105 // We can reuse the cipher object if the document hasn't changed.
107 if (m_cipher && m_cipher->getDocument()!=element->getOwnerDocument()) {
108 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
113 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(element->getOwnerDocument());
114 m_cipher->setExclusiveC14nSerialisation(false);
118 checkParams(encParams,kencParams);
119 m_cipher->encryptElementDetached(element, ENCRYPT_NONE, encParams.m_algorithm);
120 return decorateAndUnmarshall(encParams, kencParams);
122 catch(XSECException& e) {
123 auto_ptr_char temp(e.getMsg());
124 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
126 catch(XSECCryptoException& e) {
127 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
131 EncryptedData* Encrypter::encryptElementContent(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
133 // We can reuse the cipher object if the document hasn't changed.
135 if (m_cipher && m_cipher->getDocument()!=element->getOwnerDocument()) {
136 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
141 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(element->getOwnerDocument());
142 m_cipher->setExclusiveC14nSerialisation(false);
146 checkParams(encParams,kencParams);
147 m_cipher->encryptElementContentDetached(element, ENCRYPT_NONE, encParams.m_algorithm);
148 return decorateAndUnmarshall(encParams, kencParams);
150 catch(XSECException& e) {
151 auto_ptr_char temp(e.getMsg());
152 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
154 catch(XSECCryptoException& e) {
155 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
159 EncryptedData* Encrypter::encryptStream(istream& input, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
161 // Get a fresh cipher object and document.
164 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
168 DOMDocument* doc=NULL;
170 doc=XMLToolingConfig::getConfig().getParser().newDocument();
171 XercesJanitor<DOMDocument> janitor(doc);
172 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(doc);
173 m_cipher->setExclusiveC14nSerialisation(false);
175 checkParams(encParams,kencParams);
176 StreamInputSource::StreamBinInputStream xstream(input);
177 m_cipher->encryptBinInputStream(&xstream, 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::decorateAndUnmarshall(EncryptionParams& encParams, KeyEncryptionParams* kencParams)
191 XENCEncryptedData* encData=m_cipher->getEncryptedData();
193 throw EncryptionException("No EncryptedData element found?");
195 // Unmarshall a tooling version of EncryptedData around the DOM.
196 EncryptedData* xmlEncData=NULL;
197 auto_ptr<XMLObject> xmlObject(XMLObjectBuilder::buildOneFromElement(encData->getElement()));
198 if (!(xmlObject.get()) || !(xmlEncData=dynamic_cast<EncryptedData*>(xmlObject.get())))
199 throw EncryptionException("Unable to unmarshall into EncryptedData object.");
201 // Unbind from DOM so we can divorce this from the original document.
202 xmlEncData->releaseThisAndChildrenDOM();
205 KeyInfo* kinfo = encParams.m_credential ? encParams.m_credential->getKeyInfo(encParams.m_compact) : NULL;
207 xmlEncData->setKeyInfo(kinfo);
209 // Are we doing a key encryption?
211 XSECCryptoKey* kek = kencParams->m_credential.getPublicKey();
213 throw EncryptionException("Credential in KeyEncryptionParams structure did not supply a public key.");
214 if (!kencParams->m_algorithm)
215 kencParams->m_algorithm = getKeyTransportAlgorithm(kencParams->m_credential, encParams.m_algorithm);
217 m_cipher->setKEK(kek->clone());
218 // ownership of this belongs to us, for some reason...
219 auto_ptr<XENCEncryptedKey> encKey(
220 m_cipher->encryptKey(encParams.m_keyBuffer, encParams.m_keyBufferSize, ENCRYPT_NONE, kencParams->m_algorithm)
222 EncryptedKey* xmlEncKey=NULL;
223 auto_ptr<XMLObject> xmlObjectKey(XMLObjectBuilder::buildOneFromElement(encKey->getElement()));
224 if (!(xmlObjectKey.get()) || !(xmlEncKey=dynamic_cast<EncryptedKey*>(xmlObjectKey.get())))
225 throw EncryptionException("Unable to unmarshall into EncryptedKey object.");
227 xmlEncKey->releaseThisAndChildrenDOM();
230 if (kencParams->m_recipient)
231 xmlEncKey->setRecipient(kencParams->m_recipient);
234 kinfo = kencParams->m_credential.getKeyInfo(encParams.m_compact);
236 xmlEncKey->setKeyInfo(kinfo);
238 // Add the EncryptedKey inline.
239 if (!xmlEncData->getKeyInfo())
240 xmlEncData->setKeyInfo(KeyInfoBuilder::buildKeyInfo());
241 xmlEncData->getKeyInfo()->getUnknownXMLObjects().push_back(xmlEncKey);
242 xmlObjectKey.release();
249 EncryptedKey* Encrypter::encryptKey(
250 const unsigned char* keyBuffer, unsigned int keyBufferSize, KeyEncryptionParams& kencParams, bool compact
253 // Get a fresh cipher object and document.
256 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
260 XSECCryptoKey* kek = kencParams.m_credential.getPublicKey();
262 throw EncryptionException("Credential in KeyEncryptionParams structure did not supply a public key.");
264 DOMDocument* doc=NULL;
266 doc=XMLToolingConfig::getConfig().getParser().newDocument();
267 XercesJanitor<DOMDocument> janitor(doc);
268 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(doc);
269 m_cipher->setExclusiveC14nSerialisation(false);
270 m_cipher->setKEK(kek->clone());
271 auto_ptr<XENCEncryptedKey> encKey(m_cipher->encryptKey(keyBuffer, keyBufferSize, ENCRYPT_NONE, kencParams.m_algorithm));
273 EncryptedKey* xmlEncKey=NULL;
274 auto_ptr<XMLObject> xmlObjectKey(XMLObjectBuilder::buildOneFromElement(encKey->getElement()));
275 if (!(xmlObjectKey.get()) || !(xmlEncKey=dynamic_cast<EncryptedKey*>(xmlObjectKey.get())))
276 throw EncryptionException("Unable to unmarshall into EncryptedKey object.");
278 xmlEncKey->releaseThisAndChildrenDOM();
281 if (kencParams.m_recipient)
282 xmlEncKey->setRecipient(kencParams.m_recipient);
285 KeyInfo* kinfo = kencParams.m_credential.getKeyInfo(compact);
287 xmlEncKey->setKeyInfo(kinfo);
289 xmlObjectKey.release();
292 catch(XSECException& e) {
293 auto_ptr_char temp(e.getMsg());
294 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
296 catch(XSECCryptoException& e) {
297 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
301 const XMLCh* Encrypter::getKeyTransportAlgorithm(const Credential& credential, const XMLCh* encryptionAlg)
303 const char* alg = credential.getAlgorithm();
304 if (!alg || !strcmp(alg, "RSA")) {
305 if (XMLString::equals(encryptionAlg,DSIGConstants::s_unicodeStrURI3DES_CBC))
306 return DSIGConstants::s_unicodeStrURIRSA_1_5;
308 return DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1;
310 else if (!strcmp(alg, "AES")) {
311 switch (credential.getKeySize()) {
313 return DSIGConstants::s_unicodeStrURIKW_AES128;
315 return DSIGConstants::s_unicodeStrURIKW_AES192;
317 return DSIGConstants::s_unicodeStrURIKW_AES256;
320 else if (!strcmp(alg, "DESede")) {
321 return DSIGConstants::s_unicodeStrURIKW_3DES;