Shoeisha Technology Media

CodeZine(コードジン)

記事種別から探す

Blowfish暗号化データをMSXML2 DOMオブジェクトに直接ロードする

暗号化されたXMLデータをディスクに書き出さずに復号する方法

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2005/09/02 12:00

本稿では、MSMXL2ライブラリのIXMLDOMDocument::loadXMLと、自作のヘルパー関数を組み合わせることにより、Blowfishで暗号化されたクライアントの機密データをメモリに読み込んで復号し、ディスクへ書き出すことなくDOMオブジェクトにロードする方法を解説します。

はじめに

 MSXML2ライブラリを使用するときは、通常は、IXMLDOMDocumentのインスタンスを生成し、そのload関数を呼び出す(ここでファイル名のBSTR表現を引き渡す)ことで、XMLファイルをディスクからDOM(Document Object Model)オブジェクトにロードします。しかし、私は最近、セキュリティ上の問題から、まずメモリ内でXMLデータを復号してからそのメモリを(ディスクに書き出さずに)DOMオブジェクトにロードしなければならない、という事態に遭遇しました。私はオープンソースの例の中からこれを行う方法を探したのですが、意外にも見つけることができませんでした。そこで、このタスクを行うためのいくつかのヘルパー関数を作成しました。私と同じような状況に置かれた他の人々にも役立つと思うので、ここで紹介させてもらいます。

DecryptFile2Bstrヘルパー関数

 説明を続ける前に、1993年にBruce Schneier氏がBlowfish暗号化アルゴリズムを発表して以来、多くの実装が登場していることを述べなければなりません。私は、高速で信頼できるデータ暗号化/復号のための暗号化手段を必要としていたのですが、その目的にはGeorge Anescu氏による実装を使用するのが特に簡単であると思いました。そのため、私の関数は、George Anescu氏によるCBlowFishクラスを使用して暗号化されたデータを扱うようにできています。

 私が解決策を探しているときに最初に学んだことは、IXMLDOMDocumentオブジェクトがloadXMLという関数をサポートしており、この関数は解析対象のXMLを表すBSTR値を取るということです。クライアント側をできるだけ簡潔にする、というのが私のコーディングスタイルなので、今回も、クライアント側から呼び出せる1つの関数で、ほとんどすべてのことを行わせたいと考えていました。そこで作成したのが、入力ファイル名とパスワード(どちらもcharポインタ)を取り、BSTR値を戻すDecryptFile2Bstr関数です(下記参照)。戻されたBSTR値は、IXMLDOMDocument::loadXML関数で使用することができます。

 下記のコードからわかるとおり、DecryptFile2Bstr関数はCBlowFishオブジェクトをインスタンス化した後、CBlowFish::Decryptを呼び出す前に、私が作成したもう1つのヘルパー関数であるGetFormattedFileContentを呼び出します。GetFormattedFileContent関数とCBlowFish::Decrypt関数の両方に使用されるデータがcharバッファという形式なので、DecryptFile2Bstr関数は呼び出し元に戻る前に標準COMユーティリティ関数ConvertStringToBSTRを呼び出します。

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

 Blowfishアルゴリズムは8バイトのブロックをベースとするため、GetFormattedFileContent関数はそのブロック単位でデータをメモリに読み込みます。このルールに適合させるために、関数の最後でパディングを行っていることに注目してください。

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

DecryptFile2Bstr関数の使用

 データがCBlowFishクラスを使用して暗号化されている場合は、下記の太字で示した2行のコードで、そのデータをXML DOMオブジェクトにロードすることができます。

#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 = DecryptFile2Bstr(L"MyFile.xml", DEFS_ENC_PASSWORD);
  variant_t vResult = plDomDocument->loadXML(xmlfile);

  ...

今後について

 MSMXL2 IXMLDOMDocument::loadXMLを私のヘルパー関数と組み合わせることにより、ディスクへの復号を行うことなく、クライアントの機密データをメモリに読み込み、復号することができました。また、これらの関数を拡張し、CBlowFishで暗号化されたデータを持つファイルを指定ファイルに復号するヘルパー関数(DecryptFile2File)や、プレーンASCIIデータをCBlowFishで暗号化されたファイルにするヘルパー関数(EncryptFile2File)などを組み込めるようにしました。もしこれらの関数を必要としている方、あるいは興味をお持ちの方がいましたら、これらも公開しようと思います。



  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • Tom Archer(Tom Archer)

    .NETプログラマの教育・指導、プロジェクト管理コンサルティングを専門とする研修会社、Archer Consulting Groupを経営。同社がどのように貴社の開発コストを削減させ、ソフトウェアを市場に早く送り出し、製品からの収入を増やすのに役立ってくれるのかを知りたい場合は、同社のWebサイトを...

  • japan.internet.com(ジャパンインターネットコム)

    japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.com や EarthWeb.c...

バックナンバー

連載:japan.internet.com翻訳記事

もっと読む

All contents copyright © 2005-2017 Shoeisha Co., Ltd. All rights reserved. ver.1.5