Java 256 ビット AES パスワードベース暗号化 質問する

Java 256 ビット AES パスワードベース暗号化 質問する

256 ビット AES 暗号化を実装する必要がありますが、オンラインで見つけた例はすべて「KeyGenerator」を使用して 256 ビット キーを生成していますが、私は独自のパスキーを使用したいと思います。独自のキーを作成するにはどうすればよいでしょうか? 256 ビットにパディングしてみましたが、キーが長すぎるというエラーが表示されます。無制限の管轄パッチはインストールしているので、これは問題ではありません :)

つまり、KeyGenerator は次のようになります...

// Get the KeyGenerator
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); // 192 and 256 bits may not be available

// Generate the secret key specs.
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();

コードはここから取得しました

編集

私は実際にパスワードをビットではなく 256 バイトにパディングしていましたが、これは長すぎます。以下は、これについてもう少し経験を積んだ後に私が使用しているコードです。

byte[] key = null; // TODO
byte[] input = null; // TODO
byte[] output = null;
SecretKeySpec keySpec = null;
keySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
output = cipher.doFinal(input)

「TODO」部分は自分で行う必要があります :-)

ベストアンサー1

password(a char[]) とsalt(a byte[]— によって選択された 8 バイトは適切なソルトになります。秘密にする必要はありません) を帯域外受信者と共有しますSecureRandom。次に、この情報から適切なキーを導出します。

/* Derive the key, given password and salt. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

マジックナンバー(どこかで定数として定義される可能性があります)65536 と 256 は、それぞれキー導出の反復回数とキーのサイズです。

キー導出関数は反復処理されるため、多大な計算量が必要となり、攻撃者が多数の異なるパスワードを素早く試すことを防止します。反復回数は、利用可能なコンピューティング リソースに応じて変更できます。

キーのサイズは 128 ビットまで縮小できますが、それでも「強力な」暗号化であると考えられます。ただし、AES を弱める攻撃が発見された場合、安全マージンはあまり得られません。

適切なブロックチェーンモードを使用すると、同じ派生キーを使用して多くのメッセージを暗号化できます。暗号ブロック連鎖 (CBC)、各メッセージに対してランダムな初期化ベクトル (IV) が生成され、プレーン テキストが同一であっても異なる暗号テキストが生成されます。CBC は、最も安全なモードではない可能性があります (以下の AEAD を参照)。セキュリティ プロパティが異なる他のモードは多数ありますが、すべて同様のランダム入力を使用します。いずれの場合も、各暗号化操作の出力は、暗号テキスト初期化ベクトルです。

/* Encrypt the message. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal("Hello, World!".getBytes(StandardCharsets.UTF_8));

ciphertextと を保存しますiv。復号化時に、 は同じソルトと反復パラメータを持つパスワードを使用して、まったく同じ方法で再生成されます。このキーメッセージとともに保存された初期化ベクトルSecretKeyを使用して暗号を初期化します。

/* Decrypt the message, given derived key and initialization vector. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
String plaintext = new String(cipher.doFinal(ciphertext), StandardCharsets.UTF_8);
System.out.println(plaintext);

Java 7 に含まれる APIAEAD暗号モードのサポートOpenJDK および Oracle ディストリビューションに含まれる「SunJCE」プロバイダーは、Java 8 以降でこれらを実装しています。これらのモードのいずれかを CBC の代わりに強く推奨します。これにより、データの整合性とプライバシーが保護されます。


java.security.InvalidKeyException「キーサイズまたはデフォルトパラメータが不正です」というメッセージが表示される場合、暗号化の強度が制限されていることを意味します。無制限の強度の管轄ポリシーファイルが正しい場所にありません。JDKでは、以下の場所に置く必要があります。${jdk}/jre/lib/security

問題の説明によると、ポリシー ファイルが正しくインストールされていないようです。システムには複数の Java ランタイムが存在する可能性があります。正しい場所が使用されていることを再確認してください。

おすすめ記事