Live Journal about blowfish |

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 representation 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 the task. Hopefully, these functions will help others that run into a similar situation.

Since Bruce Schneier introduced the Blowfish encryption algorithm in 1993, its had many implementations. I’ve personally found George Anescu’s work to be especially easy to use in scenarios where I’ve needed fast and reliable 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, which takes a BSTR value representing the XML to parse. Since I like to keep the client side as easy and clean as possible, I wanted the client to call a single function that would pretty much do everything. As a result, I created the DecryptFile2Bstr function, which takes an input file name and password (both char pointers) and returns a BSTR that can then be used with the IXMLDOMDocument::loadXML function:

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;
  }
}

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.

The Blowfish algorithm is based on eight-byte blocks, so the GetFormattedFileContent function reads the data into memory accordingly. Note the padding at the end of the function to accommodate 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 your data has been encrypted 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 plain ASCII data to a CBlowFish-encrypted file (EncryptFile2File). If you have any need or interest in these functions, email me and I’ll also post them for public use.


Understanding Encryption

To ensure that your private data stays private, CrashPlan encrypts your files before transport, with no dependency on destination or Internet security. CrashPlan+ / CrashPlan PRO uses 448-bit Blowfish encryption; CrashPlan (the free version) uses 128-bit Blowfish, the same 128-bit encryption that online banking and most businesses use.

“128” and “448” refer to the length of the encryption key. The longer the key, the harder it is to decrypt data.

Blowfish is an encryption algorithm. It’s a freely available, documented and open method of encrypting data. Being Open is very important, because it means that it uses public processes that can be tested by everyone and as a result, proven to be secure. Blowfish was invented by a security expert named Bruce Schneier.

We escrow the encryption key to protect you in case your computer is lost or stolen. Because only you (the customer) knows the private password, no one else can restore your files. In the event that you need to reinstall CrashPlan, your configuration settings are pulled from our server, including your locked encryption key.

CrashPlan’s servers maintain this encryption key, so it is transferred securely with the same encryption technology used to encrypt data during backup. The encryption is stored as part of your CrashPlan configuration settings and in the archive.

Considerations

  • Your private key is never cached or stored on any remote location. It is stored on the source computer that is being backed up. Your data is encrypted with the key on the source computer, so that CrashPlan can back up without prompting.
  • CrashPlan uses the same key for restoring files.
  • Unless you replace the archive encryption key with your own private key, the encryption key doesn’t change. This means that you can still restore versions of files associated with the original password. If you change your password, CrashPlan locks the encryption key with the new password.
  • Your private password or private key is never sent to CrashPlan, and therefore CrashPlan Support cannot obtain the password or key for you if you lose it. You won’t be able to restore the data that has already been backed up without the private password, and you will need to restart your backup from scratch.
  • If you really must downgrade your security, you will have to create a new account and start over. If you want to does this under the same email address, email support to disable your account.