BadPaddingException: Given final block not properly padded due to different java version - java

I java 8 installed on client side where I am encrypting my data file using the below technique
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
outputStream = new CipherOutputStream(new FileOutputStream(encryptedFile), cipher);
And now i am decrypting on server side where i have Java 7 installed as per the code below.
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
inputStream = new CipherInputStream(new FileInputStream(encryptedFile), cipher);
outputStream = new FileOutputStream(decryptedFileName);
Doing so give me below error
Caused by: java.io.IOException: javax.crypto.BadPaddingException: Given final block not properly padded
at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:115) [jce.jar:1.7.0_71]
at javax.crypto.CipherInputStream.read(CipherInputStream.java:233) [jce.jar:1.7.0_71]
at javax.crypto.CipherInputStream.read(CipherInputStream.java:209) [jce.jar:1.7.0_71]
Same code works fine when i have same java version (1.7) installed on both side.
How can we fix this so that without changing the java version either of the side

There are a number of possible causes for this issue:
You don't specify how you are getting/generating the key. If your JREs differ in their possession/absence of the JCE Unlimited Strength Jurisdiction Policies, one will support 256-bit AES encryption and the other will only support 128-bit. If you are generating a key based on the available key lengths, this could be causing the keys not to match. Meanwhile, both of your Java 7 environments may have the same level policies installed.
You are not specifying the block cipher mode of operation or padding scheme on either side of the system -- I recommend an AEAD mode like GCM, EAX, or CCM (CTR + CBC-MAC) in conjunction with NoPadding, but even CBC/PKCS5Padding or CTR/NoPadding are better than the default AES/ECB/PKCS5Padding that you will get just by invoking Cipher.getInstance("AES").
You don't explain how you are encoding the cipher text before persisting it and then deserializing it for decryption. Without a safe encoding scheme like hexadecimal or Base64, you may (read: eventually will) encounter encoding issues working with raw binary values.
Once you change from ECB to another mode of operation, you will need to provide the initialization vector (IV) for both encryption and decryption, and transmit the IV alongside the cipher text. The IV does not need to be encrypted in any way, but it must be unique and non-predictable for each message encrypted with the same key. As it is always the block size of the cipher (fixed at 16 bytes/128 bits for AES), simply prepend the cipher text with the IV value and then split it for decryption.
AES (and all symmetric cryptography) uses the same key for encryption and decryption -- there are no public and private keys involved. It could just be a naming issue, but the fact that you are trying to decrypt with publicKey may indicate the wrong key being used. You should verify that both the encryption and decryption keys are byte-identical (same length (16, 24, or 32 bytes) and equal). ECB "decryption" will always "succeed" if the cipher text is an exact multiple of the block size (16 bytes). Then the padding is verified. If you attempt to decrypt a message with the wrong key, you will often (255/256 times) get a padding error. The other case is that the last byte decrypts to 0x01, which is a valid padding value for PKCS #5/#7, so it won't detect a padding error.
Demonstration that AES/ECB/PKCS5Padding is the default on Java 8 (1.8.0_101):
#Test
public void testCipherGetInstanceShouldDefaultToECB() throws Exception {
// Arrange
final String PLAINTEXT = "This is a plaintext message."
final SecretKey key = new SecretKeySpec(Hex.decodeHex("0123456789ABCDEFFEDCBA9876543210" as char[]), "AES")
Cipher unspecified = Cipher.getInstance("AES")
final Cipher EXPECTED_CIPHER = Cipher.getInstance("AES/ECB/PKCS5Padding")
unspecified.init(Cipher.ENCRYPT_MODE, key)
EXPECTED_CIPHER.init(Cipher.DECRYPT_MODE, key)
// Act
byte[] cipherBytes = unspecified.doFinal(PLAINTEXT.getBytes(StandardCharsets.UTF_8))
logger.info("Cipher text: ${Hex.encodeHexString(cipherBytes)}")
// Assert
byte[] recoveredBytes = EXPECTED_CIPHER.doFinal(cipherBytes)
String recovered = new String(recoveredBytes, StandardCharsets.UTF_8)
assert recovered == PLAINTEXT
}

