This question already has answers here:
InvalidKeyException Illegal key size
(6 answers)
Closed 6 years ago.
I'm trying to decrypt with AES some data. I've been given a 256 bit key and 16 byte IV like these:
String key = "Hh1s1f4T2mpN3yCh4ngeL8t3r\\.Thxpp";
int[] v = {11, 1, 555, 222, 241, 21, 11, 33, 35, 91, 45, 6, 14, 30, 22, 234};
String IV = Arrays.toString( v );
I've been told the padding should be PKCS7 but when I init the cipher with AES/CBC/PKCS7PADDING it says: Cannot find any provider supporting AES/CBC/PKCS7PADDING
If I use AES/CBC/PKCS5PADDING I get Illegal key size but I've checked that the key size is 32.
public static String decrypt(String key, String initVector, String encrypted) {
try {
System.out.println( "Key size: " + key.getBytes("UTF-8").length );
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
If you are getting an IllegalKeySize exception with AES-256, check to ensure you have the JCE Unlimited Cryptographic Strength Policy files installed in your active JVM. They are required for any AES key length over 128 bits.
(PKCS #7 padding scheme is effectively equivalent to PKCS #5 in Java (the block size differs in the spec definitions), but Java never added the PKCS #7 name to its list, so using PKCS5Padding is correct.)
First see the answer by #Andy.
If you are getting an "Illegal key size" error then the key size is incorrect, you need to figure out why by debugging. Create a variable for the UTF-8 key
byte[] keyBytes = key.getBytes("UTF-8")
and display it as hex, that way you can see exactly what it happening.
Inline conversions are essentially impossible to debug.
PKCS#5 padding is a subset of PKCS#7 padding and in every instance it is the same, PKCS#5 is just a name holdover from DES by lazy developers.
PKCS#7 padding:
PKCS#5 padding is identical to PKCS#7 padding, except that it has only been defined for block ciphers that use a 64-bit (8 byte) block size. In practice the two can be used interchangeably.
You need to use bouncy castle as a provider for PKCS7PADDING.
Related
For algorithm test vector evaluation, I am trying to perform an AES in GCM mode for encryption and decryption with arbitrary tag length values such as 32 bits.
When I try to initialize my cipher with such an arbitrary tag length as follows:
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec parameterSpec = new GCMParameterSpec(tagLen, iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
I am met with this error:
java.security.InvalidAlgorithmParameterException: Unsupported TLen value; must be one of {128, 120, 112, 104, 96}
Normally, this would be a good thing, because you don't want a tag length of 32. However, for my purposes I do need this tag length.
Is there a way that I can override these restrictions to allow for arbitrary tag lengths?
The Bouncy Castle library was created to support many algorithms in software, with the caveat that it let's you shoot yourself in the foot if you really want to.
I can run the above code with tag size 32 without issue:
Security.addProvider(new BouncyCastleProvider());
SecretKeySpec secretKey = new SecretKeySpec(new byte[16], "AES");
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
GCMParameterSpec parameterSpec = new GCMParameterSpec(32, new byte[16]);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
cipher.update("Maarten did it".getBytes(StandardCharsets.UTF_8));
byte[] ct = cipher.doFinal();
Note that the error can be seen e.g. here. As you can see that is the internal implementation of AES/GCM in the provider, not e.g. Cipher. You may have found that out by looking at the full stacktrace...
[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.
I have research many source code and find difficulty on how to specify block size in AES java? Does java support until 256 bits? I have search out php source code and it support until 256 bits AES encryption
This is the sample source code for AES encryption. Thanks all for helping me to figure out.
http://aesencryption.net/
PHP supports Rijndael with a 256 block size. AES is a subset of Rijndael with key sizes of 128, 192 and 256 bits and a block size of 128 bits. So saying that PHP supports AES with a blocksize of 256 bit is a contradiction (i.e. incorrect).
Java SE (up to and including Java 9) by Oracle only supports AES with a 128 bit block size and all (3) AES key sizes, although you need the Unlimited Crypto files to use 192 and 256 bit encryption.
To use Rijndael with 256 bit block size you could use Bouncy Castle lightweight API, the different block sizes aren't added to the Bouncy Castle provider either:
new RijndaelEngine(256)
For Android you may want to use Spongy Castle instead.
TRY IT:
public static void main(String[] args) {
String key = "1234567890ABCDEF";
try {
byte[] encrypt = encrypt("hello word",key);
System.out.println(new String(encrypt));
String decrypt = decrypt(encrypt, key);
System.out.println(decrypt);
} catch (Exception ex) {
}
}
public static byte[] encrypt(String message, String key1) throws Exception {
SecretKeySpec key = new SecretKeySpec(key1.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "SunJCE");
cipher.init(Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(message.getBytes());
}
public static String decrypt(byte[] message, String key1) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "SunJCE");
SecretKeySpec key = new SecretKeySpec(key1.getBytes(), "AES");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptedByte = cipher.doFinal(message);
String decryptedText = new String(decryptedByte);
return decryptedText;
}
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 am using 3DESC to decrypt data but i am getting following exception
java.security.InvalidKeyException: Invalid key length: 16 bytes
My Code:
public static byte[] decrypt3DESCBC(byte[] keyBytes, byte[] ivBytes,
byte[] dataBytes) {
try {
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
SecretKeySpec newKey = new SecretKeySpec(keyBytes, "DESede");
Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec); // Causes Exception
return cipher.doFinal(dataBytes);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Printed all the byte array above used
keyBytes : FC15780BB4B0**********0876482C1B // Masked 10 Characters
ivBytes : 0000000000000000
dataBytes : AF53C90F7FAD977E**********69DB5A2BF3080F9F07F4BFEA3EDB4DE96887BE7D40A5A590C0911A // Masked 10 Characters
DES-EDE cipher can be used with 3 different subkeys therefore the key size should be 24 bytes (3 times 8 bytes). If you want to use only 2 keys (i.e. in this mode first key == last key) then you just have to duplicate the first 8 bytes of the key array.
byte[] key;
if (keyBytes.length == 16) {
key = new byte[24];
System.arraycopy(keyBytes, 0, key, 0, 16);
System.arraycopy(keyBytes, 0, key, 16, 8);
} else {
key = keyBytes;
}
You are using an older Java version that does not handle 128 bit key lengths. In principle, 3DES always uses three keys - keys ABC - which are 64 bit each when we include the parity bits into the count (for a single DES encrypt with A, then decrypt with B, then encrypt again with C). 128 bit (dual) key however uses A = C. So to create a valid 24 byte key, you need to copy and concatenate the first 8 bytes to the tail of the array. Or you could upgrade to a newer JRE, or use a provider that does accept 16 byte 3DES keys.
Note that 192 bit (168 bit effective) 3DES keys are quite a bit more secure than 128 (112 bit effective) bit keys; 128 bit 3DES is not accepted by NIST (which handles US government standardization of cryptography) anymore. You should try and switch to AES if possible; AES doesn't have these kind of shenanigans and is much more secure.