[Error while persisting/updating sales force data in db for :00530000000dXXnAAM]
java.lang.Exception: javax.crypto.IllegalBlockSizeException text:
"id":"0011300001iidq1AAA","name":"Svebo Sveis L????ft Svein V Bondal","sic":0
message: Input length not multiple of 8 bytes at > com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:1016)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:984)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
at com.sun.crypto.provider.DESedeCipher.engineDoFinal(DESedeCipher.java:294)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
here is code i am using, btw its working in most of the cases but failing for input like above.
for encryption
{
// create a cipher using a key to initialize it
Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
// perform the actual encryption
byte[] ciphertext = cipher.doFinal(text);
return ciphertext;
}
for decryption
{
// create a cipher using a key to initialize it
Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, key, iv);
// perform the decryption
byte[] decryptedText = cipher.doFinal(text);
return decryptedText;
}
The error is quite clear: Input length not multiple of 8 bytes.
You have specified NOPadding, change that to PKCS5Padding.
DES is a block based encryption algorithm, as such the input must be an exact multiple of the block size, 8-bytes for DES. When the input is not always an exact multiple padding must be added, the easiest way to to let the implementation do that for you by specifying padding, generally PKCS#5 for DES.
Note 1:
The code has "DESede/CBC/NOPadding", there is a typo, it should be "DESede/CBC/NoPadding", see Class Cipher.
Note 2:
It is best not to use 3DES and it should not be used in new work, instead use the current standard: AES.
Related
I am trying to decrypt the ResponseText variable which i get from an API. I am getting the following error.
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be
multiple of 16 when decrypting with padded cipher
Below is my code snippet for decrypting the response. The Decrytpt method is throwing the error.
public static String decrypt(String encryptedText) throws Exception
{
Key key = generateKey();
Cipher chiper = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivspec = new IvParameterSpec(iv);
chiper.init(Cipher.DECRYPT_MODE, key, ivspec);
byte[] encVal = chiper.doFinal(encryptedText.getBytes("UTF-8"));
Base64.Encoder base64Encoder = Base64.getEncoder();
String decryptedValue = base64Encoder.encodeToString(encVal);
String decryptedString= new String("");
return decryptedString;
}
I have not posted the actual encrypted value here as the length of the encrypted value is too high. I am new to Java. Thanks in advance.
You should probably base 64 decode the ciphertext, decrypt the binary ciphertext and then decode the resulting plaintext to UTF-8.
You haven't correctly reversed the encryption routine (encode UTF-8, encrypt, encode base64), in other words.
There is a generateKey() for the decryption; unless it returns a static value (and doesn't generate one, as the method name implies) decryption will likely fail. So either the name is wrong, or the decryption.
The IV doesn't seem to be included with the ciphertext either, which will mean that that's the next problem to deal with.
Finally, you will want to know how to handle exceptions for encryption / decryption routines.
Every time the encryption values changed by using AES, let anyone investigate the below code and let me know the issue
code:
private static final String secretKeys = "58BA833E57A51CBF9BF8BAB696BF9"
public static String encrypt() throws Exception {
byte[] salt = new byte[16];
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
PBEKeySpec pbeKeySpec = new PBEKeySpec(secretKeys.getChars(),salt,1000, 256);
Key secretKey = factory.generateSecret(pbeKeySpec);
byte[] key = new byte[32];
byte[] iv = new byte[16];
SecretKeySpec secret = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
byte[] result = cipher.doFinal("welcome".getBytes("UTF-8"));
String s = Base64.getEncoder().encodeToString(result);
return s
}
Output
first time I got the below-encrypted string
CZRIP35M4CnJtuDQ6YpmaQ==
The second time I got the below-encrypted string
/fylTjohAZDsnCaHhiZo3A==
I have three questions:
why the encrypted string not a constant?
how can I set the Blocksize? ( AES.BlockSize = 128;)
How can I set the padding mode? (AES.Padding = PaddingMode.PKCS7;)
For the first question, #Freiheit already answered this.
Long story short, based on the iv (initilization vector) which acts as a salt and will be different for each encryption.
Having that said, encrypting the same plain text will result in different encrypted text, but the decryption (if necessary) will result back into the same plain text.
IV is helpful to make the encryption predictable.
Having stored the same password for 2 different users in a database will have different values, but will be the same password.
With the current cipher configured, you already have 128 block size. You can read more about the different cypher transformation here. You can also find more information of the block sizes for different algorithms here
You just need to change the Cipher.getInstance() to AES/CBC/PKCS7Padding
1) the encrypted text is always different because the Cipher initialization is providing it's own IV since you are not providing one. You need to provide the IV you've "computed" in order to have a consistent output. Remember you never want to use an IV more than once for whatever this code is ultimately intended to do.
2) The keysize can be 128, 192 or 256 but the blocksize is always 128.
3) Java only provides PKCS5, but there is no difference in the implementation for AES. see what-is-the-difference-between-pkcs5-padding-and-pkcs7-padding
As was already pointed out there are several problems with the code provided such as the first lines not actually doing anything and the key and iv both being uninitialized. I would additionally suggest you use SecureRandom to initialize your key and iv. If you plan on using only a single AES key, this can be computed once and placed in the code or configuration file instead of running PBKDF2 every time.
Only adding to the answer provided by #micker, you need to invoke another version of Cipher.init(); one that takes the IV into account:
...
byte[] iv = new byte[16];
IvParameterSpec ivSpec = new IvParameterSpec(iv); // <= Wrap your IV bytes here.
SecretKeySpec secret = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret, ivSpec); // <= Add IV here.
...
That being said, the implementation suffers from a slew of other issues (key being all zeroes, IV being all zeroes, first 4 line don't do anything for you (as #JBNizet pointed out)). I hope you are only using it to study how Java's encryption mechanics works.
I have done Encryption with ,
public static String encrypt(String plainText) {
try {
byte[] keyData = secret_key.getBytes();
SecretKeySpec secretKey = new SecretKeySpec(keyData, "AES/ECB/PKCS7Padding");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] cipherText = cipher.doFinal(plainText.getBytes("UTF-8"));
String encryptedString = Base64.encodeToString(cipherText, Base64.NO_WRAP);
return encryptedString;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
it's working well.
but part of Decryption gives Error like,
W/System.err: javax.crypto.BadPaddingException: pad block corrupted
W/System.err: at com.android.org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(JCEBlockCipher.java:701)
W/System.err: at javax.crypto.Cipher.doFinal(Cipher.java:1111)
decrypt Code like,
public static String decrypt(String encryptedText) {
try {
byte[] keyData = secret_key.getBytes();
SecretKeySpec secretKey = new SecretKeySpec(keyData, "AES/ECB/PKCS7Padding");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] cipherText = Base64.decode(encryptedText,Base64.NO_WRAP);
String decryptedString = new String(cipher.doFinal(cipherText),"UTF-8");
return decryptedString;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
here what is the problem? How can i solve this Issue?
It is likely that your secret_key value contains bytes which are not well represented in the ambiguous encoding you're using. When you call String#getBytes() without specifying an encoding, you get the system default, which can vary.
You should use hexadecimal encoding whenever you represent your key as a String. This will be consistent across serialization/deserialization on every platform. There are many standard implementations of this encoding/decoding process available (i.e. org.bouncycastle.util.encoders.Hex.decode("0123456789ABCDEFFEDCBA9876543210"); or org.apache.commons.codec.binary.Hex.decodeHex("0123456789ABCDEFFEDCBA9876543210".toCharArray()); which both return the raw byte[]).
Some side notes:
You are using ECB mode of operation, which is extremely susceptible to frequency analysis for cryptanalysis and is effectively deprecated aside from toy crypto demonstrations. I suggest you use CBC, CTR, or GCM.
You do not provide an initialization vector (IV), so the same message encrypted with the same key will always yield identical cipher text. Use a unique and non-predictable IV for every encryption operation by generating 16 bytes from SecureRandom and populating it into an IvParameterSpec. You can prepend the IV bytes to the cipher text and transport/store it in the clear.
Your cipher text is not authenticated, allowing for malicious users to both manipulate encrypted data and to attempt decryption via padding oracle/CCA attacks. Use an authenticated encryption with associated data (AEAD) mode like GCM, or use an HMAC/SHA-256 message authentication code (MAC) over the cipher text, and verify it using a constant-time equals method before attempting any decryption.
You do not need to provide the mode of operation or padding scheme when instantiating a key. SecretKey key = new SecretKeySpec(keyData, "AES"); is sufficient.
I used following code to encrypt the data. My input is 16 bytes and key is 16 bytes but the output I am getting (encrypted data ) is 32 bytes. Why?
public static byte[] encrypt(byte[] plainText, byte[] key) {
try {
byte[] passwordKey128 = Arrays.copyOfRange(key, 0, 16);
SecretKeySpec secretKey = new SecretKeySpec(passwordKey128, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] cipherText = cipher.doFinal(plainText);
// String encryptedString = Base64.getEncoder().encodeToString(cipherText);
return cipherText;
What can be the reason? Does AES add some data?
You obtain Cipher object through the Cipher.getInstance(transformation) method where the transformation is of the form:
"algorithm/mode/padding" or
"algorithm"
When you do this the implementation searches through the list of crypto providers in the system and determine if any implementation supports this. If you don't specify the mode and padding, its up to the crypto provider to decide what default mode and padding to use.
According to this, For example, the SunJCE defaults to ECB as the default mode, and PKCS5Padding.
As PKCS5Padding always adds at least one byte, it pushes your 16 bytes over the limit of the block and creates the need for two blocks.
i modified the code available on
http://java.sun.com/developer/technicalArticles/Security/AES/AES_v1.html
and made encrypt and decrypt methods in program. but i am getting BadpaddingException..
also the function is returning null..
why it is happing?? whats going wrong? please help me..
these are variables i am using:
kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
raw = new byte[]{(byte)0x00,(byte)0x11,(byte)0x22,(byte)0x33,(byte)0x44,(byte)0x55,(byte)0x66,(byte)0x77,(byte)0x88,(byte)0x99,(byte)0xaa,(byte)0xbb,(byte)0xcc,(byte)0xdd,(byte)0xee,(byte)0xff};
skeySpec = new SecretKeySpec(raw, "AES");
cipher = Cipher.getInstance("AES");
plainText=null;
cipherText=null;
following is decrypt function..
public String decrypt(String cipherText)
{
try
{
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original = cipher.doFinal(cipherText.getBytes());
plainText = new String(original);
}
catch(BadPaddingException e)
{
}
return plainText;
}
From the Java-Security archives
One common mistakes that people made is to put the encrypted bytes inside a
string and upon decryption they use String.getBytes() to retrieve it.
Since String does its own character encoding, the byte[] that you used to
construct the String object and the byte[] that you get from its getBytes()
are not necessarily equal.
Where is cipherText actually coming from? It needs to be a "raw" byte array (not a string), and needs to have been encrypted in a way that the Cipher can understand.
AES (and block ciphers in general) can be run in different "block modes" and with different "padding", and when you instantiate a Cipher, you should indicate which block mode you're using (or which was used to originally encrypt the data). If you get a BadPaddingException when passing in raw bytes, then it generally means the data has been encrypted using a different mode or padding. (In this case, it could just be an artefact of converting the data to a String, as I think another poster has mentioned.)
Some information I've written that might be helpful:
AES and block ciphers in Java
block modes
Since you've shown very little code it's hard to help predict what might be causing the exception.
plainText is null because it is initialized to null and the decrypt function is throwing an exception before assigning a value to plainText.
What do you do with kgen? In the example you linked to it is used to generate the raw byte array for the secret key spec. In your variable instantiation list you manually define the raw byte array.
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); // 192 and 256 bits may not be available
// Generate the secret key specs.
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");