2 * Copyright 2001-2006 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"
26 #include <xsec/enc/openssl/OpenSSLCryptoSymmetricKey.hpp>
27 #include <xsec/enc/XSECCryptoException.hpp>
28 #include <xsec/framework/XSECException.hpp>
29 #include <xsec/xenc/XENCEncryptedData.hpp>
30 #include <xsec/xenc/XENCEncryptedKey.hpp>
32 using namespace xmlencryption;
33 using namespace xmlsignature;
34 using namespace xmltooling;
37 Encrypter::~Encrypter()
39 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
40 memset(m_keyBuffer,0,32);
43 void Encrypter::checkParams(EncryptionParams& encParams, KeyEncryptionParams* kencParams)
45 if (encParams.m_keyBufferSize==0) {
46 if (encParams.m_key) {
48 throw EncryptionException("Generating EncryptedKey inline requires the encryption key in raw form.");
50 else if (!encParams.m_key) {
52 throw EncryptionException("Using a generated encryption key requires a KeyEncryptionParams object.");
54 // We're generating a random key. The maximum supported length is AES-256, so we need 32 bytes.
55 if (XSECPlatformUtils::g_cryptoProvider->getRandom(m_keyBuffer,32)<32)
56 throw EncryptionException("Unable to generate random data; was PRNG seeded?");
57 encParams.m_keyBuffer=m_keyBuffer;
58 encParams.m_keyBufferSize=32;
62 if (!encParams.m_key) {
63 // We have to have a raw key now, so we need to build a wrapper around it.
64 if (XMLString::equals(encParams.m_algorithm,DSIGConstants::s_unicodeStrURI3DES_CBC)) {
65 encParams.m_key=new OpenSSLCryptoSymmetricKey(XSECCryptoSymmetricKey::KEY_3DES_192);
67 else if (XMLString::equals(encParams.m_algorithm,DSIGConstants::s_unicodeStrURIAES128_CBC)) {
68 encParams.m_key=new OpenSSLCryptoSymmetricKey(XSECCryptoSymmetricKey::KEY_AES_128);
70 else if (XMLString::equals(encParams.m_algorithm,DSIGConstants::s_unicodeStrURIAES192_CBC)) {
71 encParams.m_key=new OpenSSLCryptoSymmetricKey(XSECCryptoSymmetricKey::KEY_AES_192);
73 else if (XMLString::equals(encParams.m_algorithm,DSIGConstants::s_unicodeStrURIAES256_CBC)) {
74 encParams.m_key=new OpenSSLCryptoSymmetricKey(XSECCryptoSymmetricKey::KEY_AES_256);
77 throw EncryptionException("Unrecognized encryption algorithm, unable to build key wrapper.");
79 static_cast<OpenSSLCryptoSymmetricKey*>(encParams.m_key)->setKey(encParams.m_keyBuffer, encParams.m_keyBufferSize);
82 // Set the encryption key.
83 m_cipher->setKey(encParams.m_key->clone());
86 EncryptedData* Encrypter::encryptElement(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
88 // We can reuse the cipher object if the document hasn't changed.
90 if (m_cipher && m_cipher->getDocument()!=element->getOwnerDocument()) {
91 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
96 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(element->getOwnerDocument());
99 checkParams(encParams,kencParams);
100 m_cipher->encryptElementDetached(element, ENCRYPT_NONE, encParams.m_algorithm);
101 return decorateAndUnmarshall(encParams, kencParams);
103 catch(XSECException& e) {
104 auto_ptr_char temp(e.getMsg());
105 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
107 catch(XSECCryptoException& e) {
108 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
112 EncryptedData* Encrypter::encryptElementContent(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
114 // We can reuse the cipher object if the document hasn't changed.
116 if (m_cipher && m_cipher->getDocument()!=element->getOwnerDocument()) {
117 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
122 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(element->getOwnerDocument());
125 checkParams(encParams,kencParams);
126 m_cipher->encryptElementContentDetached(element, ENCRYPT_NONE, encParams.m_algorithm);
127 return decorateAndUnmarshall(encParams, kencParams);
129 catch(XSECException& e) {
130 auto_ptr_char temp(e.getMsg());
131 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
133 catch(XSECCryptoException& e) {
134 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
138 EncryptedData* Encrypter::encryptStream(istream& input, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
140 // Get a fresh cipher object and document.
143 XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
147 DOMDocument* doc=NULL;
149 doc=XMLToolingConfig::getConfig().getParser().newDocument();
150 m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(doc);
152 checkParams(encParams,kencParams);
153 StreamInputSource::StreamBinInputStream xstream(input);
154 m_cipher->encryptBinInputStream(&xstream, ENCRYPT_NONE, encParams.m_algorithm);
155 EncryptedData* xmlEncData = decorateAndUnmarshall(encParams, kencParams);
159 catch(XSECException& e) {
161 auto_ptr_char temp(e.getMsg());
162 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
164 catch(XSECCryptoException& e) {
166 throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
174 EncryptedData* Encrypter::decorateAndUnmarshall(EncryptionParams& encParams, KeyEncryptionParams* kencParams)
176 XENCEncryptedData* encData=m_cipher->getEncryptedData();
178 throw EncryptionException("No EncryptedData element found?");
180 // Unmarshall a tooling version of EncryptedData around the DOM.
181 EncryptedData* xmlEncData=NULL;
182 auto_ptr<XMLObject> xmlObject(XMLObjectBuilder::buildOneFromElement(encData->getElement()));
183 if (!(xmlObject.get()) || !(xmlEncData=dynamic_cast<EncryptedData*>(xmlObject.get())))
184 throw EncryptionException("Unable to unmarshall into EncryptedData object.");
186 // Unbind from DOM so we can divorce this from the original document.
187 xmlEncData->releaseThisAndChildrenDOM();
190 if (encParams.m_keyInfo) {
191 xmlEncData->setKeyInfo(encParams.m_keyInfo);
192 encParams.m_keyInfo=NULL; // transfer ownership
195 // Are we doing a key encryption?
197 m_cipher->setKEK(kencParams->m_key->clone());
198 // ownership of this belongs to us, for some reason...
199 auto_ptr<XENCEncryptedKey> encKey(
200 m_cipher->encryptKey(encParams.m_keyBuffer, encParams.m_keyBufferSize, ENCRYPT_NONE, kencParams->m_algorithm)
202 EncryptedKey* xmlEncKey=NULL;
203 auto_ptr<XMLObject> xmlObjectKey(XMLObjectBuilder::buildOneFromElement(encKey->getElement()));
204 if (!(xmlObjectKey.get()) || !(xmlEncKey=dynamic_cast<EncryptedKey*>(xmlObjectKey.get())))
205 throw EncryptionException("Unable to unmarshall into EncryptedKey object.");
207 xmlEncKey->releaseThisAndChildrenDOM();
210 if (kencParams->m_keyInfo) {
211 xmlEncKey->setKeyInfo(kencParams->m_keyInfo);
212 kencParams->m_keyInfo=NULL; // transfer ownership
215 // Add the EncryptedKey.
216 if (!xmlEncData->getKeyInfo())
217 xmlEncData->setKeyInfo(KeyInfoBuilder::buildKeyInfo());
218 xmlEncData->getKeyInfo()->getOthers().push_back(xmlEncKey);
219 xmlObjectKey.release();