Member-only story
Goでのパスワードを使用したデータ暗号化(後半)
Password
さて、aes.NewCipher() は 16、24、または 32 バイトのキーを必要とし、この例では 32 バイトのキーを使用しています。しかし、私たちのパスワードは32バイトにはなりません。そこで、パスワードを適切なキーに変換する必要があります。これを行うには、鍵導出関数(KDF)11を使用して、パスワードを適切な暗号キーにするために「伸張」します。このキーストレッチ12は、それ自体が遅いという特徴を持っています。これは、アタッカーがパスワードにブルートフォース攻撃を試みるために多くのリソース(総当たり攻撃)を費やす必要があるためなのです。KDF にはいくつかのオプションがあります。そのオプションというのはArgon213、scrypt14、bcrypt15、pbkdf216です。どれを選ぶかはいくつかの要因に依存しますが、主にどのくらい安全であるか171819202122で選びます。
通常、KDFではパスワード、ソルト、および繰り返しの引数を持つ。salt23は、攻撃者がパスワードとキーのペアを保存するだけではなく、アタッカーが派生キーのディクショナリを事前にコンピューティングすることを防ぐために使用されます。というのも、異なるソルトは各パスワードは、異なるアウトプットを算出するからです。それぞれのパスワードはキーを導出するために使用されたソルトと照合しなければならりません。(Isom 2015; Wikipedia 2020) ソルトは、ランダムに生成される必要があるという点で nonce に関連しています。また、nonceと同様に、ソルトは秘密である必要はありませんが、ユニークである必要があります。繰り返し引数または difficulty パラメータは、処理を何回繰り返すかを表します。これは、ソルトを使用してもディクショナリ攻撃は可能ですが、反復回数を指定すると、パスワードからキーをコンピューティングするのにかかる時間が遅くなるからです(Viega and Messier 2003)。(Viega and Messier 2003, 141–42)
この例では scrypt を使用していますので、どのようにプログラムに実装するか見てみましょう。
import ("crypto/rand""golang.org/x/crypto/scrypt")func DeriveKey(password, salt []byte) ([]byte, []byte, error) {if salt == nil {salt = make([]byte, 32)if _, err := rand.Read(salt); err != nil {return nil, nil, err}}key, err := scrypt.Key(password, salt, 1048576, 8, 1…