cipher.getInstance() with blowfish in java - java

Hello My code does not give me any error but also does not work.
I do not know what it is problem but I think it is in Cipher.getInstance
private static void createKey(char[] password) throws Exception {
System.out.println("Generating a Blowfish key...");
// Create a blowfish key
KeyGenerator keyGenerator = KeyGenerator.getInstance("Blowfish");
keyGenerator.init(256);
Key key = keyGenerator.generateKey();
System.out.println("Done generating the key.");
// Now we need to create the file with the key,
// encrypting it with a password.
byte[] salt = new byte[8];
SecureRandom random = new SecureRandom();
random.nextBytes(salt);
PBEKeySpec pbeKeySpec = new PBEKeySpec(password);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithSHAAndTwofish-CBC");
SecretKey pbeKey = keyFactory.generateSecret(pbeKeySpec);
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, ITERATIONS);
//Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES-CBC");
//Cipher cipher = Cipher.getInstance("PBEWithSHAAndTwofish-CBC");
Cipher cipher = Cipher.getInstance("PBEWithSHAAndTwofish-CBC");
cipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);
// Encrypt the key
byte[] encryptedKeyBytes = cipher.doFinal(key.getEncoded());
// Write out the salt, and then the encrypted key bytes
FileOutputStream fos = new FileOutputStream(KEY_FILENAME);
fos.write(salt);
fos.write(encryptedKeyBytes);
fos.close();
}

Related

JAVA separate AES key, initilization vector and data from encrypted file with these 3 combinations used during encryption

