1

ファイルを暗号化してから復号化するには、AES を使用します。error に関する多くのトピックを読みまし"Given final block not properly padded"た。しかし、私は解決策を見つけられません。

私のコードの言語を指定して申し訳ありませんが、私は書き込み言語のJavaを知りません

これが私のコードです:

変数

// IV, secret, salt in the same time
private byte[] salt = { 'h', 'u', 'n', 'g', 'd', 'h', '9', '4' };
public byte[] iv;
public SecretKey secret;

createSecretKey

public void createSecretKey(String password){
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
    SecretKey tmp = factory.generateSecret(spec);
    secret = new SecretKeySpec(tmp.getEncoded(), "AES");
}

メソッド暗号化

public void encrypt(String inputFile){
    FileInputStream fis = new FileInputStream(inputFile);
    // Save file: inputFile.enc
    FileOutputStream fos = new FileOutputStream(inputFile + ".enc");

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secret);

    AlgorithmParameters params = cipher.getParameters();
    // Gen Initialization Vector
    iv = (byte[]) ((IvParameterSpec) params
            .getParameterSpec(IvParameterSpec.class)).getIV();
    // read from file (plaint text)  -----> save with .enc
    int readByte;
    byte[] buffer = new byte[1024];
    while ((readByte = fis.read(buffer)) != -1) {
        fos.write(cipher.doFinal(buffer), 0, readByte);
    }
    fis.close();
    fos.flush();
    fos.close();
}

メソッド復号化

public void decrypt(String inputFile){
    FileInputStream fis = new FileInputStream(inputFile);
    // Save file: filename.dec
    FileOutputStream fos = new FileOutputStream(inputFile.substring(0,
            inputFile.length() - 4) + ".dec");

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
    // Read from file encrypted  ---> .dec 
    int readByte;
    byte[] buffer = new byte[1024];
    while ((readByte = fis.read(buffer)) != -1) {
        fos.write(cipher.doFinal(buffer), 0, readByte);
    }
    fos.flush();
    fos.close();
    fis.close();
}

アップデート

解決策: の編集サイズはbuffer16 の倍数です。読み取り/書き込みファイルには CipherInput/Output を使用してください。

TksArtjom B.

4

2 に答える 2

8

AES はブロック暗号であるため、16 バイトのブロックでのみ機能します。CBC などの操作モードを使用すると、複数のブロックを連鎖させることができます。PKCS#5 パディングなどのパディングを使用すると、平文をブロック サイズの次の倍数まで埋めることで、任意の長さの平文を暗号化できます。

問題は、1024 バイトごとに個別に暗号化していることです。1024 はブロック サイズを分割するため、パディングは暗号化の前に完全なブロックを追加します。したがって、暗号文チャンクの長さは 1040 バイトです。次に、復号化中に、パディングが欠落している 1024 しか読み取っていません。Java はそれを復号化し、パディングを削除しようとします。パディングの形式が正しくない場合 (存在しないため)、例外がスローされます。

簡単な修正

復号化用のバッファを 1040 バイトに増やすだけです。

適切な修正

個別のチャンクで暗号化しないでください。Cipher#update(byte[], int, int)代わりにCipher.doFinal使用して、読み取るすべてのバッファの暗号文を更新するか、CipherInputStream.


その他のセキュリティに関する考慮事項:

ランダムな IV がありません。これがないと、攻撃者は暗号文を観察するだけで、同じ鍵で同じ平文を暗号化したことがわかる可能性があります。

暗号文認証がありません。これがないと、暗号文の (悪意のある) 変更を確実に検出できず、パディング オラクル攻撃などの攻撃に対してシステムを開く可能性があります。GCM などの認証済みモードを使用するか、作成した暗号文を HMAC 経由で実行して認証タグを作成し、最後に書き込みます。次に、復号化中/復号化前にタグを検証できます。

于 2015-07-17T11:54:27.547 に答える
0

暗号化されたデータの長さがプレーン データの長さと等しいという誤った仮定の下にありますが、暗号化された AES データは常に AES ブロック サイズ (16 バイト) の倍数であり、追加の完全なパディング ブロックを持つことができます。

ストリーム暗号化を処理する最も効率的な方法は、JCE の CipherOutputStream および CipherInputStream ( http://docs.oracle.com/javase/7/docs/api/javax/crypto/CipherInputStream.html ) を使用することです。これらのクラスは、すべての作業を行います。

また、復号化に使用できるように、暗号化メソッドで新しく生成された IV を常に保存してください。

于 2015-07-17T11:55:18.790 に答える