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

パスワードで文字列を暗号化する

ここでは、共通鍵暗号(共有キー暗号、対称鍵暗号、秘密鍵暗号、慣用暗号)方式によって、パスワードを使って、ファイルを暗号化、復号化する方法を説明します。

パスワードを使って文字列を暗号化、復号化する方法は「パスワードでファイルを暗号化する」とほぼ同じですので、詳しくはそちらをご覧いただくことにして、ここではサンプルのコードだけを紹介します。

ただし、「パスワードでファイルを暗号化する」とは違い、ここではICryptoTransform.TransformFinalBlockメソッドを使って暗号化と復号化を行っています。もしTransformFinalBlockメソッドを使わずに、「パスワードでファイルを暗号化する」のようにCryptoStreamを使うのであれば、「パスワードでファイルを暗号化する」のコードで、FileStreamの代わりにMemoryStreamを使うようにしてください。

VB.NET
コードを隠すコードを選択
''' <summary>
''' 文字列を暗号化する
''' </summary>
''' <param name="sourceString">暗号化する文字列</param>
''' <param name="password">暗号化に使用するパスワード</param>
''' <returns>暗号化された文字列</returns>
Public Shared Function EncryptString(ByVal sourceString As String, _
                                     ByVal password As String) As String
    'RijndaelManagedオブジェクトを作成
    Dim rijndael As New System.Security.Cryptography.RijndaelManaged()

    'パスワードから共有キーと初期化ベクタを作成
    Dim key As Byte(), iv As Byte()
    GenerateKeyFromPassword(password, rijndael.KeySize, key, rijndael.BlockSize, iv)
    rijndael.Key = key
    rijndael.IV = iv

    '文字列をバイト型配列に変換する
    Dim strBytes As Byte() = System.Text.Encoding.UTF8.GetBytes(sourceString)

    '対称暗号化オブジェクトの作成
    Dim encryptor As System.Security.Cryptography.ICryptoTransform = _
        rijndael.CreateEncryptor()
    'バイト型配列を暗号化する
    Dim encBytes As Byte() = encryptor.TransformFinalBlock(strBytes, 0, strBytes.Length)
    '閉じる
    encryptor.Dispose()

    'バイト型配列を文字列に変換して返す
    Return System.Convert.ToBase64String(encBytes)
End Function

''' <summary>
''' 暗号化された文字列を復号化する
''' </summary>
''' <param name="sourceString">暗号化された文字列</param>
''' <param name="password">暗号化に使用したパスワード</param>
''' <returns>復号化された文字列</returns>
Public Shared Function DecryptString(ByVal sourceString As String, _
                                     ByVal password As String) As String
    'RijndaelManagedオブジェクトを作成
    Dim rijndael As New System.Security.Cryptography.RijndaelManaged()

    'パスワードから共有キーと初期化ベクタを作成
    Dim key As Byte(), iv As Byte()
    GenerateKeyFromPassword(password, rijndael.KeySize, key, rijndael.BlockSize, iv)
    rijndael.Key = key
    rijndael.IV = iv

    '文字列をバイト型配列に戻す
    Dim strBytes As Byte() = System.Convert.FromBase64String(sourceString)

    '対称暗号化オブジェクトの作成
    Dim decryptor As System.Security.Cryptography.ICryptoTransform = _
        rijndael.CreateDecryptor()
    'バイト型配列を復号化する
    '復号化に失敗すると例外CryptographicExceptionが発生
    Dim decBytes As Byte() = decryptor.TransformFinalBlock(strBytes, 0, strBytes.Length)
    '閉じる
    decryptor.Dispose()

    'バイト型配列を文字列に戻して返す
    Return System.Text.Encoding.UTF8.GetString(decBytes)
End Function

''' <summary>
''' パスワードから共有キーと初期化ベクタを生成する
''' </summary>
''' <param name="password">基になるパスワード</param>
''' <param name="keySize">共有キーのサイズ(ビット)</param>
''' <param name="key">作成された共有キー</param>
''' <param name="blockSize">初期化ベクタのサイズ(ビット)</param>
''' <param name="iv">作成された初期化ベクタ</param>
Private Shared Sub GenerateKeyFromPassword(ByVal password As String, _
                                           ByVal keySize As Integer, _
                                           ByRef key As Byte(), _
                                           ByVal blockSize As Integer, _
                                           ByRef iv As Byte())
    'パスワードから共有キーと初期化ベクタを作成する
    'saltを決める
    Dim salt As Byte() = System.Text.Encoding.UTF8.GetBytes("saltは必ず8バイト以上")
    'Rfc2898DeriveBytesオブジェクトを作成する
    Dim deriveBytes As New System.Security.Cryptography.Rfc2898DeriveBytes( _
        password, salt)
    '.NET Framework 1.1以下の時は、PasswordDeriveBytesを使用する
    'Dim deriveBytes As New System.Security.Cryptography.PasswordDeriveBytes( _
    '    password, salt)

    '反復処理回数を指定する デフォルトで1000回
    deriveBytes.IterationCount = 1000

    '共有キーと初期化ベクタを生成する
    key = deriveBytes.GetBytes(keySize \ 8)
    iv = deriveBytes.GetBytes(blockSize \ 8)