I have created encrypted file with combination of AES encryption, intilizatio vector and original data.
So my encrypted file contains above 3 elements in encrypted form.
Now during decryption i am stuck at separating all these 3 elements again, moreover i have to use AES key length hard coded during decryption that was generated during encryption.
public static void encrypt() throws Exception {
// RSA with ECB mode
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, generatePublicKey(readKeysFromFile("My_public.pub")));
// AES key generator
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, srandom);
SecretKey skey = kgen.generateKey();
// Initialization vector 16 byte
byte[] iv = new byte[128/8];
srandom.nextBytes(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);
try (FileOutputStream out = new FileOutputStream("dataFile" + ".enc")) {
{
byte[] b = cipher.doFinal(skey.getEncoded());
out.write(b);
System.err.println("AES Key Length: " + b.length);
}
out.write(iv);
System.err.println("IV Length: " + iv.length);
Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
ci.init(Cipher.ENCRYPT_MODE, skey, ivspec);
File inputDataFile = new File("dataFile.xml");
try (DataInputStream in = new DataInputStream(new FileInputStream(inputDataFile))) {
byte[] buffer = new byte[(int)inputDataFile.length()];
in.readFully(buffer);
in.close();
byte[] encryptedData = ci.doFinal(buffer);
out.write(encryptedData);
out.close();
}
}
}
public static void decryptRSAAES() throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, generatePrivateKey(readKeysFromFile("My_private.key")));
File file2 = new File("dataFile.enc");
RandomAccessFile raf = new RandomAccessFile(file2, "r");
// length of AES key
byte[] c = new byte[384];
// read the AES key from file
raf.read(c, 0 , 384);
byte[] fileContent = Files.readAllBytes(file2.toPath());
byte[] keyb = cipher.doFinal(c);
SecretKeySpec skey = new SecretKeySpec(keyb, "AES");
// read the initializatoin vector
byte[] iv = new byte[128/8];
raf.seek(384);
raf.read(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);
raf.seek(400);
Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
ci.init(Cipher.DECRYPT_MODE, skey, ivspec);
try (FileOutputStream out = new FileOutputStream("decryptedFileTest"+".xml")){
byte[] decryptedData = ci.doFinal(fileContent);
out.write(decryptedData);
out.close();
//processDecryptFile(ci, in, out);
}
}
Actual result: decrypted file is created with AES key and original plain data
Expected result: write only original plain data in output removing AES and initilization vector.
Let's simplify this and use the functions newly available in Java's InputStream classes:
public static void encrypt(RSAPublicKey publicKey) throws Exception {
try (FileOutputStream out = new FileOutputStream("dataFile" + ".enc")) {
// --- RSA using PKCS#1 v1.5 padding
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// --- AES key generator
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
SecretKey skey = kgen.generateKey();
// --- write encrypted AES key
byte[] encryptedSKey = cipher.doFinal(skey.getEncoded());
out.write(encryptedSKey);
// --- Initialization vector 16 byte
SecureRandom srandom = new SecureRandom();
byte[] iv = new byte[128/8];
srandom.nextBytes(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);
// --- write IV
out.write(iv);
// --- initialize AES cipher
Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
ci.init(Cipher.ENCRYPT_MODE, skey, ivspec);
// --- convert file by copying to memory
try (FileInputStream in = new FileInputStream("dataFile.xml")) {
byte[] buffer = in.readAllBytes();
byte[] encryptedData = ci.doFinal(buffer);
out.write(encryptedData);
}
}
}
public static void decrypt(RSAPrivateKey privateKey) throws Exception {
try (FileInputStream in = new FileInputStream("dataFile" + ".enc")) {
// --- RSA using PKCS#1 v1.5 padding
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// --- read encrypted AES key
byte[] encryptedSKey = in.readNBytes(determineEncryptionSizeInBytes(privateKey));
byte[] decryptedSKey = cipher.doFinal(encryptedSKey);
SecretKey skey = new SecretKeySpec(decryptedSKey, "AES");
// --- Initialization vector 16 byte
byte[] iv = in.readNBytes(128 / Byte.SIZE);
IvParameterSpec ivspec = new IvParameterSpec(iv);
// --- initialize AES cipher
Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
ci.init(Cipher.DECRYPT_MODE, skey, ivspec);
// --- convert file by copying to memory
File outputDataFile = new File("dataFile.xml2");
try (FileOutputStream out = new FileOutputStream(outputDataFile)) {
byte[] buffer = in.readAllBytes();
byte[] decryptedData = ci.doFinal(buffer);
out.write(decryptedData);
}
}
}
private static int determineEncryptionSizeInBytes(RSAPrivateKey privateKey) {
return (privateKey.getModulus().bitLength() + Byte.SIZE - 1) / Byte.SIZE;
}
public static void main(String[] args) throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(384 * Byte.SIZE);
KeyPair pair = kpg.generateKeyPair();
encrypt((RSAPublicKey) pair.getPublic());
decrypt((RSAPrivateKey) pair.getPrivate());
}
As you can see the code is now very much more like a mirror image. I have simply copied the encryption code and then made changes to it. As you can see it now uses fewer classes by relying on InputStream#readAllBytes() (since Java 9) and InputStream#readNBytes() (since Java 11).
Note that you generally want to stream the file using a smaller buffer. As the entire plaintext and ciphertext are currently buffered your application uses much more memory than required. To encrypt data using streams you can rely on CipherInputStream and CipherOutputStream.
Needless to say the exception handling needs improvement, I've simply looked at the best way to solve your current issue. Please take another look at it when you've got things working (get things working, get things right, get things optimized).

Trying to use my own key for desCipher

I am using a key generated by keygenerator to create my desCipher object. I would like to use a key I created, instad of being created by generateKey() methed
my code
KeyGenerator keygenerator = KeyGenerator.getInstance("DES");
myDesKey = keygenerator.;
desCipher.init(Cipher.DECRYPT_MODE, myDesKey);
You may want to look into SecretKeySpec
byte[] binaryKey
byte [] encrypted
SecretKeySpec keySpec = new SecretKeySpec(binaryKey, "DES");
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, keySpec);
decryptedString = new String(cipher.doFinal(encrypted));

BadPaddingException using SecretKey generated by DiffieHellman

