はじめに

.NET Frameworkには暗号を扱うクラスが提供されております。これらのクラスを使用することで暗号にかかる様々な処理を容易に実装できるようになります。鍵を管理するキーコンテナもこれらのクラスを利用することで容易に利用できます。
キーコンテナの使用は、暗号に必要な鍵(殊に秘密鍵)を比較的安全に保管してくれる良い方法と考えますがマシンがクラッシュした際の対処方法を検討しておかないと暗号文を復号できないトラブルに発展してしまう可能性があります。
今回はマシンがクラッシュした場合を想定して、キーコンテナに格納された鍵を別のマシンに移行する手段を検討することにします。

鍵の生成とエクスポート

キーコンテナを利用して鍵を生成する方法は非常にシンプルです。
以下のようにするだけです。


        // CspParametersオブジェクトの作成
        CspParameters cp = new CspParameters();
        // キーコンテナを参照するときの名前を指定する
        cp.KeyContainerName = @"キーコンテナを参照するときの名称";
        // CspParametersを指定してRSACryptoServiceProviderオブジェクトを作成
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp);
    

次に公開鍵をエクスポートするには以下のようにToXmlString()メソッドにfalseを渡して得られた文字列をファイルに書き出すだけです。


        // SaveFileDialog オブジェクト作成
        SaveFileDialog sfd = new SaveFileDialog();
        // ファイル名の初期値を指定する
        sfd.FileName = "ファイル名";
        // 選択肢を指定する
        sfd.Filter = "XMLファイル(*.xml)|*.xml|すべてのファイル(*.*)|*.*";
        //タイトルを設定する
        sfd.Title = "保存する公開鍵のファイルを選択してください。";
        // ダイアログボックスを閉じる前に現在のディレクトリを復元するようにする
        sfd.RestoreDirectory = true;
        // 既に存在するファイル名を指定したとき警告する
        sfd.OverwritePrompt = true;
        // 存在しないパスが指定されたとき警告を表示する
        sfd.CheckPathExists = true;
        // ダイアログを表示する
        if (sfd.ShowDialog() == DialogResult.OK)
        {
            // ファイルに書き込む
            using (Stream stream = sfd.OpenFile())
            using (StreamWriter sw = new StreamWriter(stream))
            {
                sw.Write(rsa.ToXmlString(false));
            }
        }
    

秘密鍵のエクスポート

次に秘密鍵をエクスポートする方法です。
こちらは、ToXmlString()メソッドに渡すパラメータをtrueに変えるだけです。
これにより公開鍵と秘密鍵が得られます。
ここで注意していただきたいことは、秘密鍵の保管です。
このファイルが漏洩してしまったら、暗号化して管理する意味がなくなってしまいます。セキュリティ機能付きのUSBメモリにファイルを移動しておき金庫の中へ...と、厳重に管理してください。

秘密鍵のインポート

ここまでの説明で秘密鍵がエクスポートされました。ここからが本題です。
ファイルにエクスポートされた秘密鍵をキーコンテナにインポートして、暗号文を復号出来ればミッション成功と考えます。
まずインポートの方法は次のように、FromXmlString()メソッドにエクスポートされた秘密鍵ファイルの値を渡します。


        // CspParametersオブジェクトの作成
        CspParameters cp = new CspParameters();
        // キーコンテナを参照するときの名前を指定する
        cp.KeyContainerName = @"キーコンテナを参照するときの名称";
        // CspParametersを指定してRSACryptoServiceProviderオブジェクトを作成
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp);

        // OpenFileDialog オブジェクト作成
        OpenFileDialog ofd = new OpenFileDialog();
        // ファイル名の初期値を指定する
        ofd.FileName = "ファイル名";
        // 選択肢を指定する
        ofd.Filter = "XMLファイル(*.xml)|*.xml|すべてのファイル(*.*)|*.*";
        // タイトルを設定する
        ofd.Title = "インポートする秘密鍵のファイルを選択してください。";
        // ダイアログボックスを閉じる前に現在のディレクトリを復元するようにする
        ofd.RestoreDirectory = true;
        // ダイアログを表示する
        if (ofd.ShowDialog() == DialogResult.OK)
        {
            // 非対称鍵ペアをインポート
            rsa.FromXmlString(File.ReadAllText(ofd.FileName));
        }
    

動作確認

それでは動作確認をしてみましょう。
1台のマシンで動作確認を行うのであれば、キーコンテナを参照するときの名前を変えることで確認できます。
例えば、参照名:secret_1で作成した非対称鍵ペアをエクスポートし、参照名:secret_2にインポートします。
この状態で、参照名:secret_1の鍵で暗号化したデータを、参照名:secret_2の鍵で復号します。
筆者は、これらを確認するサンプルプログラムを作成し、次のような手順で暗号化と復号を試してみました。

  1. サンプルプログラムを起動
  2. 参照名:secret_1で作成した非対称鍵ペアを作成
  3. 参照名:secret_1の非対称鍵ペアをエクスポート
  4. 平文「Abc」を暗号化
  5. 暗号文を退避
  6. サンプルプログラムを終了
  7. サンプルプログラムを起動
  8. 参照名:secret_2で非対称鍵ペアをインポート
  9. サンプルプログラムを終了
  10. サンプルプログラムを起動
  11. キーコンテナに参照名:secret_2を指定
  12. 退避した暗号文を復号
  13. 平文「Abc」を確認
  14. サンプルプログラムを終了

これらの操作で、参照名:secret_1の鍵で暗号化したデータを、参照名:secret_2の鍵で復号出来ることを確認しました。

今回作成したサンプルプログラムは、BitHubに置いておきます。
ご参考になれば幸いです。

ここで紹介する内容は、弊社で確認した一例です。また本ページの内容は、RSA暗号方式の使用を推奨するものでも安全を保証するものでもありません。
本ページを参考に作業をされ、何らかのトラブルや損失・損害等が発生しましても一切責任を負えません。自己責任でお願いします。