2012-03-16 43 views
4

私はSecureStringタイプを返す関数GetPasswordをしました。Rfc2898DeriveBytes + PBKDF2 + SecureStringは文字列の代わりに安全な文字列を使用できますか?

私は鍵を生成するためにRfc2898DeriveBytesに、このセキュリティで保護された文字列を渡すと、Visual Studioがエラーを示しています。私の限られた知識は、Rfc2898DeriveBytesは文字列だけを受け入れ、安全な文字列を受け入れないからです。これには回避策がありますか?

//read the password from terminal 
Console.Write("Insert password"); 
securePwd = myCryptography.GetPassword(); 

//dont know why the salt is initialized like this 
byte[] salt = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xF1, 0xF0, 0xEE, 0x21, 0x22, 0x45 }; 
try 
{ //PBKDF2 standard 
    Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(securePwd, salt, iterationsPwd); 
+1

...塩がそうである理由はわかりません:D – NoobTom

+0

私は今、私がsecurePwd.ToStringを使用しているということは、secureStringを無用に使用するというプロセス全体が問題になることです。 D – NoobTom

+0

これは、 '/ /端末からのパスワードの読み込み 'で始まります。 –

答えて

4

いくつかの研究を行うと、SecureStringに言及stackoverflowの上、前の回答を見ていたら、その答えはほぼ確実である:「いいえ」。 APIの作成者だけがSecureStringを受け入れ、内部的に正しく処理できます。そして、彼らはプラットフォームの助けを借りてのみそれを行うことができます。

ユーザーとして - プレーンテキストStringを取得できる場合は、最初にSecureStringを使用する利点のほとんどを無効にしてしまいます。実際には安全ではない安全なコードを作成すると、少し危険です。

+0

よろしくお願いいたします。ありがとうございます。 – NoobTom

6

どうやら、あなたは、SecureStringexpose its internal state via the Marshal.SecureStringToBSTR() function.

ではなく、結果のうちStringを作成することによって与えられる保護に違反Rfc2898DeriveBytesに渡すByte[]にコンテンツをコピーすることができます。 Stringを作成すると、それは無期限にヒープにたむろして、または順番に攻撃者がそれを見つけることができる可能性が高まりれ、ディスクにページングを取得できるように、パスワード情報を破壊することを防ぐでしょう。その代わりに、パスワードの使用が終了したらすぐにパスワードを破棄し、配列に0を書き込む必要があります。あなたはByte[]にコピーするのと同じ理由から、あなたもBSTRの各要素にゼロを割り当てる必要があります。

塩をランダムさもなければ予め計算辞書攻撃が可能であり、各ハッシュされたパスワードではなく、固定された、予測可能な値のために選択されるべきです。ブルートフォース攻撃を防ぐためには、何万回も繰り返す必要があります。

+0

ありがとうございますが、私はパスワードを持つマシンでファイルを暗号化し、同じパスワードを持つ別のマシンでそれを復号化する必要があります。したがって、私は塩が同じでなければならない、または第2のマシンがそれを解読することができないと考えます。私は正しいですか? – NoobTom

+0

答えが「正式」なので答えとしてもう一方を選択しますが、あなたのトリッキーな提案に本当に感謝しています – NoobTom

+0

@NoobTomはい、もちろん両方のマシンで塩が同じでなければなりません。パスワードのハッシングを認証目的に使用する場合は、ハッシュ、ソルト、および反復回数を保存して、新しいハッシュが格納されたハッシュと一致するかどうかを確認するためにパスワードが提示されたときにハッシュを再計算できるようにする必要があります。パスワード認証にハードコードされたハッシュを使用しないでください。 – erickson

1

Rfc2898DeriveBytesクラスは、キーの導出に使用されるパスワードを渡すためのオーバーロードをサポートしていないことが面白いことが分かりました。

WPFはPasswordBox制御でSecureStringオブジェクトとしてパスワードを処理することができます。このような浪費のように思えましたが、このコントロールが提供する追加のセキュリティは、SecureStringをコンストラクタに渡すことができなかったために失われました。しかしericksonは、stringよりもメモリ内のbyte[]の内容を適切に管理するのが比較的容易であるため、stringの代わりにbyte[]を使用する優れた点をもたらしました。インスピレーションとしてエリクソンのの提案を使用して

私は、メモリ内の平文値の最小露出でSecureStringによって保護されたパスワードの値を使用するために許可する必要があり、次のラッパーを思い付きました。

private byte[] DeriveKey(SecureString password, byte[] salt, int iterations, int keyByteLength) 
{ 
    IntPtr ptr = Marshal.SecureStringToBSTR(password); 
    byte[] passwordByteArray = null; 
    try 
    { 
     int length = Marshal.ReadInt32(ptr, -4); 
     passwordByteArray = new byte[length]; 
     GCHandle handle = GCHandle.Alloc(passwordByteArray, GCHandleType.Pinned); 
     try 
     { 
      for (int i = 0; i < length; i++) 
      { 
       passwordByteArray[i] = Marshal.ReadByte(ptr, i); 
      } 

      using (var rfc2898 = new Rfc2898DeriveBytes(passwordByteArray, salt, iterations)) 
      { 
       return rfc2898.GetBytes(keyByteLength); 
      } 
     } 
     finally 
     { 
      Array.Clear(passwordByteArray, 0, passwordByteArray.Length); 
      handle.Free(); 
     } 
    } 
    finally 
    { 
     Marshal.ZeroFreeBSTR(ptr); 
    } 
} 

このアプローチはBSTRは、4つのバイト長の接頭辞を持つデータ列の最初の文字を指すポインタであるという事実を利用しています。

重要事項:

  • usingステートメントでRfc2898DeriveBytesをラップすることによって、それは決定論的に配置されていることを保証します。これは、KeyedHashAlgorithmの内部HMACSHA1オブジェクトを持ち、への呼び出しでゼロにするために所有しているキー(パスワード)のコピーを持つ必要があるため、重要です。廃棄。詳細については、Reference Sourceを参照してください。
  • BSTRが完了するとすぐにゼロをゼロにしてZeroFreeBSTRで解放します。
  • 最後に、パスワードのコピーをゼロクリア(消去)します。
  • 更新:byte[]の固定が追加されました。このanswerのコメントで説明したように、byte[]が固定されていない場合、ガベージコレクタはコレクション中にオブジェクトを再配置する可能性があり、元のコピーをゼロにすることはできません。

これは、平文パスワードをメモリに最小限の時間保持し、SecureStringを使用した場合の利得をあまり大きくしないようにする必要があります。ただし、攻撃者がRAMにアクセスできない場合、おそらく大きな問題があります。もう1つのポイントは、私たちが使用しているAPIがコピーを誤って(ゼロでない/クリアしていない)、パスワードのコピーを管理できるということだけです。私の知る限り、これはRfc2898DeriveBytesの場合ではありませんが、byte[]キー(パスワード)のコピーは固定されていません。したがって、ヒープ内でゼロになる前に移動された場合、配列のトレースがハングアップすることがあります。ここでのメッセージは、コードが安全に見えるということですが、問題はその下にある可能性があります。

誰かがこの実装で深刻な問題を発見した場合は、私にお知らせください。

関連する問題