256 bits Blowfish encryption in java - 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

Related

java : invalid key size while using aes encryption after using JCE security policy version 8

I'm trying to generate AES key of size 256 bit and I downloaded the JCE security policy of version 8 and I placed the US_export_policy.jar and the local_policy.jar in the jre/lib/security folder. Is there anything I've left out in the code and what could be the cause for the exception?
This is what I've coded and it gives me an illegal key size exception.
Here's the code :
kgen = KeyGenerator.getInstance("AES");
kgen.init(256);
SecretKey skey = kgen.generateKey();
byte[] iv = new byte[16];
SecureRandom srandom = new SecureRandom();
srandom.nextBytes(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);
System.out.println(iv);
Here, iv is the initialization vector that I'm using further in the code.
Would greatly appreciate your help and thanks in advance.
This is exception I'm getting :
java.security.InvalidKeyException: Illegal key size
at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1039)
at javax.crypto.Cipher.implInit(Cipher.java:805)
at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
at javax.crypto.Cipher.init(Cipher.java:1396)
at javax.crypto.Cipher.init(Cipher.java:1327)
at com.global.DocMananger.Crypto.main(Crypto.java:145)
This is the line that's throwing the error :
Cipher cipherAES = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipherAES.init(Cipher.ENCRYPT_MODE, skey, ivspec);
Use jdk1.8.0_91 package, it will work after changing JCE policy files.
In jdk1.8.0_144, it won't work even changing JCE files. Seems it has some issues in that version. Ask you query in Java8 forum regarding this.

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

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
}

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[].

Is AES128 or AES256 on Android?

Greetings,
On Android, we can't specify AES128 or AES256. But is AES128, or AES256 actually run when using "AES/CBC/PKCS5Padding"?
I tried something like below
SecretKeyFactory sf = SecretKeyFactory.getInstance("PBEWITHSHAAND256BITAES-CBC-BC");
KeySpec ks = new PBEKeySpec(masterPassword.toCharArray(),k1,1320,256);
secKey = sf.generateSecret(ks);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secKey, generateIV(cipher));
The SecretKeyFactory created has a keySize of 256, and the keyLength specified in PBEKeySpec seems doesn't matter. No matter 256 or 128, or any other positive number, the secKey generated always has 256 keySize. Since we passed the secKey to initialize the cipher, so now, does the encryption will be run using AES128, or AES256?
Thanks!
This article should allow you to determine the strengths and ciphers you have available in the runtime image. I don't know if it will kick you out at this point but by specifying PBEKeySpec with a length of 256 I think you might have it.
On Android, we can't specify AES128 or
AES256. But is AES128, or AES256
actually run when using
"AES/CBC/PKCS5Padding"?
Am I wrong suggesting that none is actually determined at getInstance()? I suppose the length of the cipher's key will be determined only after call to init() where you set a key which is of certain length.

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