xsec/tools/cipher/cipher.cpp (647 lines of code) (raw):

/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ /* * XSEC * * cipher := Tool to handle basic encryption/decryption of XML documents * * Author(s): Berin Lautenbach * * $Id$ * */ // XSEC #include <xsec/utils/XSECPlatformUtils.hpp> #include <xsec/framework/XSECProvider.hpp> #include <xsec/framework/XSECException.hpp> #include <xsec/enc/XSECCryptoException.hpp> #include <xsec/enc/XSECCryptoUtils.hpp> #include <xsec/enc/OpenSSL/OpenSSLCryptoSymmetricKey.hpp> #include <xsec/utils/XSECBinTXFMInputStream.hpp> #include <xsec/xenc/XENCEncryptedData.hpp> #include <xsec/xenc/XENCEncryptedKey.hpp> #include "XencInteropResolver.hpp" #include "../../utils/XSECDOMUtils.hpp" // General #include <memory.h> #include <string.h> #include <iostream> #include <fstream> #include <stdlib.h> #if defined(HAVE_UNISTD_H) # include <unistd.h> #else # if defined(HAVE_DIRECT_H) # include <direct.h> # endif #endif #if defined (_DEBUG) && defined (_MSC_VER) #include <crtdbg.h> #endif #include <xercesc/util/PlatformUtils.hpp> #include <xercesc/util/XMLString.hpp> #include <xercesc/dom/DOM.hpp> #include <xercesc/parsers/XercesDOMParser.hpp> #include <xercesc/util/XMLException.hpp> #include <xercesc/util/XMLUri.hpp> #include <xercesc/util/XMLUni.hpp> #include <xercesc/util/Janitor.hpp> #include <xercesc/util/BinFileInputStream.hpp> #include <xercesc/framework/XMLFormatter.hpp> #include <xercesc/framework/StdOutFormatTarget.hpp> #include <xercesc/framework/LocalFileFormatTarget.hpp> XERCES_CPP_NAMESPACE_USE using std::cerr; using std::cout; using std::endl; using std::ostream; #ifdef XSEC_HAVE_XALAN // XALAN #include <xalanc/XPath/XPathEvaluator.hpp> #include <xalanc/XalanTransformer/XalanTransformer.hpp> // If this isn't defined, we're on Xalan 1.12+ and require modern C++ #ifndef XALAN_USING_XALAN # define XALAN_USING_XALAN(NAME) using xalanc :: NAME; #endif XALAN_USING_XALAN(XPathEvaluator) XALAN_USING_XALAN(XalanTransformer) #endif #if defined (XSEC_HAVE_OPENSSL) // OpenSSL # include <xsec/enc/OpenSSL/OpenSSLCryptoKeyHMAC.hpp> # include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp> # include <openssl/err.h> # include <openssl/bio.h> # include <openssl/evp.h> # include <openssl/pem.h> #endif #if defined (XSEC_HAVE_WINCAPI) # include <xsec/enc/WinCAPI/WinCAPICryptoProvider.hpp> # include <xsec/enc/WinCAPI/WinCAPICryptoSymmetricKey.hpp> # include <xsec/enc/WinCAPI/WinCAPICryptoKeyHMAC.hpp> #endif #if defined (XSEC_HAVE_NSS) # include <xsec/enc/NSS/NSSCryptoProvider.hpp> # include <xsec/enc/NSS/NSSCryptoSymmetricKey.hpp> # include <xsec/enc/NSS/NSSCryptoKeyHMAC.hpp> #endif #include <time.h> #ifndef XSEC_HAVE_XALAN std::ostream& operator<< (std::ostream& target, const XMLCh * s) { char *p = XMLString::transcode(s); target << p; XSEC_RELEASE_XMLCH(p); return target; } #endif // ---------------------------------------------------------------------------- // Checksig // ---------------------------------------------------------------------------- void printUsage(void) { cerr << "\nUsage: cipher [options] <input file name>\n\n"; cerr << " Where options are :\n\n"; cerr << " --decrypt/-d\n"; cerr << " Operate in decrypt mode (default) - outputs the decrypted octet stream\n"; cerr << " Reads in the input file as an XML file, searches for an EncryptedData node\n"; cerr << " and decrypts the content\n"; cerr << " --decrypt-element/-de\n"; cerr << " Operate in decrypt and XML mode.\n"; cerr << " This will output the original XML document with the first encrypted\n"; cerr << " element decrypted.\n"; cerr << " --encrypt-file/-ef\n"; cerr << " Encrypt the contents of the input file as raw data and create an\n"; cerr << " XML Encrypted Data outpu\n"; cerr << " --encrypt-xml/-ex\n"; cerr << " Parse the input file and encrypt the doc element down, storing the\n"; cerr << " output as a XML Encrypted Data\n"; cerr << " --key/-k [kek] <KEY_TYPE> [options]\n"; cerr << " Set the key to use.\n"; cerr << " If the first parameter is \"kek\", the key arguments will be used\n"; cerr << " as a Key EncryptionKey\n"; cerr << " KEY_TYPE defines what the key is. Can be one of :\n"; cerr << " X509, RSA, AES128, AES192, AES256, AES128-GCM, AES192-GCM, AES256-GCM or 3DES\n"; cerr << " options are :\n"; cerr << " <filename> - for X509 PEM files (must be an RSA KEK certificate\n"; cerr << " <filename> <password> - for RSA private key files (MUST be a KEK)\n"; cerr << " <key-string> - For a string to use as the key for AES or DES keys\n"; #ifdef XSEC_XKMS_ENABLED cerr << " --xkms/-x\n"; cerr << " The key that follows on the command line is to be interpreted as\n"; cerr << " an XKMS RSAKeyPair encryption key\n"; #endif cerr << " --interop/-i\n"; cerr << " Use the interop resolver for Baltimore interop examples\n"; cerr << " --out-file/-o\n"; cerr << " Output the result to the indicated file (rather than stdout)\n"; #ifdef XSEC_HAVE_WINCAPI cerr << " --wincapi/-w\n"; cerr << " Force use of Windows Crypto API\n"; #endif #ifdef XSEC_HAVE_NSS cerr << " --nss/-n\n"; cerr << " Force use of NSS Crypto API\n"; #endif cerr << "\n Exits with codes :\n"; cerr << " 0 = Decrypt/Encrypt OK\n"; cerr << " 1 = Decrypt/Encrypt failed\n"; cerr << " 2 = Processing error\n"; } int evaluate(int argc, char ** argv) { char * filename = NULL; char * outfile = NULL; unsigned char * keyStr = NULL; bool doDecrypt = true; bool errorsOccured = false; bool doDecryptElement = false; bool useInteropResolver = false; bool encryptFileAsData = false; bool parseXMLInput = true; bool doXMLOutput = false; #ifdef XSEC_XKMS_ENABLED bool isXKMSKey = false; #endif XSECCryptoKey * kek = NULL; XSECCryptoKey * key = NULL; int keyLen = 0; const XMLCh* kekAlg = NULL; const XMLCh* keyAlg = NULL; DOMDocument *doc; unsigned char keyBuf[24]; XMLFormatTarget *formatTarget ; #if defined(_WIN32) && defined (XSEC_HAVE_WINCAPI) HCRYPTPROV win32DSSCSP = 0; // Crypto Providers HCRYPTPROV win32RSACSP = 0; CryptAcquireContext(&win32DSSCSP, NULL, NULL, PROV_DSS, CRYPT_VERIFYCONTEXT); CryptAcquireContext(&win32RSACSP, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); #endif if (argc < 2) { printUsage(); return 2; } // Run through parameters int paramCount = 1; while (paramCount < argc - 1) { if (_stricmp(argv[paramCount], "--decrypt-element") == 0 || _stricmp(argv[paramCount], "-de") == 0) { paramCount++; doDecrypt = true; doDecryptElement = true; doXMLOutput = true; parseXMLInput = true; } else if (_stricmp(argv[paramCount], "--interop") == 0 || _stricmp(argv[paramCount], "-i") == 0) { // Use the interop key resolver useInteropResolver = true; paramCount++; } else if (_stricmp(argv[paramCount], "--encrypt-file") == 0 || _stricmp(argv[paramCount], "-ef") == 0) { // Use this file as the input doDecrypt = false; encryptFileAsData = true; doXMLOutput = true; parseXMLInput = false; paramCount++; } else if (_stricmp(argv[paramCount], "--encrypt-xml") == 0 || _stricmp(argv[paramCount], "-ex") == 0) { // Us this file as an XML input file doDecrypt = false; encryptFileAsData = false; doXMLOutput = true; parseXMLInput = true; paramCount++; } else if (_stricmp(argv[paramCount], "--out-file") == 0 || _stricmp(argv[paramCount], "-o") == 0) { if (paramCount +2 >= argc) { printUsage(); return 1; } paramCount++; outfile = argv[paramCount]; paramCount++; } #ifdef XSEC_XKMS_ENABLED else if (_stricmp(argv[paramCount], "--xkms") == 0 || _stricmp(argv[paramCount], "-x") == 0) { paramCount++; isXKMSKey = true; } #endif #ifdef XSEC_HAVE_WINCAPI else if (_stricmp(argv[paramCount], "--wincapi") == 0 || _stricmp(argv[paramCount], "-w") == 0) { // Use the interop key resolver WinCAPICryptoProvider * cp = new WinCAPICryptoProvider(); XSECPlatformUtils::SetCryptoProvider(cp); paramCount++; } #endif #ifdef XSEC_HAVE_NSS else if (_stricmp(argv[paramCount], "--nss") == 0 || _stricmp(argv[paramCount], "-n") == 0) { // NSS Crypto Provider NSSCryptoProvider * cp = new NSSCryptoProvider(); XSECPlatformUtils::SetCryptoProvider(cp); paramCount++; } #endif else if (_stricmp(argv[paramCount], "--key") == 0 || _stricmp(argv[paramCount], "-k") == 0) { // Have a key! paramCount++; bool isKEK = false; XSECCryptoSymmetricKey::SymmetricKeyType loadKeyAs = XSECCryptoSymmetricKey::KEY_NONE; if (_stricmp(argv[paramCount], "kek") == 0) { isKEK = true; paramCount++; if (paramCount >= argc) { printUsage(); return 2; } } if (_stricmp(argv[paramCount], "3DES") == 0 || _stricmp(argv[paramCount], "AES128") == 0 || _stricmp(argv[paramCount], "AES192") == 0 || _stricmp(argv[paramCount], "AES256") == 0 || _stricmp(argv[paramCount], "AES128-GCM") == 0 || _stricmp(argv[paramCount], "AES192-GCM") == 0 || _stricmp(argv[paramCount], "AES256-GCM") == 0) { if (paramCount +2 >= argc) { printUsage(); return 2; } switch(argv[paramCount][4]) { case '\0' : keyLen = 24; loadKeyAs = XSECCryptoSymmetricKey::KEY_3DES_192; keyAlg = DSIGConstants::s_unicodeStrURI3DES_CBC; break; case '2' : keyLen = 16; loadKeyAs = XSECCryptoSymmetricKey::KEY_AES_128; if (isKEK) { kekAlg = DSIGConstants::s_unicodeStrURIKW_AES128; } else if (strlen(argv[paramCount]) == 6) { keyAlg = DSIGConstants::s_unicodeStrURIAES128_CBC; } else { keyAlg = DSIGConstants::s_unicodeStrURIAES128_GCM; } break; case '9' : keyLen = 24; loadKeyAs = XSECCryptoSymmetricKey::KEY_AES_192; if (isKEK) { kekAlg = DSIGConstants::s_unicodeStrURIKW_AES192; } else if (strlen(argv[paramCount]) == 6) { keyAlg = DSIGConstants::s_unicodeStrURIAES192_CBC; } else { keyAlg = DSIGConstants::s_unicodeStrURIAES192_GCM; } break; case '5' : keyLen = 32; loadKeyAs = XSECCryptoSymmetricKey::KEY_AES_256; if (isKEK) { kekAlg = DSIGConstants::s_unicodeStrURIKW_AES256; } else if (strlen(argv[paramCount]) == 6) { keyAlg = DSIGConstants::s_unicodeStrURIAES256_CBC; } else { keyAlg = DSIGConstants::s_unicodeStrURIAES256_GCM; } break; } paramCount++; unsigned char keyStr[64]; if (strlen(argv[paramCount]) > 64) { cerr << "Key string too long\n"; return 2; } XSECCryptoSymmetricKey * sk = XSECPlatformUtils::g_cryptoProvider->keySymmetric(loadKeyAs); #ifdef XSEC_XKMS_ENABLED if (isXKMSKey) { unsigned char kbuf[XSEC_MAX_HASH_SIZE]; CalculateXKMSKEK((unsigned char *) argv[paramCount], (int) strlen(argv[paramCount]), kbuf, XSEC_MAX_HASH_SIZE); sk->setKey(kbuf, keyLen); } else { #endif memset(keyStr, 0, 64); strcpy((char *) keyStr, argv[paramCount]); sk->setKey(keyStr, keyLen); #ifdef XSEC_XKMS_ENABLED } #endif paramCount++; if (isKEK) kek = sk; else key = sk; } #ifdef XSEC_HAVE_OPENSSL else if (_stricmp(argv[paramCount], "RSA") == 0) { // RSA private key file if (paramCount + 3 >= argc) { printUsage(); return 2; } if (!isKEK) { cerr << "RSA private keys may only be KEKs\n"; return 2; } BIO * bioKey; if ((bioKey = BIO_new(BIO_s_file())) == NULL) { cerr << "Error opening private key file\n\n"; return 1; } if (BIO_read_filename(bioKey, argv[paramCount + 1]) <= 0) { cerr << "Error opening private key file\n\n"; return 1; } EVP_PKEY * pkey; pkey = PEM_read_bio_PrivateKey(bioKey,NULL,NULL,argv[paramCount + 2]); if (pkey == NULL) { cerr << "Error loading private key\n\n"; return 1; } kek = new OpenSSLCryptoKeyRSA(pkey); kekAlg = DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1; EVP_PKEY_free(pkey); BIO_free(bioKey); paramCount += 3; } else if (_stricmp(argv[paramCount], "X509") == 0) { // X509 cert used to load an encrypting key if (paramCount + 2 >= argc) { printUsage(); exit (1); } if (!isKEK) { cerr << "X509 private keys may only be KEKs\n"; return 2; } // Load the encrypting key // For now just read a particular file BIO * bioX509; if ((bioX509 = BIO_new(BIO_s_file())) == NULL) { cerr << "Error opening file\n\n"; exit (1); } if (BIO_read_filename(bioX509, argv[paramCount + 1]) <= 0) { cerr << "Error opening X509 Certificate " << argv[paramCount + 1] << "\n\n"; exit (1); } X509 * x ; x = PEM_read_bio_X509_AUX(bioX509,NULL,NULL,NULL); if (x == NULL) { BIO * bio_err; if ((bio_err=BIO_new(BIO_s_file())) != NULL) BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT); cerr << "Error loading certificate key\n\n"; ERR_print_errors(bio_err); BIO_free(bio_err); exit (1); } // Now load the key EVP_PKEY *pkey; pkey = X509_get_pubkey(x); #ifdef XSEC_OPENSSL_HAVE_EVP_PKEY_ID if (pkey == NULL || EVP_PKEY_id(pkey) != EVP_PKEY_RSA) #else if (pkey == NULL || pkey->type != EVP_PKEY_RSA) #endif { cerr << "Error extracting RSA key from certificate" << endl; } kek = new OpenSSLCryptoKeyRSA(pkey); kekAlg = DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1; // Clean up EVP_PKEY_free (pkey); X509_free(x); BIO_free(bioX509); paramCount += 2; } /* argv[1] = "--x509cert" */ #endif /* XSEC_HAVE_OPENSSL */ else { printUsage(); return 2; } } else { cerr << "Unknown option: " << argv[paramCount] << endl; printUsage(); return 2; } } if (paramCount >= argc) { printUsage(); return 2; } if (outfile != NULL) { formatTarget = new LocalFileFormatTarget(outfile); } else { formatTarget = new StdOutFormatTarget(); } filename = argv[paramCount]; if (parseXMLInput) { XercesDOMParser * parser = new XercesDOMParser; Janitor<XercesDOMParser> j_parser(parser); parser->setDoNamespaces(true); parser->setCreateEntityReferenceNodes(true); // Now parse out file XMLSize_t errorCount = 0; try { parser->parse(filename); errorCount = parser->getErrorCount(); if (errorCount > 0) errorsOccured = true; } catch (const XMLException& e) { cerr << "An error occurred during parsing\n Message: " << e.getMessage() << endl; errorsOccured = true; } catch (const DOMException& e) { cerr << "A DOM error occurred during parsing\n DOMException code: " << e.code << endl; errorsOccured = true; } if (errorsOccured) { cout << "Errors during parse" << endl; return (2); } /* Now that we have the parsed file, get the DOM document and start looking at it */ doc = parser->adoptDocument(); } else { // Create an empty document XMLCh tempStr[100]; XMLString::transcode("Core", tempStr, 99); DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr); doc = impl->createDocument( 0, // root element namespace URI. MAKE_UNICODE_STRING("ADoc"), // root element name NULL);// DOMDocumentType()); // document type object (DTD). } XSECProvider prov; XENCCipher * cipher = prov.newCipher(doc); if (kek != NULL) cipher->setKEK(kek); if (key != NULL) cipher->setKey(key); try { if (doDecrypt) { if (useInteropResolver == true) { // Map out base path of the file #ifdef XSEC_HAVE_GETCWD_DYN char *path = getcwd(NULL, 0); char *baseURI = (char*)malloc(strlen(path) + 8 + 1 + strlen(filename) + 1); #else char path[PATH_MAX]; char baseURI[(PATH_MAX * 2) + 10]; getcwd(path, PATH_MAX); #endif strcpy(baseURI, "file:///"); // Ugly and nasty but quick if (filename[0] != '\\' && filename[0] != '/' && filename[1] != ':') { strcat(baseURI, path); strcat(baseURI, "/"); } else if (path[1] == ':') { path[2] = '\0'; strcat(baseURI, path); } strcat(baseURI, filename); // Find any ':' and "\" characters int lastSlash = 0; for (unsigned int i = 8; i < strlen(baseURI); ++i) { if (baseURI[i] == '\\') { lastSlash = i; baseURI[i] = '/'; } else if (baseURI[i] == '/') lastSlash = i; } // The last "\\" must prefix the filename baseURI[lastSlash + 1] = '\0'; XMLCh * uriT = XMLString::transcode(baseURI); #ifdef XSEC_HAVE_GETCWD_DYN free(path); free(baseURI); #endif XencInteropResolver ires(doc, &(uriT[8])); XSEC_RELEASE_XMLCH(uriT); cipher->setKeyInfoResolver(&ires); } // Find the EncryptedData node DOMNode * n = findXENCNode(doc, "EncryptedData"); if (doDecryptElement) { while (n != NULL) { // decrypt cipher->decryptElement(static_cast<DOMElement *>(n)); // Find the next EncryptedData node n = findXENCNode(doc, "EncryptedData"); } } else { XSECBinTXFMInputStream * bis = cipher->decryptToBinInputStream(static_cast<DOMElement *>(n)); Janitor<XSECBinTXFMInputStream> j_bis(bis); XMLByte buf[1024]; XMLSize_t read = bis->readBytes(buf, 1023); while (read > 0) { formatTarget->writeChars(buf, read, NULL); read = bis->readBytes(buf, 1023); } } } else { XENCEncryptedData *xenc = NULL; // Encrypting if (kek != NULL && key == NULL) { XSECPlatformUtils::g_cryptoProvider->getRandom(keyBuf, 24); XSECCryptoSymmetricKey * k = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_3DES_192); k->setKey(keyBuf, 24); cipher->setKey(k); keyAlg = DSIGConstants::s_unicodeStrURI3DES_CBC; keyStr = keyBuf; keyLen = 24; } if (encryptFileAsData) { // Create a BinInputStream BinFileInputStream * is = new BinFileInputStream(filename, XMLPlatformUtils::fgMemoryManager); xenc = cipher->encryptBinInputStream(is, keyAlg); // Replace the document element DOMElement * elt = doc->getDocumentElement(); doc->replaceChild(xenc->getElement(), elt); elt->release(); } else { // Document encryption cipher->encryptElement(doc->getDocumentElement(), keyAlg); } // Do we encrypt a created key? if (kek != NULL && xenc != NULL) { XENCEncryptedKey *xkey = cipher->encryptKey(keyStr, keyLen, kekAlg); // Add to the EncryptedData xenc->appendEncryptedKey(xkey); } } if (doXMLOutput) { // Output the result XMLCh core[] = { XERCES_CPP_NAMESPACE_QUALIFIER chLatin_C, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_o, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_r, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_e, XERCES_CPP_NAMESPACE_QUALIFIER chNull }; DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(core); DOMLSSerializer *theSerializer = ((DOMImplementationLS*)impl)->createLSSerializer(); Janitor<DOMLSSerializer> j_theSerializer(theSerializer); // Get the config so we can set up pretty printing DOMConfiguration *dc = theSerializer->getDomConfig(); dc->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, false); // Now create an output object to format to UTF-8 DOMLSOutput *theOutput = ((DOMImplementationLS*)impl)->createLSOutput(); Janitor<DOMLSOutput> j_theOutput(theOutput); theOutput->setEncoding(MAKE_UNICODE_STRING("UTF-8")); theOutput->setByteStream(formatTarget); theSerializer->write(doc, theOutput); cout << endl; } } catch (const XSECException &e) { char * msg = XMLString::transcode(e.getMsg()); cerr << "An error occurred during encryption/decryption operation\n Message: " << msg << endl; XSEC_RELEASE_XMLCH(msg); errorsOccured = true; if (formatTarget != NULL) delete formatTarget; doc->release(); return 2; } catch (const XSECCryptoException &e) { cerr << "An error occurred during encryption/decryption operation\n Message: " << e.getMsg() << endl; errorsOccured = true; if (formatTarget != NULL) delete formatTarget; doc->release(); #ifdef XSEC_HAVE_OPENSSL ERR_load_crypto_strings(); BIO * bio_err; if ((bio_err=BIO_new(BIO_s_file())) != NULL) BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT); ERR_print_errors(bio_err); #endif return 2; } if (formatTarget != NULL) delete formatTarget; doc->release(); return 0; } int main(int argc, char **argv) { int retResult; #if defined (_DEBUG) && defined (_MSC_VER) // Do some memory debugging under Visual C++ _CrtMemState s1, s2, s3; // At this point we are about to start really using XSEC, so // Take a "before" checkpoing _CrtMemCheckpoint( &s1 ); #endif // Initialise the XML system try { XMLPlatformUtils::Initialize(); #ifdef XSEC_HAVE_XALAN XPathEvaluator::initialize(); XalanTransformer::initialize(); #endif XSECPlatformUtils::Initialise(); } catch (const XMLException &e) { cerr << "Error during initialisation of Xerces" << endl; cerr << "Error Message = : " << e.getMessage() << endl; } retResult = evaluate(argc, argv); XSECPlatformUtils::Terminate(); #ifdef XSEC_HAVE_XALAN XalanTransformer::terminate(); XPathEvaluator::terminate(); #endif XMLPlatformUtils::Terminate(); #if defined (_DEBUG) && defined (_MSC_VER) _CrtMemCheckpoint( &s2 ); if ( _CrtMemDifference( &s3, &s1, &s2 ) && ( s3.lCounts[0] > 0 || s3.lCounts[1] > 1 || // s3.lCounts[2] > 2 || We don't worry about C Runtime s3.lCounts[3] > 0 || s3.lCounts[4] > 0)) { // Note that there is generally 1 Normal and 1 CRT block // still taken. 1 is from Xalan and 1 from stdio // Send all reports to STDOUT _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE ); _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT ); _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE ); _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT ); _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE ); _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT ); // Dumpy memory stats _CrtMemDumpAllObjectsSince( &s3 ); _CrtMemDumpStatistics( &s3 ); } // Now turn off memory leak checking and end as there are some // Globals that are allocated that get seen as leaks (Xalan?) int dbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); dbgFlag &= ~(_CRTDBG_LEAK_CHECK_DF); _CrtSetDbgFlag( dbgFlag ); #endif return retResult; }