3

Java AES 暗号化/復号化の非常に標準的な方法を使用しています。

byte[] key = hexStringToByteArray("C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF");

byte[] message = hexStringToByteArray("01A0A1A2A3A4A5A6A703020100060001");

SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");

// Instantiate the cipher
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);

byte[] encrypted = cipher.doFinal(message);

cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] original = cipher.doFinal(encrypted);

ご覧のとおり、128 ビット キーと 128 ビット メッセージを使用しています。私は常に期待どおりの結果を得ることができますが、暗号化された結果は常に 256 ビット長です。2 番目の 128 ビットは常に同じです。結果を切り捨てる以外に、最初の 128 ビットを変更せずに、暗号が最初の 128 ビットのみを返すようにするにはどうすればよいですか? ここでのブロックサイズの定義と混同しているように感じます。

4

2 に答える 2

12

あなたの質問に近づく前に、邪魔にならないようにする必要があることがいくつかあります。このコードで見られる潜在的に危険な点の 1 つは、明示的なモードとパディングで暗号が指定されていないことです。これは、プロバイダーのデフォルト次第であることを意味します。これが現在 Oracle の JVM とともに配布されているプロバイダである場合、それらのデフォルトはECBおよびPKCS5Paddingです。それらを使用したい場合は、次のように指定します。

 Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

2 つ目は、ECBあまり安全ではないため、使用するモードの適切な選択ではないことです。CBC初期化ベクトルを使用するため、はるかに優れたオプションです。

質問に。暗号化されたテキストのサイズの理由は、この場合はパディング スキームによるものPKCS5です。パディングは、平文がアルゴリズムで処理できる長さであることを確認するために必要です。AES の場合、16 バイトの倍数でなければなりません。暗号化されていないデータの長さがすでに 16 バイトの倍数になっている場合、パディングでさらに 16 バイトを追加する必要があります (jbtule のコメントはこちら)。このように初期化するCipherと、16 バイトの暗号化されたデータが生成されます。

Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");

これには、暗号化されていないデータの長さが 16 バイトの倍数であることが必要です。そうでない場合は、例外がスローされます。

適切な推奨事項を提供するには、何をしようとしているのかを正確に理解することが有益な場合があります。

于 2013-04-08T15:00:44.450 に答える
3

暗号インスタンスは、最大 16 バイトのパディングを暗号文に追加する PKCS5Padding パディングを使用しています。これを修正するには、いくつかの方法があります。

オプション 1: パディングを使用する Cipher.getInstance("AES") を使用する代わりに、Cipher.getInstance("AES/CBC/NoPadding") を使用します。ただし、平文が 16 バイトの倍数である必要があるため、これはお勧めできません。

オプション 2: BouncyCastleを暗号プロバイダーとして使用してから、

import org.bouncycastle.jce.provider.BouncyCastleProvider;
Cipher.getInstance("AES/CTR/NoPadding", new BouncyCastleProvider());

暗号を初期化します。これは、Cipher Block Chaining モード (CBC) の代わりに Counter モード (CTR) を使用し、Counter モードはパディングを必要としません。カウンター モードでは、暗号文と共に平文で送信できる固有の初期化ベクトルを使用することが重要です。例えば、

byte[] IV = new byte[16];
new SecureRandom().getBytes(IV);
cipher.init(Cipher.ENCRYPT_MODE, key, IV);

次に、暗号文を復号化するときに、同じ初期化ベクトルで暗号を初期化します。IV をどのように送信するかはあなた次第ですが、秘密にしておく必要はありません。

暗号ブロック連鎖モードの初期化ベクトルも一意である必要がありますが、これはカウンター モードほど重要ではありません。

于 2013-04-08T15:01:20.137 に答える