web-dev-qa-db-ja.com

javax.crypto.BadPaddingException

私はAESアルゴリズムに取り組んでいますが、解決できないこの例外があります。

javax.crypto.BadPaddingException: Given final block not properly padded
at com.Sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.Sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.Sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)

例外は復号化部分で発生します。復号化アルゴリズムが存在する場所とは異なる場所でキーを初期化します

KeyGenerator kgen = KeyGenerator.getInstance("AES");//key generation for AES
kgen.init(128); // 192 and 256 bits may not be available

次に、ファイルから読み取った暗号テキストを次のメソッドに渡します

 public String decrypt(String message, SecretKey skey) {

    byte[] raw = skey.getEncoded();
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
    // Instantiate the cipher
    Cipher cipher;

    byte[] original = null;
    try {
        cipher = Cipher.getInstance("AES");

        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        System.out.println("Original string: "
                + message);
        original = cipher.doFinal(message.trim().getBytes());  //here where I got the exception
        String originalString = new String(original);
       }
 //catches

[〜#〜] edit [〜#〜]これが暗号化方法です。

public String encrypt(String message, SecretKey skey) {
    byte[] raw = skey.getEncoded();
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");

    // Instantiate the cipher

    Cipher cipher;
    byte[] encrypted = null;
    try {
        cipher = Cipher.getInstance("AES");

        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);

        encrypted = cipher.doFinal(message.getBytes());
        System.out.println("raw is " + encrypted);

    } catches
    return asHex(encrypted);
}

ここにasHexメソッドがあります

  public static String asHex(byte buf[]) {
    StringBuffer strbuf = new StringBuffer(buf.length * 2);
    int i;

    for (i = 0; i < buf.length; i++) {
        if (((int) buf[i] & 0xff) < 0x10) {
            strbuf.append("0");
        }

        strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
    }

    return strbuf.toString();
}

ここからファイルから暗号文を読みます

static public String readFile(String filePath) {
    StringBuilder file = new StringBuilder();
    String line = null;
    try {
        FileReader reader = new FileReader(filePath);
        BufferedReader br = new BufferedReader(reader);
        if (br != null) {
            line = br.readLine();
            while (line != null) {
                file.append(line);
                //      System.out.println("line is " + line);
                line = br.readLine();

            }
        }
        br.close();
        reader.close();
    } catch (IOException ex) {
        Logger.getLogger(FileManagement.class.getName()).log(Level.SEVERE, null, ex);
    }
    System.out.println("line is " + file.toString());
    return String.valueOf(file);

}

誰か助けてもらえますか?

19
palAlaa

わかりました。したがって、問題は、暗号化されたバイトを(asHexメソッドを使用して)16進文字列に変換しているが、復号化のために16進文字列をバイト配列に正しく変換していないことです。 getBytesは使用できません。

次の method を使用して、16進文字列をバイト配列に変換できます。

public static byte[] fromHexString(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                             + Character.digit(s.charAt(i+1), 16));
    }
    return data;
}

次に、使用する復号化方法を変更します。

original = cipher.doFinal(fromHexString(message));
14
dogbane

Bad Padding Exceptionが発生しましたが、インターネットで問題の解決策を見つけることができませんでした。勤勉な時間を経て見つけたので、ここにあげます。

私の問題は、ハードドライブ上のファイルを読み取り、バッファを介して暗号化し、常にupdate()メソッドではなくdoFinal()メソッドを呼び出すことでした。それを解読するとき、私はパディングエラーがありました

    input = new FileInputStream(file);
    output = new FileOutputStream(newFile);

    Cipher cipher = Cipher.getInstance("DES");
    cipher.init(Cipher.ENCRYPT_MODE, mySecretKey);

    byte[] buf = new byte[1024];

    count = input.read(buf);
    while (count >= 0) {
        output.write(cipher.update(buf, 0, count)); // HERE I WAS DOING doFinal() method
        count = input.read(buf);
    }
    output.write(cipher.doFinal()); // AND I DID NOT HAD THIS LINE BEFORE
    output.flush();

そして、同じ方法で、ただしDECRYPT_MODEを使用したCipher initで復号化する場合

    input = new FileInputStream(file);
    output = new FileOutputStream(newFile);

    Cipher cipher = Cipher.getInstance("DES");
    cipher.init(Cipher.DECRYPT_MODE, mySecretKey);

    byte[] buf = new byte[1024];

    count = input.read(buf);

    while (count >= 0) {
        output.write(cipher.update(buf, 0, count)); // HERE I WAS DOING doFinal() method

        //AND HERE WAS THE BadPaddingExceotion -- the first pass in the while structure

        count = input.read(buf);
    }
    output.write(cipher.doFinal()); // AND I DID NOT HAD THIS LINE BEFORE
    output.flush();

コードが記述されたため、BadPaddingExceptionはなくなりました。

この例外は、元のクリアファイルの長さ(file.length()で取得)がバッファよりも大きい場合にのみ表示されると正確に判断できます。それ以外の場合、while構造体で数回渡す必要はなく、doFinal()呼び出しを使用して1回のパスで暗号化できます。これは、暗号化しようとするファイルのサイズに続く例外のランダムな文字を正当化します。

あなたが良い読書をしたことを願っています!

4
Mav3656

message.trim().getBytes()は、メッセージを暗号化したときに生成されるのと同じバイトを返さないと思います。特に、trim()メソッドは、暗号化されたメッセージにパディングとして追加されたバイトを削除できます。

暗号化中にdoFinal()メソッドの返された配列とmessage.trim().getBytes()の返された配列の両方を確認します。

  1. 同じバイト数(配列の長さ)を取得しました
  2. 配列内で同じバイトを得た
1
Progman
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(512);
KeyPair rsaKeyPair = kpg.genKeyPair();
byte[] txt = "This is a secret message.".getBytes();
System.out.println("Original clear message: " + new String(txt));

// encrypt
Cipher cipher;
try
{
    cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.ENCRYPT_MODE, rsaKeyPair.getPublic());
    txt = cipher.doFinal(txt);
}
catch (Throwable e)
{
    e.printStackTrace();
    return;
}
System.out.println("Encrypted message: " + new String(txt));

// decrypt
try
{
    cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.DECRYPT_MODE, rsaKeyPair.getPrivate());
    txt = cipher.doFinal(txt);
}
catch (Throwable e)
{
    e.printStackTrace();
    return;
}
System.out.println("Decrypted message: " + new String(txt));
0
Jaya shree