web-dev-qa-db-ja.com

安全なAESキーを生成していますか?

私は この質問 をAESのIVについて少し前に尋ねました、そして私は非常に素晴らしくて役に立つ回答を得ました(ありがとう!)だから、皆さんがもう一度私を助けることができると思いました、今回は実際のキー生成。

TL; DR-下部を参照

現在、私はこのように暗号化しています:

_Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
SecureRandom randomSecure = SecureRandom.getInstance("SHA1PRNG");
byte[] iv = new byte[cipher.getBlockSize()];
randomSecure.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParams);
rawCryptotext = cipher.doFinal(textToEncrypt.getBytes());
_

ご覧のとおり、私はSecureRandomクラスを使用してランダムIVを生成しています。

ただし:

コードの6行目のkey変数に注目してください。

SecretKeySpec skeySpec = new SecretKeySpec(key。getBytes( "UTF-8")、 "AES");

その変数は、次のようなgetKey()メソッドから取得されます。

_public static String getKey()
    {
        String possibleKey = "init";
        String validKey = null;

        while (possibleKey.length() != 16)
        {
            System.out.printf("\nPlease enter a 128-bit key: ");
            possibleKey = input.nextLine();
        }

        if (possibleKey.length() == 16)
        {
            validKey = possibleKey;
        }
        else
        {
            System.out.println("Something has gone very wrong...");
        }

        return validKey;
    }
_

ユーザーからキーを取得し、それをプレーンテキストSecretKeySpecに渡します。

だから私の質問:プレーンテキストのキーをランダムなIVと組み合わせると、安全な暗号化が実現しますか?または、最初にSHA-256などでキー文字列をハッシュし、その結果をキーに使用する必要がありますか?

いいえ

あなたがしていることは、16文字の文字列、つまりパスワードを入力するようにユーザーに要求することです。 16バイトは128ビットに適合できることは事実ですが、すべての可能なバイト値が(等しく)可能であるデータに対してのみ保持されます。文字で構成されるテキストはそれ以外です。 1つ目は、印刷可能な文字のセットがすべてのバイトのセットよりもはるかに小さいためです。 (試行した場合、すべてのバイトを入力することもできない可能性があります。)2番目に、ユーザーはランダムなバイトを入力するのではなく、単語を入力するためです。そして言葉はさらに予測可能です。

ユーザーにパスワードを入力させたい場合は、長さを制限しないで(おそらく最小値を設定する場合を除く)、 PBKDF2 のようなものを使用してキーを伸ばし、パスワードに対する辞書の推測を遅くします。 (@marstatoがコメントしたように)。

一方、ランダムキーを生成したい場合は、strongランダムビットジェネレーターからバイトを取り出し、ファイルに保存します。

7
ilkkachu

keyはユーザーが入力したパスワードだと思います。

直接暗号化に使用しないでください。 (おそらく非常に弱い)ユーザーパスワードに対するブルートフォース攻撃は、完全な128(または192、256)ビットキーに対するよりもはるかに簡単です。パスワードをハッシュしてキーを取得するだけでは、ブルートフォースを適切な量だけ遅くすることがないため、うまくいきません。生のパスワードに対するブルートフォース攻撃を実行不可能にするために、1回の試行を十分に遅らせるために、パスワードは数万回ハッシュされる必要があります。

PBKDF2はこれに対するソリューションです。これは、ソルト、安全なハッシュ関数、および大量の反復を組み合わせています。

// obtain password from wherever you like
char[] password;

// generate salt using a secureRandom; store salt with ciphertext
byte[] salt;

// key size in bits
int keySize = 128;
// choose so that it takes the computer of your average user about 1 second to do the derivation (lower if running on mobile devices, higher on an enterprise server)
int nIterations = 10000;

SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBDKF2WithHmacSHA256");
SecretKeySpec keySpec = keyFactory.generateSecret(new PBEKeySpec(password, salt, keysize));
// init cipher with keySpec
3
marstato