1. ホーム
  2. java

[解決済み] Java 256ビットAESパスワードベース暗号化機能

2022-03-22 03:56:14

質問

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

Ie. 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();

ここからコードを抜粋

EDIT

実は、パスワードをビットではなく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)

自分でやらなければならないこと:-)

解決方法は?

を共有します。 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) このため、平文が同一であっても、異なる暗号文が生成されます。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));

を格納します。 ciphertextiv . 復号化する際には 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搭載API AEAD暗号モード対応 OpenJDKやOracleディストリビューションに含まれるSunJCEプロバイダは、Java 8からこれらを実装しています。CBCの代わりに、これらのモードの1つを強くお勧めします。


A java.security.InvalidKeyException というメッセージが表示された場合、暗号強度が低いことを意味します。 無制限強度管轄のポリシーファイルが正しい場所にない。JDKでは、これらのファイルは ${jdk}/jre/lib/security

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