End Sub
C#
コードを隠すコードを選択
/// <summary>
/// 文字列を暗号化する
/// </summary>
/// <param name="sourceString">暗号化する文字列</param>
/// <param name="password">暗号化に使用するパスワード</param>
/// <returns>暗号化された文字列</returns>
public static string EncryptString(string sourceString, string password)
{
    //RijndaelManagedオブジェクトを作成
    System.Security.Cryptography.RijndaelManaged rijndael =
        new System.Security.Cryptography.RijndaelManaged();

    //パスワードから共有キーと初期化ベクタを作成
    byte[] key, iv;
    GenerateKeyFromPassword(
        password, rijndael.KeySize, out key, rijndael.BlockSize, out iv);
    rijndael.Key = key;
    rijndael.IV = iv;

    //文字列をバイト型配列に変換する
    byte[] strBytes = System.Text.Encoding.UTF8.GetBytes(sourceString);

    //対称暗号化オブジェクトの作成
    System.Security.Cryptography.ICryptoTransform encryptor =
        rijndael.CreateEncryptor();
    //バイト型配列を暗号化する
    byte[] encBytes = encryptor.TransformFinalBlock(strBytes, 0, strBytes.Length);
    //閉じる
    encryptor.Dispose();

    //バイト型配列を文字列に変換して返す
    return System.Convert.ToBase64String(encBytes);
}

/// <summary>
/// 暗号化された文字列を復号化する
/// </summary>
/// <param name="sourceString">暗号化された文字列</param>
/// <param name="password">暗号化に使用したパスワード</param>
/// <returns>復号化された文字列</returns>
public static string DecryptString(string sourceString, string password)
{
    //RijndaelManagedオブジェクトを作成
    System.Security.Cryptography.RijndaelManaged rijndael =
        new System.Security.Cryptography.RijndaelManaged();

    //パスワードから共有キーと初期化ベクタを作成
    byte[] key, iv;
    GenerateKeyFromPassword(
        password, rijndael.KeySize, out key, rijndael.BlockSize, out iv);
    rijndael.Key = key;
    rijndael.IV = iv;

    //文字列をバイト型配列に戻す
    byte[] strBytes = System.Convert.FromBase64String(sourceString);

    //対称暗号化オブジェクトの作成
    System.Security.Cryptography.ICryptoTransform decryptor =
        rijndael.CreateDecryptor();
    //バイト型配列を復号化する
    //復号化に失敗すると例外CryptographicExceptionが発生
    byte[] decBytes = decryptor.TransformFinalBlock(strBytes, 0, strBytes.Length);
    //閉じる
    decryptor.Dispose();

    //バイト型配列を文字列に戻して返す
    return System.Text.Encoding.UTF8.GetString(decBytes);
}

/// <summary>
/// パスワードから共有キーと初期化ベクタを生成する
/// </summary>
/// <param name="password">基になるパスワード</param>
/// <param name="keySize">共有キーのサイズ(ビット)</param>
/// <param name="key">作成された共有キー</param>
/// <param name="blockSize">初期化ベクタのサイズ(ビット)</param>
/// <param name="iv">作成された初期化ベクタ</param>
private static void GenerateKeyFromPassword(string password,
    int keySize, out byte[] key, int blockSize, out byte[] iv)
{
    //パスワードから共有キーと初期化ベクタを作成する
    //saltを決める
    byte[] salt = System.Text.Encoding.UTF8.GetBytes("saltは必ず8バイト以上");
    //Rfc2898DeriveBytesオブジェクトを作成する
    System.Security.Cryptography.Rfc2898DeriveBytes deriveBytes =
        new System.Security.Cryptography.Rfc2898DeriveBytes(password, salt);
    //.NET Framework 1.1以下の時は、PasswordDeriveBytesを使用する
    //System.Security.Cryptography.PasswordDeriveBytes deriveBytes =
    //    new System.Security.Cryptography.PasswordDeriveBytes(password, salt);
    //反復処理回数を指定する デフォルトで1000回
    deriveBytes.IterationCount = 1000;

    //共有キーと初期化ベクタを生成する
    key = deriveBytes.GetBytes(keySize / 8);
    iv = deriveBytes.GetBytes(blockSize / 8);
}
  • 履歴:
  • 2004/9/12 ResizeBytesArrayメソッドを修正。
  • 2005/3/26 ResizeBytesArrayメソッドを修正。
  • 2009/6/13 EncryptString関数内の変数の名前を変更。
  • 2010/10/3 「パスワードでファイルを暗号化する」に合わせて、大幅に書き換える。
  • 2013/7/5 C#のコードでコメントに間違いがあったのを修正。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • このサイトで紹介されているコードの多くは、例外処理が省略されています。例外処理については、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。