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.
Related
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
}
I want to generate Random key using AES/ECB/PKCS7PADDING but java does not support PKCS7 padding and in my algo I have to use the same padding, bouncy castle does support PKCS7PADDING but I am unable to understand how to generate key using that
My code :
Security.addProvider(new BouncyCastleProvider());
private byte[] generateSessionKey() throws NoSuchAlgorithmException, NoSuchProviderException {
KeyGenerator kgen = KeyGenerator.getInstance("AES/ECB/PKCS7PADDING", "BC");
kgen.init(SYMMETRIC_KEY_SIZE);
SecretKey key = kgen.generateKey();
return key.getEncoded();
}
I am receiving error of no such algorithm
Key generation for AES does not have to do anything with padding. Padding is required for some modes of operation such as ECB and CBC. But the key itself doesn't rely on the mode or the padding. So you should just use:
KeyGenerator kgen = KeyGenerator.getInstance("AES", "BC");
which will undoubtedly work.
Do not use PKCS#7 padding, substitute "PKCS5Padding" for "PKCS7Padding".
Please take a look here to understand the difference between the padding mechanisms and here for the difference in Java.
I guess Android is using a stripped down Bouncy Castle provider (it was one of the reasons that SpongyCastle was lounged), which would explain the differences between Android and the Java SE provider.
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>
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
I have written some (functional) AES encryption code using Java's built in encryption libraries, as follows, but I'd like to use a 256-bit key. However, I'd like to do this without the user having to install to Unlimited Strength Cryptography Policy files.
Now, I've heard that using the BouncyCastle Lightweight API can allow me to do this, but unfortunately I'm having a great deal of trouble getting my head around it, and am struggling to fit any documentation that helps me.
Here is a my current code, in which 'content' is the byte array to be encrypted:
KeyGenerator kgen = KeyGenerator.getInstance("AES");
int keySize = 128;
kgen.init(keySize);
SecretKey key = kgen.generateKey();
byte[] aesKey = key.getEncoded();
SecretKeySpec aesKeySpec = new SecretKeySpec(aesKey, "AES");
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.ENCRYPT_MODE, aesKeySpec);
byte[] encryptedContent = aesCipher.doFinal(content);
How would I go about re-implementing this with the BouncyCastle Lightweight API? Can anyone help me out and/or point me in the direction of some simple example code?
I'm also interesting in any other solutions that allow 256-bit key AES encryption without the need for the user to install the unlimited strength policy files.
Many thanks!
This question and answer is a useful starting point.
256bit AES/CBC/PKCS5Padding with Bouncy Castle
The next best place to look is the test code for the LW APIs and then the JCE Provider code. The JCE Provider code is a wrapper around the LW libraries - so if you want to know how to do it, that's the best place to see it.
By the JCE Provider code, I mean the BC implementation.