I have seen a lot of questions/answers but no one works for me. The problem is that, when I want to decrypt a text, I go throw BadPaddingException and doesn't know why.
Here is my code to encrypt text:
KeyAgreement keyAgreement = this.getSecretKeyAgreement(publicOtherUserKey, privateOwnKey);
SecretKey secretKey = new SecretKeySpec(keyAgreement.generateSecret(), "AES");
Cipher aesCipher = null;
aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] byteDataToEncrypt = text.getBytes();
byte[] byteCipherText = aesCipher.doFinal(byteDataToEncrypt);
byte[] encodedBytes = Base64.encodeBase64(byteCipherText);
textEncrypted = new String(encodedBytes);
Where "publicOtherUserKey" and "privateOwnKey" where generated using Diffie-Hellman Protocol.
Here is the code that decrypt the text, that goes throw BadPaddingException
KeyAgreement keyAgreement = this.getSecretKeyAgreement(publicOtherUserKey, privateOwnKey);
byte[] encodedBytes = text.getBytes();
SecretKey secretKey = new SecretKeySpec(keyAgreement.generateSecret(), "AES");
byte[] decodedBytes = Base64.decodeBase64(encodedBytes);
Cipher decrypt = Cipher.getInstance("AES");
decrypt.init(Cipher.DECRYPT_MODE, secretKey);
textDecrypted = new String(decrypt.doFinal(decodedBytes));
Where "publicOtherUserKey" and "privateOwnKey" where generated using Diffie-Hellman Protocol, and "text" is the encrypted text.
Can you help me?
EDIT
It's important to mention that all the keys and texts are encoded in Base64
EDIT 2
Code for Start key exchange with Diffie-Hellman
int bitLength = 256; // 256 bits
SecureRandom rnd = new SecureRandom();
BigInteger p = BigInteger.probablePrime(bitLength, rnd);
BigInteger g = BigInteger.probablePrime(bitLength, rnd);
DHParameterSpec dhParams = new DHParameterSpec(p, g);
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "BC");
keyGen.initialize(dhParams, new SecureRandom());
KeyAgreement aKeyAgree = KeyAgreement.getInstance("DH", "BC");
KeyPair aPair = keyGen.generateKeyPair();
aKeyAgree.init(aPair.getPrivate());
byte[] aPairPrivateKey = aPair.getPrivate().getEncoded();
byte[] encodedBytesPrivateKey = Base64.encodeBase64(aPairPrivateKey);
String privateKey = new String(encodedBytesPrivateKey);
byte[] aPairPublicKey = aPair.getPublic().getEncoded();
byte[] encodedBytesPublicKey = Base64.encodeBase64(aPairPublicKey);
String publicKey = new String(encodedBytesPublicKey);
Where "publicKey" and "privateKey" are the keys to later generate the secret key. "publicKey" is the Key sended to the other user. "p" and "g" are the numbers to generate the Key too.
The code for complete the exchange:
DHParameterSpec dhParams = new DHParameterSpec(p, g);
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "BC");
keyGen.initialize(dhParams, new SecureRandom());
KeyAgreement bKeyAgree = KeyAgreement.getInstance("DH", "BC");
KeyPair bPair = keyGen.generateKeyPair();
bKeyAgree.init(bPair.getPrivate());
byte[] userPublicBytesBase64 = base64EncodedPublicKey.getBytes();
byte[] userPublicKey = Base64.decodeBase64(userPublicBytesBase64);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(userPublicKey);
KeyFactory keyFactory = KeyFactory.getInstance("DH");
PublicKey aPublicKey = keyFactory.generatePublic(keySpec);
bKeyAgree.doPhase(aPublicKey, true);
final byte[] bPairPrivateKey = bPair.getPrivate().getEncoded();
byte[] encodedBytesPrivateKey = Base64.encodeBase64(bPairPrivateKey);
String privateKey = new String(encodedBytesPrivateKey);
final byte[] bPairPublicKey = bPair.getPublic().getEncoded();
byte[] encodedBytesPublicKey = Base64.encodeBase64(bPairPublicKey);
String publicKey = new String(encodedBytesPublicKey);
"base64EncodedPublicKey" is the Key generated in the first block of Code ("publicKey"), and "p" and "g" are too the primes generated in the first block of Code.

