BadPaddingException just with letters like “o”, “b”, “c”

问题: I'm making a program which works with messages cryptography by Socket. But, when in my messages has a "o", or "b", or "c" and another letters, i receives that Exception in...

问题:

I'm making a program which works with messages cryptography by Socket. But, when in my messages has a "o", or "b", or "c" and another letters, i receives that Exception in the decrypto moment.

Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
    at com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:975)
    at com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1056)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:853)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
    at javax.crypto.Cipher.doFinal(Cipher.java:2164)
    at teste1.Decrypt.decrypt(Decrypt.java:15)
    at teste1.Server.main(Server.java:24)

Yep, my message arrives completed with all the characters, so i don't think in some character was lost in the trasmission. So i don't really know what's the problem, because i've tried to changes a lot of things, but i continued recieving this Exception.

Decrypt class:

package teste1;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;

public class Decrypt{

    String IV = "AAAAAAAAAAAAAAAA";

    public String decrypt(String str, String keys) throws Exception{
        Cipher decrypt = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");
        SecretKeySpec key = new SecretKeySpec(keys.getBytes("UTF-8"), "AES");
        decrypt.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(IV.getBytes("UTF-8")));
        return new String(decrypt.doFinal(str.getBytes()),"UTF-8");
    }

}

If wants the encrypt class too:

package teste1;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class Encrypt {

    String IV = "AAAAAAAAAAAAAAAA";

    public byte[] encrypt(String menE, String keys) throws Exception {
        Cipher encrypt = Cipher.getInstance("AES/EBC/PKCS5Padding", "SunJCE");
        SecretKeySpec key = new SecretKeySpec(keys.getBytes("UTF-8"), "AES");
        encrypt.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(IV.getBytes("UTF-8")));
        return encrypt.doFinal(menE.getBytes());
    }
}

回答1:

That happens because Strings change your bytes, you should really use Base64 if strings are a must.

If you want to test that run this code:

byte[] aByte = {-45};
System.out.println(Arrays.toString(new String(aByte, StandardCharsets.UTF_8).getBytes(StandardCharsets.UTF_8)));

It will output: [-17, -65, -67] (which is not -45).

Anyways so a few tips for you:

  • You cannot encrypt with "ECB" and decrypt with "CBC".
  • An IV should not be a constant. you should generate a new IV for every message and send it along with the message.
  • Don't specify "UTF-8" use StandardCharsets.UTF_8 (note if using android: StandardCharsets.UTF-8 is API 19+ so you should have a constant for Charset.forName("UTF-8"))

Here is some example code for how to do it with Base64:

public byte[] encrypt(String message, String key, String iv) throws Exception {
        Cipher encrypt = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");
        SecretKeySpec secretKey = new SecretKeySpec(Base64.getDecoder().decode(key), "AES");
        encrypt.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(Base64.getDecoder().decode(iv)));
        return encrypt.doFinal(/*Get bytes from your message*/message.getBytes(StandardCharsets.UTF_8));
    }

    public String decrypt(String encryptedMessage, String key, String iv) throws Exception{
        Cipher decrypt = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");
        SecretKeySpec secretKey = new SecretKeySpec(Base64.getDecoder().decode(key), "AES");
        decrypt.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(Base64.getDecoder().decode(iv)));
        return new String(decrypt.doFinal(Base64.getDecoder().decode(encryptedMessage)), StandardCharsets.UTF_8);
    }

And run it with

//your message
    String message = "Hello World!";
    //generate a new AES key. (an AES key is just a random sequence 16 bytes)
    SecureRandom random = new SecureRandom();
    byte[] aesKey = new byte[16];
    random.nextBytes(aesKey);
    //generate a new initialization vector (iv) which is also a random sequence of 16 bytes.
    byte[] iv = new byte[16];
    random.nextBytes(iv);

    String aesKeyAsString = Base64.getEncoder().encodeToString(aesKey);
    String ivAsString = Base64.getEncoder().encodeToString(iv);
    //encrypt
    byte[] encrypted = encrypt(message, aesKeyAsString, ivAsString);
    //enocde your encrypted byte[] to String
    String encryptedString = Base64.getEncoder().encodeToString(encrypted);
    //decrypt
    String decrypted = decrypt(encryptedString, aesKeyAsString, ivAsString);
    //print your results
    System.out.println("Encrypted: " + encryptedString + " Decrypted: " + decrypted);

Outputs:

Encrypted: |encrypted string depended on the generated key and iv| Decrypted: Hello World!

You can also use the more efficient way and use byte[] instead of Strings but it's your choice.

  • 发表于 2019-03-29 01:40
  • 阅读 ( 505 )
  • 分类:sof

条评论

请先 登录 后评论
不写代码的码农
小编

篇文章

作家榜 »

  1. 小编 文章
返回顶部
部分文章转自于网络,若有侵权请联系我们删除