16

実際、私はインターネットから多くを検索し、これについてもstackoverflowで検索しました。

最初は、暗号化と復号化にパディングを使用しませんでしたが、

しかし、最後にここから解決策を得ました

https://stackoverflow.com/a/10775577/1115788

そして、AES/CBC/PKCS5Padding としてパディングを使用してコードを更新しましたが、同じエラーが発生し、最後のブロックが復号化されていません...

過去2日間これに取り組んでいますが、解決策が見つかりません

私のクリプターコード:

package mani.droid.browsedropbox;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class Crypter {

    Cipher encipher;
    Cipher decipher;
CipherInputStream cis;
CipherOutputStream cos;
FileInputStream fis;
byte[] ivbytes = new byte[]{(byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e',                                                                                          (byte)'f', (byte)'g', (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m',     (byte)'n', (byte)'o', (byte)'p'};
    IvParameterSpec iv = new IvParameterSpec(ivbytes);

public boolean enCrypt(String key, InputStream is, OutputStream os)
{
    try {
        byte[] encoded = new BigInteger(key, 16).toByteArray();
        SecretKey seckey = new SecretKeySpec(encoded, "AES");
        encipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        encipher.init(Cipher.ENCRYPT_MODE, seckey, iv);
        cis = new CipherInputStream(is, encipher);
        copyByte(cis, os);
        return true;
    } 
    catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidAlgorithmParameterException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return false;
}

public boolean deCrypt(String key, InputStream is, OutputStream os)
{
    try {
        byte[] encoded = new BigInteger(key, 16).toByteArray();
        SecretKey seckey = new SecretKeySpec(encoded, "AES");
        encipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        encipher.init(Cipher.DECRYPT_MODE, seckey, iv);
        cos = new CipherOutputStream(os, encipher);
        copyByte(is, cos);
        //cos.close();
        return true;
    } 
    catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidAlgorithmParameterException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return false;
}

public void copyByte(InputStream is, OutputStream os) throws IOException
{
    byte[] buf = new byte[8192];
    int numbytes;
    while((numbytes = is.read(buf)) != -1)
    {
        os.write(buf, 0, numbytes);
        os.flush();
    }
    os.close();
    is.close();
}
}
4

6 に答える 6

16

私はまったく同じ問題を抱えていました。パディングを必要としない暗号モードを使用したため、受け入れられた解決策は機能しますが、これは暗号関連の問題が修正される方法ではありません。

CipherOutputStream のドキュメントによると、暗号化を適切に完了するには、close() メソッドを呼び出す必要があります (つまり、パディング ブロックが追加されます)。

このメソッドは、カプセル化された暗号オブジェクトの doFinal メソッドを呼び出します。これにより、カプセル化された暗号によってバッファリングされたすべてのバイトが処理されます。結果は、この出力ストリームの flush メソッドを呼び出すことによって書き出されます。

このメソッドは、カプセル化された暗号オブジェクトを初期状態にリセットし、基になる出力ストリームの close メソッドを呼び出します。

CipherOutputStream.close() メソッドを呼び出した後も OutputStream を開いたままにしたい場合は、OutputStream を閉じないストリームにラップすることができます。例えば:

public class NotClosingOutputStream extends OutputStream {
  private final OutputStream os;

  public NotClosingOutputStream(OutputStream os) {
    this.os = os;
  }

  @Override
  public void write(int b) throws IOException {
    os.write(b);
  }

  @Override
  public void close() throws IOException {
    // not closing the stream.
  }

  @Override
  public void flush() throws IOException {
    os.flush();
  }

  @Override
  public void write(byte[] buffer, int offset, int count) throws IOException {
    os.write(buffer, offset, count);
  }

  @Override
  public void write(byte[] buffer) throws IOException {
    os.write(buffer);
  }
}

次に、次を使用できます。

...
cos = new CipherOutputStream(new NotClosingOutputStream(os), encipher);
copyByte(is, cos);
cos.close();
...

osストリームは閉じられないことに注意してください。必要に応じて自分で行う必要があります。

于 2014-03-20T23:24:14.677 に答える
7

試行錯誤しながらようやく自問自答しました 実はここで Conflict is I set Padding inencipher = Cipher.getInstance("AES/CBC/PKCS7Padding");

いくつかの値でIVを設定.....

最後に、アルゴリズムを置き換えただけの回答を得ました

から:

AES/CBC/PKCS7パディング

に:

AES/CFB8/NoPadding

そしてそれは魅力のように機能しました....だから、この問題に苦しんでいる他の人にこの答えを提案します。あなたが問題を解決した場合は、他の人のためにここに言及してください...

于 2012-10-10T11:20:12.213 に答える
0

これがOPの問題に関連しているかどうかはわかりませんが、これは誰かを助けるかもしれません.

変更内容に関係なく、繰り返し取得java.io.IOException: last block incomplete in decryption する場合は、以前の実行からのファイルをまだ使用しているかどうかを確認してください。読み取り/書き込みテスト コードがそのファイルに追加されると、書き込み先の破損したファイルを削除しない限り、常にその例外が発生します。

于 2015-03-05T14:04:30.410 に答える
0

CipherInputStream がパディングの問題でも失敗するのを見てきました。この動作は、JVM のバージョンによって異なります。たとえば、7u55 32 ビットのコードは正常に動作し、7u55 64 ビットの同じコードは失敗しました...そして、後の 32 ビット JVM でも失敗が見られました。回避策は、バイト配列メソッドを使用し、CipherInputStream を回避することでした。

于 2014-10-29T06:53:28.423 に答える