XMLToolingConfig.h
encinclude_HEADERS = \
+ encryption/Encrypter.h \
encryption/Encryption.h
implinclude_HEADERS = \
if BUILD_XMLSEC
xmlsec_sources = \
+ encryption/impl/Encrypter.cpp \
signature/impl/SignatureValidator.cpp \
signature/impl/XMLSecSignatureImpl.cpp
else
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Encrypter.h
+ *
+ * Methods for encrypting XMLObjects and other data.
+ */
+
+#if !defined(__xmltooling_encrypter_h__) && !defined(XMLTOOLING_NO_XMLSEC)
+#define __xmltooling_encrypter_h__
+
+#include <xmltooling/encryption/Encryption.h>
+
+#include <xsec/enc/XSECCryptoKey.hpp>
+#include <xsec/xenc/XENCCipher.hpp>
+
+namespace xmlencryption {
+
+ /**
+ * Wrapper API for XML Encryption functionality.
+ * Designed to allow both external and internal key generation as follows:
+ *
+ * If no keying material is supplied, then the algorithm MAY be recognized
+ * and a key can be generated internally. This is only done if a KeyEncryptionParams
+ * structure is also supplied to the operation (otherwise the key would be lost).
+ *
+ * If an XSECCryptoKey is supplied, then it is used directly, but if KeyEncryptionParams
+ * are supplied, an exception will result unless the raw key buffer is also supplied.
+ *
+ * If a raw key is provided, then a key object can also be created internally if the
+ * algorithm is recognized.
+ *
+ * Summing up, if KeyEncryptionParams are used, a raw key must be available or the
+ * key can be generated when the encryption algorithm itself is a standard one. If
+ * no KeyEncryptionParams are supplied, then the key must be supplied either in raw
+ * or object form.
+ */
+ class XMLTOOL_API Encrypter
+ {
+ public:
+
+ /**
+ * Structure to collect encryption requirements.
+ */
+ struct XMLTOOL_API EncryptionParams {
+
+ /**
+ * Constructor.
+ * The algorithm constant and key buffer <strong>MUST</strong> be accessible for the life of
+ * the structure. The other objects will be destroyed if need be when the structure is destroyed.
+ *
+ * @param algorithm the XML Encryption key wrapping or transport algorithm constant
+ * @param keyBuffer buffer containing the raw key information
+ * @param keyBufferSize the size of the raw key buffer in bytes
+ * @param key the key encryption key to use, or NULL
+ * @param keyInfo a KeyInfo object to place within the EncryptedData structure
+ */
+ EncryptionParams(
+ const XMLCh* algorithm=DSIGConstants::s_unicodeStrURIAES256_CBC,
+ const unsigned char* keyBuffer=NULL,
+ unsigned int keyBufferSize=0,
+ XSECCryptoKey* key=NULL,
+ xmlsignature::KeyInfo* keyInfo=NULL
+ ) : m_keyBuffer(keyBuffer), m_keyBufferSize(keyBufferSize), m_key(key), m_keyInfo(keyInfo), m_algorithm(algorithm) {
+ }
+
+ ~EncryptionParams() {
+ delete m_key;
+ delete m_keyInfo;
+ }
+ private:
+ const unsigned char* m_keyBuffer;
+ unsigned int m_keyBufferSize;
+ XSECCryptoKey* m_key;
+ xmlsignature::KeyInfo* m_keyInfo;
+ const XMLCh* m_algorithm;
+
+ friend class Encrypter;
+ };
+
+ /**
+ * Structure to collect key wrapping/transport requirements.
+ */
+ struct XMLTOOL_API KeyEncryptionParams {
+
+ /**
+ * Constructor.
+ * The algorithm constant <strong>MUST</strong> be accessible for the life of the structure.
+ * Using a static constant suffices for this. The other objects will be destroyed if need be
+ * when the structure is destroyed.
+ *
+ * @param algorithm the XML Encryption key wrapping or transport algorithm constant
+ * @param key the key encryption key to use
+ * @param keyInfo a KeyInfo object to place within the EncryptedKey structure that describes the KEK
+ */
+ KeyEncryptionParams(const XMLCh* algorithm, XSECCryptoKey* key, xmlsignature::KeyInfo* keyInfo=NULL)
+ : m_key(key), m_keyInfo(keyInfo), m_algorithm(algorithm) {
+ }
+
+ ~KeyEncryptionParams() {
+ delete m_key;
+ delete m_keyInfo;
+ }
+ private:
+ XSECCryptoKey* m_key;
+ xmlsignature::KeyInfo* m_keyInfo;
+ const XMLCh* m_algorithm;
+
+ friend class Encrypter;
+ };
+
+ Encrypter() : m_cipher(NULL) {}
+
+ ~Encrypter();
+
+ /**
+ * Encrypts the supplied element and returns the resulting object.
+ * The returned object will be unmarshalled around a DOM tree created
+ * using the encrypted element's owning document.
+ *
+ * If an encryption algorithm is set, but no key, a random key will be
+ * generated iff keParams is non-NULL and the algorithm is known.
+ *
+ * If key encryption parameters are supplied, then the encryption key
+ * is wrapped and the result placed into an EncryptedKey object in the
+ * KeyInfo of the returned EncryptedData.
+ *
+ * @param element the DOM element to encrypt
+ * @param keParams key encryption settings, or NULL
+ */
+ EncryptedData* encryptElement(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams=NULL);
+
+ /**
+ * Encrypts the supplied element's children and returns the resulting object.
+ * The returned object will be unmarshalled around a DOM tree created
+ * using the encrypted content's owning document.
+ *
+ * If an encryption algorithm is set, but no key, a random key will be
+ * generated iff keParams is non-NULL and the algorithm is known.
+
+ * If key encryption parameters are supplied, then the encryption key
+ * is wrapped and the result placed into an EncryptedKey object in the
+ * KeyInfo of the returned EncryptedData.
+ *
+ * @param element parent element of children to encrypt
+ * @param keParams key encryption settings, or NULL
+ */
+ EncryptedData* encryptElementContent(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams=NULL);
+
+ /**
+ * Encrypts the supplied input stream and returns the resulting object.
+ * The returned object will be unmarshalled around a DOM tree created
+ * using the encrypted element's owning document.
+ *
+ * If an encryption algorithm is set, but no key, a random key will be
+ * generated iff keParams is non-NULL and the algorithm is known.
+
+ * If key encryption parameters are supplied, then the encryption key
+ * is wrapped and the result placed into an EncryptedKey object in the
+ * KeyInfo of the returned EncryptedData.
+ *
+ * @param input the stream to encrypt
+ * @param keParams key encryption settings, or NULL
+ */
+ EncryptedData* encryptStream(std::istream& input, EncryptionParams& encParams, KeyEncryptionParams* kencParams=NULL);
+
+ private:
+ void checkParams(EncryptionParams& encParams, KeyEncryptionParams* kencParams);
+ EncryptedData* decorateAndUnmarshall(EncryptionParams& encParams, KeyEncryptionParams* kencParams);
+
+ XENCCipher* m_cipher;
+ unsigned char m_keyBuffer[32];
+ };
+
+ DECL_XMLTOOLING_EXCEPTION(EncryptionException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmlencryption,xmltooling::XMLToolingException,Exceptions in encryption processing);
+
+};
+
+#endif /* __xmltooling_encrypter_h__ */
* XMLObjects representing XML Encryption content
*/
-#ifndef __xmltooling_encrypt_h__
-#define __xmltooling_encrypt_h__
+#ifndef __xmltooling_encryption_h__
+#define __xmltooling_encryption_h__
#include <xmltooling/AttributeExtensibleXMLObject.h>
#include <xmltooling/signature/KeyInfo.h>
void XMLTOOL_API registerEncryptionClasses();
};
-#endif /* __xmltooling_encrypt_h__ */
+#endif /* __xmltooling_encryption_h__ */
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Encrypter.cpp
+ *
+ * Methods for encrypting XMLObjects and other data.
+ */
+
+#include "internal.h"
+#include "encryption/Encrypter.h"
+
+#include <xsec/enc/openssl/OpenSSLCryptoSymmetricKey.hpp>
+#include <xsec/enc/XSECCryptoException.hpp>
+#include <xsec/framework/XSECException.hpp>
+#include <xsec/xenc/XENCEncryptedData.hpp>
+#include <xsec/xenc/XENCEncryptedKey.hpp>
+
+using namespace xmlencryption;
+using namespace xmlsignature;
+using namespace xmltooling;
+using namespace std;
+
+Encrypter::~Encrypter()
+{
+ XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
+ memset(m_keyBuffer,0,32);
+}
+
+void Encrypter::checkParams(EncryptionParams& encParams, KeyEncryptionParams* kencParams)
+{
+ if (encParams.m_keyBufferSize==0) {
+ if (encParams.m_key) {
+ if (kencParams)
+ throw EncryptionException("Generating EncryptedKey inline requires the encryption key in raw form.");
+ }
+ else if (!encParams.m_key) {
+ if (!kencParams)
+ throw EncryptionException("Using a generated encryption key requires a KeyEncryptionParams object.");
+
+ // We're generating a random key. The maximum supported length is AES-256, so we need 32 bytes.
+ if (XSECPlatformUtils::g_cryptoProvider->getRandom(m_keyBuffer,32)<32)
+ throw EncryptionException("Unable to generate random data; was PRNG seeded?");
+ encParams.m_keyBuffer=m_keyBuffer;
+ encParams.m_keyBufferSize=32;
+ }
+ }
+
+ if (!encParams.m_key) {
+ // We have to have a raw key now, so we need to build a wrapper around it.
+ if (XMLString::equals(encParams.m_algorithm,DSIGConstants::s_unicodeStrURI3DES_CBC)) {
+ encParams.m_key=new OpenSSLCryptoSymmetricKey(XSECCryptoSymmetricKey::KEY_3DES_192);
+ }
+ else if (XMLString::equals(encParams.m_algorithm,DSIGConstants::s_unicodeStrURIAES128_CBC)) {
+ encParams.m_key=new OpenSSLCryptoSymmetricKey(XSECCryptoSymmetricKey::KEY_AES_128);
+ }
+ else if (XMLString::equals(encParams.m_algorithm,DSIGConstants::s_unicodeStrURIAES192_CBC)) {
+ encParams.m_key=new OpenSSLCryptoSymmetricKey(XSECCryptoSymmetricKey::KEY_AES_192);
+ }
+ else if (XMLString::equals(encParams.m_algorithm,DSIGConstants::s_unicodeStrURIAES256_CBC)) {
+ encParams.m_key=new OpenSSLCryptoSymmetricKey(XSECCryptoSymmetricKey::KEY_AES_256);
+ }
+ else {
+ throw EncryptionException("Unrecognized encryption algorithm, unable to build key wrapper.");
+ }
+ static_cast<OpenSSLCryptoSymmetricKey*>(encParams.m_key)->setKey(encParams.m_keyBuffer, encParams.m_keyBufferSize);
+ }
+
+ // Set the encryption key.
+ m_cipher->setKey(encParams.m_key->clone());
+}
+
+EncryptedData* Encrypter::encryptElement(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
+{
+ // We can reuse the cipher object if the document hasn't changed.
+
+ if (m_cipher && m_cipher->getDocument()!=element->getOwnerDocument()) {
+ XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
+ m_cipher=NULL;
+ }
+
+ if (!m_cipher)
+ m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(element->getOwnerDocument());
+
+ try {
+ checkParams(encParams,kencParams);
+ m_cipher->encryptElementDetached(element, ENCRYPT_NONE, encParams.m_algorithm);
+ return decorateAndUnmarshall(encParams, kencParams);
+ }
+ catch(XSECException& e) {
+ auto_ptr_char temp(e.getMsg());
+ throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
+ }
+ catch(XSECCryptoException& e) {
+ throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
+ }
+}
+
+EncryptedData* Encrypter::encryptElementContent(DOMElement* element, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
+{
+ // We can reuse the cipher object if the document hasn't changed.
+
+ if (m_cipher && m_cipher->getDocument()!=element->getOwnerDocument()) {
+ XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
+ m_cipher=NULL;
+ }
+
+ if (!m_cipher)
+ m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(element->getOwnerDocument());
+
+ try {
+ checkParams(encParams,kencParams);
+ m_cipher->encryptElementContentDetached(element, ENCRYPT_NONE, encParams.m_algorithm);
+ return decorateAndUnmarshall(encParams, kencParams);
+ }
+ catch(XSECException& e) {
+ auto_ptr_char temp(e.getMsg());
+ throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
+ }
+ catch(XSECCryptoException& e) {
+ throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
+ }
+}
+
+EncryptedData* Encrypter::encryptStream(istream& input, EncryptionParams& encParams, KeyEncryptionParams* kencParams)
+{
+ // Get a fresh cipher object and document.
+
+ if (m_cipher) {
+ XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher);
+ m_cipher=NULL;
+ }
+
+ DOMDocument* doc=NULL;
+ try {
+ doc=XMLToolingConfig::getConfig().getParser().newDocument();
+ m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(doc);
+
+ checkParams(encParams,kencParams);
+ StreamInputSource::StreamBinInputStream xstream(input);
+ m_cipher->encryptBinInputStream(&xstream, ENCRYPT_NONE, encParams.m_algorithm);
+ EncryptedData* xmlEncData = decorateAndUnmarshall(encParams, kencParams);
+ doc->release();
+ return xmlEncData;
+ }
+ catch(XSECException& e) {
+ doc->release();
+ auto_ptr_char temp(e.getMsg());
+ throw EncryptionException(string("XMLSecurity exception while encrypting: ") + temp.get());
+ }
+ catch(XSECCryptoException& e) {
+ doc->release();
+ throw EncryptionException(string("XMLSecurity exception while encrypting: ") + e.getMsg());
+ }
+ catch (...) {
+ doc->release();
+ throw;
+ }
+}
+
+EncryptedData* Encrypter::decorateAndUnmarshall(EncryptionParams& encParams, KeyEncryptionParams* kencParams)
+{
+ XENCEncryptedData* encData=m_cipher->getEncryptedData();
+ if (!encData)
+ throw EncryptionException("No EncryptedData element found?");
+
+ // Unmarshall a tooling version of EncryptedData around the DOM.
+ EncryptedData* xmlEncData=NULL;
+ auto_ptr<XMLObject> xmlObject(XMLObjectBuilder::buildOneFromElement(encData->getElement()));
+ if (!(xmlObject.get()) || !(xmlEncData=dynamic_cast<EncryptedData*>(xmlObject.get())))
+ throw EncryptionException("Unable to unmarshall into EncryptedData object.");
+
+ // Unbind from DOM so we can divorce this from the original document.
+ xmlEncData->releaseThisAndChildrenDOM();
+
+ // KeyInfo?
+ if (encParams.m_keyInfo) {
+ xmlEncData->setKeyInfo(encParams.m_keyInfo);
+ encParams.m_keyInfo=NULL; // transfer ownership
+ }
+
+ // Are we doing a key encryption?
+ if (kencParams) {
+ m_cipher->setKEK(kencParams->m_key->clone());
+ // ownership of this belongs to us, for some reason...
+ auto_ptr<XENCEncryptedKey> encKey(
+ m_cipher->encryptKey(encParams.m_keyBuffer, encParams.m_keyBufferSize, ENCRYPT_NONE, kencParams->m_algorithm)
+ );
+ EncryptedKey* xmlEncKey=NULL;
+ auto_ptr<XMLObject> xmlObjectKey(XMLObjectBuilder::buildOneFromElement(encKey->getElement()));
+ if (!(xmlObjectKey.get()) || !(xmlEncKey=dynamic_cast<EncryptedKey*>(xmlObjectKey.get())))
+ throw EncryptionException("Unable to unmarshall into EncryptedKey object.");
+
+ xmlEncKey->releaseThisAndChildrenDOM();
+
+ // KeyInfo?
+ if (kencParams->m_keyInfo) {
+ xmlEncKey->setKeyInfo(kencParams->m_keyInfo);
+ kencParams->m_keyInfo=NULL; // transfer ownership
+ }
+
+ // Add the EncryptedKey.
+ if (!xmlEncData->getKeyInfo())
+ xmlEncData->setKeyInfo(KeyInfoBuilder::buildKeyInfo());
+ xmlEncData->getKeyInfo()->getOthers().push_back(xmlEncKey);
+ xmlObjectKey.release();
+ }
+
+ xmlObject.release();
+ return xmlEncData;
+}
}\r
};\r
\r
- DECL_XMLTOOLING_EXCEPTION(XMLSecurityException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmlsignature,xmltooling::XMLToolingException,Exceptions in XML Security processing);\r
- DECL_XMLTOOLING_EXCEPTION(SignatureException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmlsignature,xmlsignature::XMLSecurityException,Exceptions in signature processing);\r
+ DECL_XMLTOOLING_EXCEPTION(SignatureException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmlsignature,xmltooling::XMLToolingException,Exceptions in signature processing);\r
\r
};\r
\r
virtual BinInputStream* makeStream() const { return new StreamBinInputStream(m_is); }\r
/// @endcond\r
\r
-\r
- private:\r
- std::istream& m_is;\r
-\r
+ /**\r
+ * A Xerces input stream that wraps a C++ input stream\r
+ */\r
class XMLTOOL_API StreamBinInputStream : public BinInputStream\r
{\r
public:\r
+ /**\r
+ * Constructs a Xerces input stream around a C++ input stream reference.\r
+ * \r
+ * @param is reference to an input stream\r
+ */\r
StreamBinInputStream(std::istream& is) : m_is(is), m_pos(0) {}\r
+ /// @cond off\r
virtual unsigned int curPos() const { return m_pos; }\r
virtual unsigned int readBytes(XMLByte* const toFill, const unsigned int maxToRead);\r
+ /// @endcond\r
private:\r
std::istream& m_is;\r
unsigned int m_pos;\r
};\r
+\r
+ private:\r
+ std::istream& m_is;\r
};\r
};\r
\r
Name="impl"\r
>\r
<File\r
+ RelativePath=".\encryption\impl\Encrypter.cpp"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\encryption\impl\EncryptionImpl.cpp"\r
>\r
</File>\r
Name="encryption"\r
>\r
<File\r
+ RelativePath=".\encryption\Encrypter.h"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\encryption\Encryption.h"\r
>\r
</File>\r