-1

以下の手法を使用してデータファイルを暗号化するクライアント側にJava 8をインストールしました

    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, key);
    outputStream = new CipherOutputStream(new FileOutputStream(encryptedFile), cipher);

そして今、私は以下のコードに従ってJava 7がインストールされているサーバー側で復号化しています。

Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
inputStream = new CipherInputStream(new FileInputStream(encryptedFile), cipher);
outputStream = new FileOutputStream(decryptedFileName);

そうすることで、以下のエラーが表示されます

Caused by: java.io.IOException: javax.crypto.BadPaddingException: Given final block not properly padded
    at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:115) [jce.jar:1.7.0_71]
    at javax.crypto.CipherInputStream.read(CipherInputStream.java:233) [jce.jar:1.7.0_71]
    at javax.crypto.CipherInputStream.read(CipherInputStream.java:209) [jce.jar:1.7.0_71]

両側に同じ Java バージョン (1.7) がインストールされている場合、同じコードが正常に動作します。どちらの側でもJavaバージョンを変更せずにこれを修正するにはどうすればよいですか

4

1 に答える 1

0

この問題には、いくつかの原因が考えられます。

  1. キーの取得/生成方法を指定しません。JRE がJCE Unlimited Strength Jurisdiction Policiesの所有/不在で異なる場合、一方は 256 ビット AES 暗号化をサポートし、もう一方は 128 ビットのみをサポートします。利用可能なキーの長さに基づいてキーを生成している場合、これが原因でキーが一致しない可能性があります。一方、両方の Java 7 環境に同じレベルのポリシーがインストールされている場合があります。

  2. システムのいずれかの側で動作のブロック暗号モードまたはパディング スキームを指定していません。を呼び出すだけで取得できます。GCMEAXCCMNoPaddingCBC/PKCS5PaddingCTR/NoPaddingAES/ECB/PKCS5PaddingCipher.getInstance("AES")

  3. 暗号テキストを永続化する前にエンコードしてから、復号化のために逆シリアル化する方法については説明しません。16 進数や Base64 のような安全なエンコーディング スキームがないと、生のバイナリ値を扱う際にエンコーディングの問題が発生する可能性があります (最終的にはそうなります)。

  4. ECBから別の操作モードに変更したら、暗号化と復号化の両方に初期化ベクトル (IV) を提供し、IV を暗号文と一緒に送信する必要があります。IV は暗号化する必要はありませんが、同じキーで暗号化されたメッセージごとに一意で予測不可能でなければなりません。これは常に暗号のブロック サイズ (AES では 16 バイト/128 ビットに固定) であるため、暗号テキストの先頭に IV 値を追加し、それを分割して復号化します。

  5. AES (およびすべての対称暗号方式) は、暗号化と復号化に同じキーを使用します。公開キーと秘密キーは関係ありません。命名の問題である可能性がありますが、復号化しようとしているという事実publicKeyは、間違ったキーが使用されていることを示している可能性があります. 暗号化キーと復号化キーの両方のバイトが同一であること (同じ長さ (16、24、または 32 バイト) で等しいこと) を確認する必要があります。ECB暗号化テキストがブロック サイズ (16 バイト) の正確な倍数である場合、「復号化」は常に「成功」​​します。次に、パディングが検証されます。間違ったキーでメッセージを復号化しようとすると、多くの場合 (255/256 回) パディング エラーが発生します。もう 1 つのケースは、最後のバイトが復号化されて0x01これは PKCS #5/#7 の有効なパディング値であるため、パディング エラーは検出されません。

AES/ECB/PKCS5PaddingJava 8 (1.8.0_101) のデフォルトであるデモ:

@Test
public void testCipherGetInstanceShouldDefaultToECB() throws Exception {
    // Arrange
    final String PLAINTEXT = "This is a plaintext message."
    final SecretKey key = new SecretKeySpec(Hex.decodeHex("0123456789ABCDEFFEDCBA9876543210" as char[]), "AES")

    Cipher unspecified = Cipher.getInstance("AES")
    final Cipher EXPECTED_CIPHER = Cipher.getInstance("AES/ECB/PKCS5Padding")

    unspecified.init(Cipher.ENCRYPT_MODE, key)
    EXPECTED_CIPHER.init(Cipher.DECRYPT_MODE, key)

    // Act
    byte[] cipherBytes = unspecified.doFinal(PLAINTEXT.getBytes(StandardCharsets.UTF_8))
    logger.info("Cipher text: ${Hex.encodeHexString(cipherBytes)}")

    // Assert
    byte[] recoveredBytes = EXPECTED_CIPHER.doFinal(cipherBytes)
    String recovered = new String(recoveredBytes, StandardCharsets.UTF_8)
    assert recovered == PLAINTEXT
}
于 2017-01-07T02:36:07.457 に答える