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.


Archive Encryption Key Security Options

Your data is not encrypted with the security you’ve chosen; rather, the security method is used to protect the encryption key that encrypts your data. Think of a key that is locked inside a safe. Your security method (also know as the public key) is the information that unlocks the safe, which contains the key (also known as the private key) that unlocks your data. In other words, your public key protects your private key.

You have these options for securing your archive encryption key:

  • account password – default
  • private password – another password to use instead of account password
  • personal private key – a private key you create that replaces the default private key

Each of the encryption key security options offers increasingly greater security, and correspondingly greater risk for forgetting. In other words, using your account password to secure your data is the simplest method and the easiest for others to penetrate. Using a private password adds another layer of security, but it is another password to remember.

Once you have upgraded your encryption key option, you cannot downgrade to another option. This prevents someone from recovering your lost or stolen computer and using CrashPlan to downgrade your security.

Securing Your Encryption Key with Your Account Password

Using your account password to secure your encryption is the simplest method to use, but the easiest for others to penetrate.

  • Default encryption key security option
  • Private key is stored on the server and on source computer
  • Public key uses your account password to protect your private key
  • Public key and private key are stored on the server for web restore
  • Public key is stored on the destination for guest restore
  • Admins can restore without password, allowing easy local fast restore

Securing Your Encryption Key with a Private Password

You can specify to use a private password, which is different from your account password, to secure your encryption key. Securing your encryption key with another password offers another level of security; however, you increase the risk to your archive because there is no way to retrieve the private password if you forget it.

  • Upgraded security
  • Private key is stored on and never leaves source computer
  • Public key uses a private-password to protect your private key
  • Public key is stored on the server for web restore and for new installations
  • Public key is stored on the destination for guest restore
  • Admins need private password to restore
  • Additional password to remember, risk not being able to restore if forgotten

Your Private Encryption Key

You can specify to replace the default encryption key with a private key to encrypt your archive. This is the most secure option, but it requires the most user management because you must provide your private key every time you restore.

  • Highest upgraded security
  • Private key is stored on and never leaves source computer
  • Manage your own private key per computer, with each computer under this account theoretically using a different private key
  • Web restore, guest restore, new installations, remote restore, etc. require the private key
  • Admins need private key to restore
  • Additional information to keep track of, with increased risk of not being able to restore if lost

Generating Your Private Key

You can create your private key in several ways:

  • Enter a passphrase that returns a private key and then paste the key into the encryption key box
  • Allow CrashPlan to generate a private encryption key for you without entering any text (just click the Generate option)
  • Import an encryption key that has been saved to a text file (e.g. an SSH private key)

Importing and Exporting the Private Key Once you’ve selected the method for generating your private key; you can use the Export option to export the key to a text file. Exporting the private key to a file makes it easier to locate the key in case you forget it. When you need to supply the private key on another computer to which you want to recover files, you can use the Import option to import the encryption key from the text file.

All data previously backed up and associated with the previous method’s encryption key is no longer available for restoring.