Loading Blowfish-Encrypted Data Into an MSXML2 DOM Object

When using the MSXML2 library, you typically load XML files from disk into a DOM (Document Object Model) object by creating an instance of IXMLDOMDocument and calling its load function—where you pass a BSTR reprentation of the file name. However, I had a situation recently where—due to security concerns—I needed to first decrypt the XML data in memory and then load that memory (without writing it to disk) into a DOM object. Surprisingly, I wasn't able to find any open source examples of how to do this, so I wrote a couple of helper functions to accomplish this task. Hopefully, these functions will help others who run into a similar situation.

Before I continue, I should state that since Bruce Schneier introduced the Blowfish encryption algorithm to the computer industry in 1993, there have been many implementations. I've personally found George Anescu's work to be especially easy to use in scenarios where I've needed a fast and reliable encryption means of encrypting and decrypting data. Therefore, my functions work with data that is encrypted using his CBlowFish class.

The first thing I learned when searching for a solution is that the IXMLDOMDocument object supports a function called loadXML that takes a BSTR value representing the XML to parse. Anyone familiar with my coding style knows that I like to keep the client side of things as easy and clean as possible. Therefore, I wanted a single function that the client could call that would pretty much do everything. As a result, I created the DecryptFile2Bstr function (shown below) that takes an input file name and password (both char pointers) and returns a BSTR that then can be used with the IXMLDOMDocument::loadXML function.

As you can see, the DecryptFile2Bstr function instantiates a CBlowFish object and then calls another helper function I wrote—GetFormattedFileContent—before invoking the CBlowFish::Decrypt function. As the data used by both the GetFormattedFileContent and CBlowFish::Decrypt functions is in the form of a char buffer, the DecryptFile2Bstr function calls the standard COM utility function ConvertStringToBSTR before returning to the caller.

BSTR DecryptFile2Bstr(char* inputFileName, char* password)
{
  try
  {
    int requiredFileSize;
    CBlowFish oBlowFish((unsigned char*)password, sizeof(password));
    char *buffer = GetFormattedFileContent( inputFileName,
                                            requiredFileSize );

    oBlowFish.Decrypt((unsigned char *)buffer, requiredFileSize);

    return _com_util::ConvertStringToBSTR(buffer);
  }
  catch ( char *ex )
  {
    throw ex;
  }
}

The Blowfish algorithm is based on 8-byte blocks so the GetFormattedFileContent function reads the data into memory accordingly. Note the padding at the end of the function to accomodate this rule.

char* GetFormattedFileContent(char *filePath, int &requiredFileSize)
{
  FILE *fp = fopen(filePath, "r+b");

  int fileSize = FileSize(fp);
  int index = fileSize;

  if ( (fileSize % 8) != 0 )
    requiredFileSize = ((fileSize / 8) + 1) * 8;
  else
    requiredFileSize = fileSize;

  char *buffer = new char[requiredFileSize + 1];
  fread(buffer, sizeof(char), fileSize, fp);
  buffer[fileSize] = 0;
  fclose(fp);
  while (index < requiredFileSize)
    buffer[index++] = 0;

  return buffer;
}

int FileSize(FILE *fp)
{
  char buffer[1];
  int count = 0;
  fseek(fp, 0, SEEK_SET);
  while (fread(buffer, sizeof(buffer), 1, fp) != 0) count++;
    fseek(fp, 0, SEEK_SET);
  return count;
}

Using the DecryptFile2Bstr Function

Assuming that your data has been encrypted by using the CBlowFish class, you can load it into an XML DOM object with two lines of code:

#import <msxml4.dll& named_guids
using namespace MSXML2;

...

::CoInitialize(NULL);

MSXML2::IXMLDOMDocumentPtr plDomDocument;

HRESULT hr = plDomDocument.CreateInstance(MSXML2::CLSID_DOMDocument);
if (SUCCEEDED(hr))
{
  // load the file as an XML document
  BSTR xmlfile = DecryptFile2Bstr(L"MyFile.xml", DEFS_ENC_PASSWORD);
  variant_t vResult = plDomDocument->loadXML(xmlfile);
  
  ...  

Looking Ahead

Combining the MSMXL2 IXMLDOMDocument::loadXML with my helper functions I was able to read the client's sensitive data into memory and decrypt it without first having to decrypt it to disk. I've also extended these functions to include other helper functions that perform such tasks as decrypting a file with CBlowFish-encrypted data to a specified file (DecryptFile2File) and encrypting a plain ASCII data to a CBlowFish-encrypted file (EncryptFile2File). If there's any need or interest in these functions, I'll also post them for public use.



About the Author

Tom Archer - MSFT

I am a Program Manager and Content Strategist for the Microsoft MSDN Online team managing the Windows Vista and Visual C++ developer centers. Before being employed at Microsoft, I was awarded MVP status for the Visual C++ product. A 20+ year veteran of programming with various languages - C++, C, Assembler, RPG III/400, PL/I, etc. - I've also written many technical books (Inside C#, Extending MFC Applications with the .NET Framework, Visual C++.NET Bible, etc.) and 100+ online articles.

Downloads

Comments

  • tell me why

    Posted by JayBus on 06/23/2005 10:17am

    Tom,
    
    why not:
    "BSTR DecryptFile2Bstr( const char* inputFileName, const char* password)"? There are "never" too many const-s.
    
    Why int FileSize(FILE *fp) so complex (and slow) instead of:
    
    inline int FileSize(FILE *fp)
    { 
      fseek(fp, 0, SEEK_END);
      int count = ftell(fp);
      fseek(fp, 0, SEEK_SET);
      return count;
    }

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

  • Live Event Date: September 10, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild". This loop of continuous delivery and continuous feedback is …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds