web-dev-qa-db-ja.com

MySQLに保存されているデータの暗号化キーを暗号化するための実用的な手順

したがって、私はユーザーデータがキーとして(の一部として)ユーザーのパスワードを使用して暗号化されて保存される最初のプロジェクトに取り組んでいます。私はベストプラクティスについて多くの同様のことを読みましたが、あまり詳しくない私のような人にとっては、詳細がぼやけているようです。

私はそれが最善であると読んだ:

  1. 検証のために、ユーザーのパスワードの強力なハッシュ(bcrypt)を用意します。 DBに保存
  2. ランダムな256ビットキー( "KEY1")を使用してAESでプライベートデータを暗号化します。保存されていません
  3. ユーザーのパスワードから導出された強力なハッシュを「KEY2」として使用して、KEY1をAES(「Enc_KEY1」)で暗号化します。ステップ1とは異なるソルト。Enc_KEY1をDBに保存します。 KEY2をどこにも保存しないでください。

回答が見つからない2つの問題があります。

  • Bcryptハッシュの文字列長は、AESキーとして互換性がありません。これは、長さと、ピリオドやドル記号などの無効な文字が原因です。この問題にどのように対処しますか?
  • Enc_KEY1の復号化に関しては、最初にユーザーのパスワードのハッシュ(bcrypt)からKEY2を生成する必要があります...ハッシュを正確に再作成するにはどうすればよいですか?私は塩を保存することになっていますか? bcryptは毎回ランダムなソルトを作成したいようです...しかし、ソルトが格納されていない限り、同じハッシュを再作成する方法はありません...ソルトを格納するのは悪いことですか?ここで何が欠けていますか?

助けてくれてありがとう。

3
thequeue

Bcryptハッシュの文字列長は、AESキーとして互換性がありません。これは、長さと、ピリオドやドル記号などの無効な文字が原因です。この問題にどのように対処しますか?

Base64エンコーディングはあなたの友人です。 Base64でエンコードされた文字はすべてAESで有効な文字です

Enc_KEY1の復号化に関しては、最初にユーザーのパスワードのハッシュ(bcrypt)からKEY2を生成する必要があります...ハッシュを正確に再作成するにはどうすればよいですか?私は塩を保存することになっていますか? bcryptは毎回ランダムなソルトを作成したいようです...しかし、ソルトが格納されていない限り、同じハッシュを再作成する方法はありません...ソルトを格納するのは悪いことですか?ここで何が欠けていますか?

はい、ソルトを保存する必要があります(パスワードハッシュを暗号化するためにAESを使用している場合は、オプションでペッパーを使用します)。それがなければ、ハッシュを再作成する方法はありません。

2
devnull

詳細をお探しの方は、

RFC 488 実装の詳細をすべて説明 OpenPGP これは、私が知る限り、1つのキー(KEY1)でデータを暗号化し、そのキーを暗号化する最も一般的な方法です暗号化されたデータと暗号化されたキーの両方を格納する暗号化されたキー( "Enc_KEY1")を生成する2番目のキー(KEY2)。後で2番目のキー(KEY2)を持っている(または推測できる)人々だけが最初のキー(KEY1)を復号化して平文を復元できます。

ソルトを秘密にする必要がないため、パスフレーズのハッシュを保存する最も一般的な方法-- Modular Crypt Format --は常にソルトを保存します。 "塩を保存しない" について話す人はたくさんいるようです。

Jaccoのエッセイは教育的に役立つかもしれません: "ソルトとは何ですか?ハッシュをソルトすることが便利なのはなぜですか?ソルトを秘密にする必要はありません。なぜソルトはランダムでなければならないのですか?"

人間が入力したパスフレーズを暗号化キーに変換することを「パスワードベースのキー導出」といいます。 bcryptなどのそれを行う関数は 鍵導出関数 と呼ばれます。

すでに発見したように、最近のほとんどのbcrypt実装には「ハッシュ」関数があり、プレーンテキストのパスフレーズが与えられると、新しい乱数をプルし、その乱数とパスフレーズを使用して一連の処理を行い、ハッシュ値を生成します。 "$ 2b $"( "bcrypt"を示す)、コストパラメータ、別の "$"、22文字のソルト文字列(base-64エンコードされた乱数)、およびaを連結した文字列を吐き出します。 31文字のチェックサム(base-64でエンコードされたハッシュ値)。その「ハッシュ」関数を呼び出すたびに、まったく同じ平文パスフレーズでも、新しい新しい乱数が取得されるため、ソルト文字列とチェックサムはほぼ確実に異なります。

これらの値をすべて連結すると、長い文字列が得られ、パスワード検証データベースに一度にすべてを保存するのに便利です。最後の31文字は、通常のbase-64エンコーディングでエンコードされた23バイト(184ビット)のデータを表します。生の基礎となるAES128の暗号化キーは、一連の128ビット(16バイト)です。これらのバイトは任意のバイト(0x00を含む)にすることができます。 「違法な文字」はありません。ただし、AES128のsome実装では、「役立つ」ために、32ビットの16進数の形式でこれらの128ビットが必要です-参照 https://stackoverflow.com/questions/14368374/how-to-turn-64-character-string-into-key-for-256-aes-encryption 詳細については、 Base64文字列から16進数の文字列への変換についてサポートが必要かどうかは、StackOverflowでお気軽に質問してください。また、otherAES128の実装には、役立つように、任意のプレーンなASCII文字列を必要な128ビットに変換するキー導出関数が含まれています。生の基礎となるAES128アルゴリズム用。

ほとんどのライブラリメンテナは人々が正しいことをできるように手助けしたいので、上記の「ハッシュ」関数と「検証」関数を強調します。これは、ほとんどのプログラマがパスフレーズハッシュを適切に実装するために必要なすべてです。ただし、アプリケーションでは、保存されたソルト値と保存された反復回数とパスフレーズを受け取り、実際のハッシュ値を提供する関数も必要です-bcryptの多くの実装には、 jBCryptなどのそのような関数が含まれていますbcrypt-nodejsOpenBSD bcryptOpenwall bcrypt など、一般的に上記の必須要素を構築するために使用される内部関数として2つの機能。必要な機能は、通常、ドキュメントでは強調されていません。

"対称暗号化および認証用の鍵の導出" および "パスワードから繰り返し鍵を導出する最も安全な方法は何ですか?"

アプリケーションは、認証と暗号化の両方に同じキーを使用しているように聞こえます。多くの人々がこれら2つの目的で完全に独立したキーを使用することを推奨していることを知りたいと思うかもしれません: 暗号化に同じ非対称キーを使用すべきでない理由彼らは署名するのと同じですか?

1
David Cary