From a8d82f50437c7228f2bb572b4b7821a7d8494c3f Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Mon, 21 May 2007 20:21:51 +0000 Subject: [PATCH] Add method to decrypt to stream. --- xmltooling/encryption/Decrypter.h | 18 ++++++ xmltooling/encryption/impl/Decrypter.cpp | 101 +++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/xmltooling/encryption/Decrypter.h b/xmltooling/encryption/Decrypter.h index 780d1a0..9f4b1e4 100644 --- a/xmltooling/encryption/Decrypter.h +++ b/xmltooling/encryption/Decrypter.h @@ -113,6 +113,24 @@ namespace xmlencryption { xercesc::DOMDocumentFragment* decryptData(const EncryptedData& encryptedData, const XMLCh* recipient=NULL); /** + * Decrypts the supplied information to an output stream. + * + * @param out output stream to receive the decrypted data + * @param encryptedData the data to decrypt + * @param key the decryption key to use (it will not be freed internally) + */ + void decryptData(std::ostream& out, const EncryptedData& encryptedData, XSECCryptoKey* key); + + /** + * Decrypts the supplied information to an output stream. + * + * @param out output stream to receive the decrypted data + * @param encryptedData the data to decrypt + * @param recipient identifier of decrypting entity for use in identifying multi-cast keys + */ + void decryptData(std::ostream& out, const EncryptedData& encryptedData, const XMLCh* recipient=NULL); + + /** * Decrypts the supplied information and returns the resulting key. * The caller is responsible for deleting the key. The algorithm of the * key must be supplied by the caller based on knowledge of the associated diff --git a/xmltooling/encryption/impl/Decrypter.cpp b/xmltooling/encryption/impl/Decrypter.cpp index c7b1097..89a274b 100644 --- a/xmltooling/encryption/impl/Decrypter.cpp +++ b/xmltooling/encryption/impl/Decrypter.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -146,6 +147,106 @@ DOMDocumentFragment* Decrypter::decryptData(const EncryptedData& encryptedData, return decryptData(encryptedData, keywrapper.get()); } +void Decrypter::decryptData(ostream& out, const EncryptedData& encryptedData, XSECCryptoKey* key) +{ + if (encryptedData.getDOM()==NULL) + throw DecryptionException("The object must be marshalled before decryption."); + + // We can reuse the cipher object if the document hasn't changed. + + if (m_cipher && m_cipher->getDocument()!=encryptedData.getDOM()->getOwnerDocument()) { + XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseCipher(m_cipher); + m_cipher=NULL; + } + + if (!m_cipher) + m_cipher=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newCipher(encryptedData.getDOM()->getOwnerDocument()); + + try { + m_cipher->setKey(key->clone()); + auto_ptr in(m_cipher->decryptToBinInputStream(encryptedData.getDOM())); + + XMLByte buf[8192]; + unsigned int count = in->readBytes(buf, sizeof(buf)); + while (count > 0) + out.write(reinterpret_cast(buf),count); + } + catch(XSECException& e) { + auto_ptr_char temp(e.getMsg()); + throw DecryptionException(string("XMLSecurity exception while decrypting: ") + temp.get()); + } + catch(XSECCryptoException& e) { + throw DecryptionException(string("XMLSecurity exception while decrypting: ") + e.getMsg()); + } +} + +void Decrypter::decryptData(ostream& out, const EncryptedData& encryptedData, const XMLCh* recipient) +{ + if (!m_credResolver) + throw DecryptionException("No CredentialResolver supplied to provide decryption keys."); + + // Resolve a decryption key directly. + vector creds; + int types = + CredentialCriteria::KEYINFO_EXTRACTION_KEY | + CredentialCriteria::KEYINFO_EXTRACTION_KEYNAMES | + CredentialCriteria::KEYINFO_EXTRACTION_IMPLICIT_KEYNAMES; + if (m_criteria) { + m_criteria->setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL); + m_criteria->setKeyInfo(encryptedData.getKeyInfo(), types); + const EncryptionMethod* meth = encryptedData.getEncryptionMethod(); + if (meth) + m_criteria->setXMLAlgorithm(meth->getAlgorithm()); + m_credResolver->resolve(creds,m_criteria); + } + else { + CredentialCriteria criteria; + criteria.setUsage(CredentialCriteria::ENCRYPTION_CREDENTIAL); + criteria.setKeyInfo(encryptedData.getKeyInfo(), types); + const EncryptionMethod* meth = encryptedData.getEncryptionMethod(); + if (meth) + criteria.setXMLAlgorithm(meth->getAlgorithm()); + m_credResolver->resolve(creds,&criteria); + } + + // Loop over them and try each one. + XSECCryptoKey* key; + for (vector::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) { + try { + key = (*cred)->getPrivateKey(); + if (!key) + continue; + return decryptData(out, encryptedData, key); + } + catch(DecryptionException& ex) { + log4cpp::Category::getInstance(XMLTOOLING_LOGCAT".Decrypter").warn(ex.what()); + } + } + + // We need to find an encrypted decryption key somewhere. We'll need the underlying algorithm... + const XMLCh* algorithm= + encryptedData.getEncryptionMethod() ? encryptedData.getEncryptionMethod()->getAlgorithm() : NULL; + if (!algorithm) + throw DecryptionException("No EncryptionMethod/@Algorithm set, key decryption cannot proceed."); + + // Check for external resolver. + const EncryptedKey* encKey=NULL; + if (m_EKResolver) + encKey = m_EKResolver->resolveKey(encryptedData, recipient); + else { + EncryptedKeyResolver ekr; + encKey = ekr.resolveKey(encryptedData, recipient); + } + + if (!encKey) + throw DecryptionException("Unable to locate an encrypted key."); + + auto_ptr keywrapper(decryptKey(*encKey, algorithm)); + if (!keywrapper.get()) + throw DecryptionException("Unable to decrypt the encrypted key."); + decryptData(out, encryptedData, keywrapper.get()); +} + XSECCryptoKey* Decrypter::decryptKey(const EncryptedKey& encryptedKey, const XMLCh* algorithm) { if (!m_credResolver) -- 2.1.4