DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

DOBON.NET

公開鍵暗号方法で暗号化する

ここでは公開鍵暗号 (非対称暗号化方式、公開キー暗号方式)により暗号化、復号化する方法を紹介します。公開鍵暗号とは、公開鍵と秘密鍵(個人鍵)の2つの鍵を使って暗号化、復号化する方法です。公開鍵方式に関して「アスキーデジタル用語辞典」では、次のように説明されています。

「暗号化専用の鍵(公開鍵)と解読専用の鍵(個人鍵)を使って、暗号化と解読を行なう形式。受信側で事前に公開鍵と個人鍵のペアを用意し、暗号文の送信側に公開鍵のほうを配布する。送信側は平文を公開鍵で暗号文に変換できるが、解読はできない。受信側は、個人鍵で平文に復元可能。公開鍵だけでは解読できないという利点がある。」

.NETでは公開キー暗号化アルゴリズムを実装するクラスとして、DSACryptoServiceProvider(DSA、通信用語の基礎知識による説明)とRSACryptoServiceProvider(RSA、通信用語の基礎知識による説明)の2つが用意されていますが、ここではRSACryptoServiceProviderを使った例のみを示します。

暗号化にはRSACryptoServiceProvider.Encryptメソッドを使用しますが、この時渡す暗号化されるデータにはサイズの制限があります。OAEPパディング、Direct Encryption、ともにサポートなしのそれぞれで暗号化されるデータの最大長の計算法が異なり、このことはヘルプ(「RSACryptoServiceProvider.Encrypt メソッド」)で説明されています。

例えばDirect Encryption(高度暗号化パックがインストールされている Microsoft Windows 2000 以降)の場合、RSACryptoServiceProvider.KeySize プロパティから取得できるキーサイズが1024ビットだとすると、暗号化されるデータの最大長は、 1024/8-11=117バイト となります。下のコードでは暗号化されるデータの最大長のチェックは全く行っていませんので、ご注意ください。

次に示すサンプルは、公開鍵暗号により文字列を暗号化、復号化するため3つの静的メソッドからなります。まずCreateKeysメソッドで公開鍵と秘密鍵のペアを作成し、その公開鍵を使ってEncryptメソッドにより暗号化します。復号化は秘密鍵を指定してDecryptメソッドにより行います。

[VB.NET]
''' <summary>
''' 公開鍵と秘密鍵を作成して返す
''' </summary>
''' <param name="publicKey">作成された公開鍵(XML形式)</param>
''' <param name="privateKey">作成された秘密鍵(XML形式)</param>
Public Shared Sub CreateKeys(ByRef publicKey As String, _
                            ByRef privateKey As String)
    'RSACryptoServiceProviderオブジェクトの作成
    Dim rsa As New _
        System.Security.Cryptography.RSACryptoServiceProvider()

    '公開鍵をXML形式で取得
    publicKey = rsa.ToXmlString(False)
    '秘密鍵をXML形式で取得
    privateKey = rsa.ToXmlString(True)
End Sub

''' <summary>
''' 公開鍵を使って文字列を暗号化する
''' </summary>
''' <param name="str">暗号化する文字列</param>
''' <param name="publicKey">暗号化に使用する公開鍵(XML形式)</param>
''' <returns>暗号化された文字列</returns>
Public Shared Function Encrypt(ByVal str As String, _
                            ByVal publicKey As String) As String
    'RSACryptoServiceProviderオブジェクトの作成
    Dim rsa As New _
        System.Security.Cryptography.RSACryptoServiceProvider()

    '公開鍵を指定
    rsa.FromXmlString(publicKey)

    '暗号化する文字列をバイト配列に
    Dim data As Byte() = System.Text.Encoding.UTF8.GetBytes(str)
    '暗号化する
    '(XP以降の場合のみ2項目にTrueを指定し、OAEPパディングを使用できる)
    Dim encryptedData As Byte() = rsa.Encrypt(data, False)

    'Base64で結果を文字列に変換
    Return System.Convert.ToBase64String(encryptedData)
End Function

''' <summary>
''' 秘密鍵を使って文字列を復号化する
''' </summary>
''' <param name="str">Encryptメソッドにより暗号化された文字列</param>
''' <param name="privateKey">復号化に必要な秘密鍵(XML形式)</param>
''' <returns>復号化された文字列</returns>
Public Shared Function Decrypt(ByVal str As String, _
                            ByVal privateKey As String) As String
    'RSACryptoServiceProviderオブジェクトの作成
    Dim rsa As New _
        System.Security.Cryptography.RSACryptoServiceProvider()

    '秘密鍵を指定
    rsa.FromXmlString(privateKey)

    '復号化する文字列をバイト配列に
    Dim data As Byte() = System.Convert.FromBase64String(str)
    '復号化する
    Dim decryptedData As Byte() = rsa.Decrypt(data, False)

    '結果を文字列に変換
    Return System.Text.Encoding.UTF8.GetString(decryptedData)
End Function
[C#]
/// <summary>
/// 公開鍵と秘密鍵を作成して返す
/// </summary>
/// <param name="publicKey">作成された公開鍵(XML形式)</param>
/// <param name="privateKey">作成された秘密鍵(XML形式)</param>
public static void CreateKeys(out string publicKey, out string privateKey)
{
    //RSACryptoServiceProviderオブジェクトの作成
    System.Security.Cryptography.RSACryptoServiceProvider rsa =
        new System.Security.Cryptography.RSACryptoServiceProvider();

    //公開鍵をXML形式で取得
    publicKey = rsa.ToXmlString(false);
    //秘密鍵をXML形式で取得
    privateKey = rsa.ToXmlString(true);
}

/// <summary>
/// 公開鍵を使って文字列を暗号化する
/// </summary>
/// <param name="str">暗号化する文字列</param>
/// <param name="publicKey">暗号化に使用する公開鍵(XML形式)</param>
/// <returns>暗号化された文字列</returns>
public static string Encrypt(string str, string publicKey)
{
    //RSACryptoServiceProviderオブジェクトの作成
    System.Security.Cryptography.RSACryptoServiceProvider rsa =
        new System.Security.Cryptography.RSACryptoServiceProvider();

    //公開鍵を指定
    rsa.FromXmlString(publicKey);

    //暗号化する文字列をバイト配列に
    byte[] data = System.Text.Encoding.UTF8.GetBytes(str);
    //暗号化する
    //(XP以降の場合のみ2項目にTrueを指定し、OAEPパディングを使用できる)
    byte[] encryptedData = rsa.Encrypt(data, false);

    //Base64で結果を文字列に変換
    return System.Convert.ToBase64String(encryptedData);
}

/// <summary>
/// 秘密鍵を使って文字列を復号化する
/// </summary>
/// <param name="str">Encryptメソッドにより暗号化された文字列</param>
/// <param name="privateKey">復号化に必要な秘密鍵(XML形式)</param>
/// <returns>復号化された文字列</returns>
public static string Decrypt(string str, string privateKey)
{
    //RSACryptoServiceProviderオブジェクトの作成
    System.Security.Cryptography.RSACryptoServiceProvider rsa =
        new System.Security.Cryptography.RSACryptoServiceProvider();

    //秘密鍵を指定
    rsa.FromXmlString(privateKey);

    //復号化する文字列をバイト配列に
    byte[] data = System.Convert.FromBase64String(str);
    //復号化する
    byte[] decryptedData = rsa.Decrypt(data, false);

    //結果を文字列に変換
    return System.Text.Encoding.UTF8.GetString(decryptedData);
}

注意:「マイクロソフト サポート技術情報 - 322371」によると、Web Service、ASP Page、COM+の場合は、上記コードの「RSACryptoServiceProviderオブジェクトの作成」の部分でエラーが発生することがあります。そのような場合は、この部分を以下のようにしてください。

[VB.NET]
'RSACryptoServiceProviderオブジェクトの作成
'(Web Service,ASP Page,COM+の時は次のようにUseMachineKeyStoreを指定する)
Dim CSPParam As New System.Security.Cryptography.CspParameters
CSPParam.Flags = _
    System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore
Dim rsa As New _
    System.Security.Cryptography.RSACryptoServiceProvider(CSPParam)
[C#]
//RSACryptoServiceProviderオブジェクトの作成
//(Web Service,ASP Page,COM+の時は次のようにUseMachineKeyStoreを指定する)
System.Security.Cryptography.CspParameters CSPParam =
    new System.Security.Cryptography.CspParameters();
CSPParam.Flags =
    System.Security.Cryptography.CspProviderFlags.UseMachineKeyStore;
System.Security.Cryptography.RSACryptoServiceProvider rsa =
    new System.Security.Cryptography.RSACryptoServiceProvider(CSPParam);

  • 履歴:
  • 2007/9/28 UseMachineKeyStoreを使用するコードを注意コラム内に移動。