Related

AES Encryption 256 ECB Mode

I tried to encrypt my plain data "hello" with key "01234567891234567890123456789012" but the problem is my encrypted code is not the same with the online reference.
Here is my android code written:
String smykey = "01234567891234567890123456789012";
String hellos = "hello";
SecretKeySpec key = new SecretKeySpec(smykey.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");//("AES/ECB/PKCS7Padding");//("ECB");//("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypted = cipher.doFinal(hellos.getBytes());
code produce,
android: 0x25 0x66...0x2d 0x87 (32 bytes)
ref: 0xa3 0xef...0x68 0x9f (16 bytes)
What's wrong with this Android code? someone I appreciate your help please?
The online reference is doing something different, the Android code produces the correct encrypted data.
The data hellos is not a multiple of the block size (16-bytes) so you must specify padding (PKCS#7).
Android is using PKCS#7 padding and 25669d21 dfd0fd6f cfef6cce 4ef12d87 is the correct result for AES with a 256-bit key, ECB mode and PKCS#7 padding.
smykey and hellos were converted to data using UTF-8 encoding.
It is a rare case where ECB mode is used, it is not secure, use CBC mode with a random iv (prepend the iv to the encrypted data). Do not return padding errors on decryption.
Use an HMAC or better yet a key extending function such as PBKDF2 to securely except a string passcode to a secure encryption key. Using a string directly as a key is not secure.

Compatible AES algorithm for Java and Javascript

I need to encrypt some values in Java application using AES algorithm, and decrypt the same in my Javascript module of my application.
I saw some examples over the internet but it seems there's some differences in compatibility.
like below issue :
AES encryption in javascript and decrypting in java
Can someone please point me some code examples to solve this issue.
Thanks.
AES is an exactly specified algorithm, so all AES implementations must be "compatible". Having said that, AES is a variable-key-length block-cipher, operating on 128-bit blocks. To actually use this in a piece of software, you have to make a bunch of other choices: how to deal with input consisting of more than 1 block (this is called the "mode"), in some modes you need an initialization vector, you need to deal with input not consisting of an exact number of blocks (padding), how to encode characters into bytes, and how to represent bytes in a context (like a source file) that doesn't support that. All those things need to be compatible.
Below is a tested example. It uses the standard Java crypto functions (and Apache Commons Codec), and JavaScript crypto library crypto-js. Choices are as follows: 128-bit key, cipher-block-chaining mode (which needs an initialization vector), PKCS5/7 padding, UTF-8 for character encoding, Base64 to represent byte arrays.
This piece of Java will output Base64-encoded ciphertext:
String plainText = "Hello, World! This is a Java/Javascript AES test.";
SecretKey key = new SecretKeySpec(
Base64.decodeBase64("u/Gu5posvwDsXUnV5Zaq4g=="), "AES");
AlgorithmParameterSpec iv = new IvParameterSpec(
Base64.decodeBase64("5D9r9ZVzEYYgha93/aUK2w=="));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
System.out.println(Base64.encodeBase64String(cipher.doFinal(
plainText.getBytes("UTF-8"))));
This piece of JavaScript correctly decrypts it:
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
<script>
var encrypted = CryptoJS.enc.Base64.parse('3Q7r1iqtaRuJCo6QHA9/GhkTmbl4VkitV9ZsD3K2VB7LuBNg4enkJUA1cF8cHyovUH2N/jFz3kbq0QsHfPByCg==');
var key = CryptoJS.enc.Base64.parse('u/Gu5posvwDsXUnV5Zaq4g==');
var iv = CryptoJS.enc.Base64.parse('5D9r9ZVzEYYgha93/aUK2w==');
document.write(CryptoJS.enc.Utf8.stringify(CryptoJS.AES.decrypt(
{ ciphertext: encrypted },
key,
{ mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, iv: iv, })));
</script>

256 bits Blowfish encryption in java

I am trying to encrypt data and send them to the server bye using 256 bits blowfish, but I do not know what is the proper provider for the key size. I have tried to change the CFB32 and CFB8 but does not work I have tried iv with 8 16 and 32 but it does not work. I have tried OAEPWithSHA-256AndMGF1Padding also it did not work.
and when I used blowfish/ECB/PKCS1Padding it gave me message that can not find any provider support blowfish/ECB/PKCS1Padding.
// Create a Blowfish key
KeyGenerator keyGenerator = KeyGenerator.getInstance("Blowfish");
// Now set the keysize to 256 bits
keyGenerator.init(256);
Key key = keyGenerator.generateKey();
System.out.println("Done generating the key.");
// Create a cipher using that key to initialize it
Cipher cipher = Cipher.getInstance("Blowfish/CFB8/NoPadding");
//Cipher encrypter = Cipher.getInstance("Blowfish/C/NoPadding");
System.out.println("good here");
SecureRandom random = new SecureRandom();
byte[] iv = new byte[16];
random.nextBytes(iv);
IvParameterSpec spec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, key,spec);
If you get the "java.security.InvalidKeyException: Illegal key size" when trying to use key size of 256, then you need to to download JCE Unlimited Strength Jurisdiction Policy Files for your JDK/JRE. The unlimited policy will allow you to use key sizes greater than the predefined limits (128 bits for blowfish).
The Oracle JDK 7 unlimited JCE policy can be downloaded here, make sure to read the readme.txt included in the archive and follow the instuctions.
If you get the "java.security.InvalidAlgorithmParameterException: Wrong IV length: must be ??? bytes long" then you have a mismatch between the actual IV array length and the IV length expected by the mode and padding specified in the Cipher.getInstance() argument. For "Blowfish/CFB8/NoPadding" the IV should be 8 bytes long, but in your code you create a 16-bytes long IV array.
If you have some other problems then you should really update your question and specify what the actual problem is and what the actual exception (preferably with the stacktrace) is.
For 256 bit Keysize, need to add JCE jar in project and referred code will work for that.
JCE Jar : http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
BlowfishUtility: https://github.com/NikhilPareek88/BlowfishUtility

Decrypting a hardcoded file as byte[]

Well this is actually a two-parter...
First I need to
read the contents of the file
crypt them into a byte[]
write the byte[] in a file or whatever...
Then the result from #2 or #3 will go into another project. I'm trying to protect our PEM/DER keys.
For decryption, I need to
read the contents of the crypted file as a byte[]
decrypt them into a byte[]
write the decrypted data to a file OR use it instead of a file
Now, I have some basic crypting code
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128); // 192 and 256 bits may not be available
SecretKey secretKey = keyGenerator.generateKey();
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// By initializing the cipher in CBC mode, an "initialization vector" has been randomly
// generated. This initialization vector will be necessary to decrypt the encrypted data.
// It is safe to store the initialization vector in plain text for later use. You can obtain
// it's bytes by calling iv.getIV().
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
IvParameterSpec iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class);
// IvParameterSpec iv = new IvParameterSpec(IV); //used for the hardcoded one
byte[] encryptedData = cipher.doFinal(data);
and decrypting one as well
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
byte[] decryptedData = cipher.doFinal(encryptedData);
System.out.println("decrypted: " + new String(decryptedData));
and the question is:
Given a use-case scenario where one would rarely encrypt something and would distribute crypted keys that are to be decrypted at runtime, what do I need to save apart from the cyphertext?
I know I need to save the IV, but when I did decryption wasn't quite good - which leads me to believe that I need to save the secretKey as well.
Could anyone give me any tips, pointers or general security hints to a better solution? If I need to save the key, the IV and the encrypted data, where should I store them? Maybe hardcode the key and store the IV along the encrypted data? Maybe hardcode both the IV and the key and just store encrypted data in the files?
This isn't about theoretical safety, think of this as the biggest nuissance and inconvenience you can cause to someone that is trying to steal your keys. We all know there's no way I can perfectly hide them.
I pretty much need what this guy started with Decrypting an encrypted file and executing in Java
However if there's a better way of feeding secure data into a PemKeyReader, i'm all ears.
Sharing the key and encrypting something are two completely different things. How to share keys
Having said this, AES with 128bit is fairly strong encryption algorithm than 3DES So what you can do is keep PKI infrastructure in place to exchange AES keys and then Encrypt and Decrypt using them.
Why not RSA? RSA needs to be minimum 512 bit to consider it as strongest and if you increase more bits then it increases time required for encryption and decryption.
SO AES is fast and safe.
Use SecretKeySpec to create key from byte[]
public static void main(String[] args) throws Exception
{
// Initialise secret key with predefined byte array [] like below. I
// have used simple string to array method to generate 16 byte array.
// AES Key must be minimum 16 bytes.
// Now you can put this byte array some where is .SO file.
// Generate new Key using this byte []
// Then you can generate a key using device specific information at
// first boot up.
// Use second key to encrypt data and first key to encrypt the second
// key
// I Hope it clears all the doubts
SecretKey key = new SecretKeySpec("ABCDEFGHIJKLMNOP".getBytes(), "AES");
System.out.println(Arrays.toString(key.getEncoded()));
// Initialise Cipher with AES Algorithm
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// Set The Encrypt Mode
cipher.init(Cipher.ENCRYPT_MODE, key);
// Encrypt some bytes
byte[] encrypted = cipher.doFinal("ABCDEFGH".getBytes());
// Print it to vefiry
System.out.println(Arrays.toString(encrypted));
// Get The IV
byte[] iv = cipher.getIV();
System.out.println(iv.length);
// Now why storing you can create structure like [16 IV][Encrypted Data]
// And while decrypting you can read first [16] bytes IV and then
// decrypt remaining bytes
//byte[] iv = new byte[16];
// System.arraycopy(encrypted, 0, iv, 0, 16)
//Copy remaining bytes to decrypt
// set cipher to decrypt mode
cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(iv));
// decrypt it
byte[] decrypted = cipher.doFinal(encrypted);
System.out.println(new String(decrypted));
}
Now write an algorithm which will generate byte[] from some random data like device name, user name, random seed etc.
You can add more protection to algorithm source code by writing that algorithm in C and create.SO file and get byte [] using Native calls.
What are the advantages of doing all this?
Event if your so is hacked it will need real time environment to run create key out of it.
Even if some one does crack it the damage will be limited i.e. 1 device
Hacker will have to repeat same with each device which is highly impossible to do.
The I/O aspect of your question is best addressed by reading the "Byte Streams" and "Buffered Streams" sections of the Oracle Java tutorial. You can accumulate the bytes in memory by writing them to a ByteArrayOutputStream, and then using the toByteArray() method to get the bytes as a byte[].

Java cryptography generated key portability

In Java, I'm generating and serializing a symmetric key for encryption purposes:
KeyGenerator keyGen = KeyGenerator.getInstance(algorithm);
SecretKey symmetricKey = keyGen.generateKey();
Base64.encode(symmetricKey.getEncoded(), new FileOutputStream(filename));
where Base64 is from the Bouncycastle cryptography package and algorithm is AES.
The key, when used with Oracle (Sun) JVM 1.6.0_21, works perfectly is moved from, e.i, Windows to Linux (even between 32/64 bits OSs).
On OS X (Intel), with Apple's JVM, the key is loaded without exception but every string encrypted on Windows or Linux generates a BadPaddingException.
A string is encoded with the following code:
Cipher cipher = Cipher.getInstance(algorithm, "BC");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
encryptedString = new String(Base64.encode(cipher.doFinal(string.getBytes())));
where algorithm is AES.
Any clues?
Padding has nothing to do with the key.
What padding algorithm are you specifying when creating the Cipher?
If you are literally using just "AES" as the cipher algorithm, you should be explicit about the mode and padding. Otherwise, the crypto provider is free to choose some default of its own, and that's likely to vary from machine to machine.

Categories