Java, error when decoding AES-256

I receive an error while decrypting: (javax.crypto.BadPaddingException: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt)
My code encryption / decryption:
private static byte[] password = null; // this.password = editText.getBytes();
static final byte[] ivBytes = {'6','g','6','o','d','a','0','u','4','n','w','i','6','9','i','j'};
public static byte[] encrypt(String text) throws Exception {
byte[] clear = text.getBytes("UTF-8");
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(password);
kgen.init(256, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] key = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
public static String decrypt(byte[] encrypted) throws Exception {
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(password);
kgen.init(256, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] key = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
String decrypted = new String(cipher.doFinal(encrypted));
return decrypted;
}
I suspect that the bug generateKey.
You're doing two things wrong:
Generating a key from a password by using the key to seed a PRNG is a bad idea. Use password-based-encryption instead. Java has an implementation of PKCS#5 that will generate a key from a password.
You need to use a new strong-random IV for each encryption:
When you encrypt, don't specify an IV in cipher.init(). A new one will be generated for you.
encrypt() needs to serialise both the IV (cipher.getIV()) and the ciphertext into a byte array.
decrypt(): separate the IV from the ciphertext, build an IvParameterSpec from it and feed into cipher.init() as you currently do.
Your issues is that when you decrypt, you generate a new secret key instead of deriving it from password. Check out this blog post to see how password-based encryption has to be implemented. There are examples of encryption and decryption functions.
Replace the below line:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
with below line:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding","BC");

AES Algorithm JAVA Giving : java.lang.IllegalArgumentException: Invalid key size

I am doing a simple implementation for AES Algorithm.
// Get the Key Generator
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); // 192 and 256 bits may not be available
// Generate the secret key specs.
SecretKey secret = kgen.generateKey();
byte[] raw = secret.getEncoded();
String key = new String(Base64.encodeBase64(raw));
I am saving "key" in database.
Now again in another operation i am fetching a "key" from database n trying to decrypt data. i call decryption function as
String dencryptReq = Utils.decrypt2(new String(Base64.decodeBase64(secretKeyInformation.getSecretKey().getBytes())),Base64.decodeBase64(encryptReq.getBytes()) );
public static String decrypt2(String key, byte[] encrypted)
throws GeneralSecurityException {
byte[] raw = Base64.decodeBase64(key.getBytes());
if (raw.length != 16) {
throw new IllegalArgumentException("Invalid key size.");
}
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec,
new IvParameterSpec(new byte[16]));
byte[] original = cipher.doFinal(encrypted);
return new String(original, Charset.forName("US-ASCII"));
}
But it is throwing me invalid key size exception.
If i do in one time this without saving in databse and fetching from database it is working fine.
I have tried your code with some modifications I have used apache commons codec library for Base64 conversion,
/* Derive the key, given password and salt. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec("password".toCharArray(), "salt".getBytes(), 65536, 128);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
/* Encrypt the message. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal("Hello, World! My data is here.. !".getBytes("UTF-8"));
System.out.println("cipher :"+new String(ciphertext));
/*String-key convertion */
String stringKey=Base64.encodeBase64String(secret.getEncoded());//To String key
byte[] encodedKey = Base64.decodeBase64(stringKey.getBytes());
SecretKey originalKey = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");// Convert from string
/* Decrypt the message, given derived key and initialization vector. */
Cipher cipher1 = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher1.init(Cipher.DECRYPT_MODE, originalKey, new IvParameterSpec(iv));
String plaintext = new String(cipher1.doFinal(ciphertext), "UTF-8");
System.out.println(plaintext);
This code worked perfectly in my system.

Categories

Resources