Decryption fails on chaging the IV in AES algorithm - java

I have some encoded value received by my webservice. Now I have to decode this encoded string and get the bytes of it.
Now I am using this byte array as my IV value for decrypting a values using AES algorithm. But it is not giving me the proper output rather throws some junk values.
Here is my code,
byte[] decoded = Base64.decodeBase64(((String) "MTIzNDU2Nzg5MTIzNDU2Nw==").getBytes());
System.out.println(new String(decoded, "UTF-8") + "\n");
MTIzNDU2Nzg5MTIzNDU2Nw== is the encoded string received from the request xml.
Now decoded will be IV for the next number to be decrypted,
String c = decrypt1("JHIlf4iXM53tgsKHQEv1dlsUTeLr5GP3LfSNGlWENkg=", decoded);
System.out.println(c);
JHIlf4iXM53tgsKHQEv1dlsUTeLr5GP3LfSNGlWENkg= is the digit to be decrypted.
public static String decrypt1(Object data, byte[] ivBytes) throws InvalidKeyException,
InvalidAlgorithmParameterException, IllegalBlockSizeException,
BadPaddingException, UnsupportedEncodingException {
byte[] keyBytes = "keyPhrase".getBytes();
Cipher cipher = null;
if (ivBytes.length<16) {
System.out.println("error" + ivBytes.length);
//ivBytes = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98, 99, 100, 101, 102, 103};
}
byte[] byteArr = null;
try {
SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(
ivBytes));
if (data instanceof String) {
byteArr = Base64.decodeBase64(((String) data).getBytes("UTF-8"));
}
byteArr = (cipher.doFinal(byteArr));
} catch (Exception e) {
e.printStackTrace();
}
//return byteArr;
return new String(byteArr);
}
Note:
Instead if I use this IV,
byte[] ivBytes = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0}; it works as expected.

You need to use the same initialization vector for encryption and decryption; you can transmit the IV in plaintext (i.e. it isn't secret)
You should also use a different IV for each ciphertext, generated with e.g. a counter or with SecureRandom

Related

How to use custom secret key instead of generating a new secret key in AES 256 encryption

I am now trying to develop a AES 256 CFB encryption program in Java.
I wish to use my own secret key (Hex). However, it returned that there is something wrong with the key length.
Here is the code
class encryption_different {
private static String SECRET_KEY = "afd7a42b34f4875e05d210ea1252e02d5305becdb752f3553d657bab1236f733";
public static String encrypt(String strToEncrypt) {
try {
//IV handling
byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
IvParameterSpec ivspec = new IvParameterSpec(iv);
//convert custom key string to Secret key format
byte[] decodedKey = Base64.getDecoder().decode(SECRET_KEY);
SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, originalKey, ivspec);
return Base64.getEncoder()
.encodeToString(cipher.doFinal(strToEncrypt.getBytes(StandardCharsets.UTF_8)));
} catch (Exception e) {
System.out.println("Error while encrypting: " + e.toString());
}
return null;
}
public static void main(String[] args){
encrypt("password1");
}
}
The error message I got:
Error while encrypting: java.security.InvalidKeyException: Invalid AES key length: 48 bytes
And therefore, I would like to know why I am getting this error message and how to fix it.

AES Encryption and Decryption not getting decrypted word in print statements but shows up in debugger

Hi I'm working on a socket programming project where it is a encrypted client and server. I have all the code working to create public keys, private keys, aes secret encryption and decryption. The issue is when I sent my encrypted values over to the server, it is missing the first few values of the encrypted values. But when I run it through the debugger and add breakpoints it prints the right decrypted value.
For this say my text is "jesus" this is my client class for example.
Client.java
try {
IvParameterSpec iv = new IvParameterSpec(initVector);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] encrypted = cipher.doFinal(value.getBytes(StandardCharsets.UTF_8));
System.out.println("encrypted string: "
+ Base64.getEncoder().encodeToString(encrypted));
return Base64.getEncoder().encodeToString(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static void main(Strings[] args) {
// I have all the code for making keys and creating the Socket connection ( all of this stuff works)
System.out.println("What is your port number");
port = scanner.nextInt();
System.out.println("What is your ip address");
ipAddress = scanner.next();
System.out.println("What is your client's private key file");
privateKeyFile = scanner.next();
System.out.println("What is your server's public key file");
publicKeyFile = scanner.next();
System.out.println("What is your text string");
textString = scanner.next();
Socket socket = new Socket(ipAddress, port);
DataInputStream input = new DataInputStream(socket.getInputStream());
// sends output to the socket
DataOutputStream output = new DataOutputStream(socket.getOutputStream());
PrivateKey clientPrivateKey = loadPrivateKey(privateKeyFile, "RSA");
PublicKey serverPublicKey = loadPublicKey(publicKeyFile, "RSA");
// I have more but essentially that is part of it
// stuff that isn't working
SecureRandom sr = new SecureRandom();
KeyGenerator kg= KeyGenerator.getInstance("AES");
kg.init(256, sr);
SecretKey key256AES = kg.generateKey();
String encodedTextString = new String(Base64.getEncoder().encode(
textString.getBytes(StandardCharsets.UTF_8)));
Integer textStringLengthFromBytes = textByte.length;
byte[] textSignature = signDigitalSignature(textByte, clientPrivateKey, "SHA512withRSA");
byte[] IV = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
String cipherText = encrypt(key256AES, IV, textString);
System.out.println("Cipher" + cipherText);
output.write(textStringLengthFromBytes);
output.write(textSignature);
output.write(cipherText.getBytes(StandardCharsets.UTF_8));
}
Server.java
public static String decrypt(SecretKey key, byte[] initVector, String encrypted) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, key, iv);
byte[] plainText = cipher.doFinal(Base64.getDecoder()
.decode(encrypted));
return new String(plainText);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static void main(String args[]){
// round 2 for this project I have to get the size of the plaintext string and //the aesEncryptedString and the actual cipher text
Integer size = in.readInt();
System.out.println("size" + size);
byte[] textSignatureFromClient = new byte[256];
in.readFully(textSignatureFromClient);
System.out.println("textSignatureFromClient" +
Arrays.toString(textSignatureFromClient));
// having issues with this part below
String cipherText = in.readLine();
System.out.println("Cipher " + cipherText);
byte[] IV = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
String decryptedVal = decrypt(AESSecretKey, IV, cipherText);
System.out.println("Text" + decryptedVal);
}
Here is an output of what values are stored in the ciphers:
Client ciphertext says: V5VoP7K/Bzzj5291kd3WYg==
Server ciphertext says: oP7K/Bzzj5291kd3WYg==
Here is the error I get as well:
java.lang.IllegalArgumentException: Input byte array has incorrect ending byte at 20
But when I debug, I pass over the decrypt line in the the server and it gets me the word jesus in plaintext both in the debugger variables and in the console. Also I apologize for how messy my code is. I'm going to clean it and modularize it more once all my requirements are met.
I have absolutely no idea why this worked but I this is what my Server.java looks like now. I just added "" at the end of in.readline() because I noticed when I added comments it got the full cipher. Additionally, it is receiving the text signature before the cipher with no issues.
Server.java
byte[] textSignatureFromClient = new byte[256];
in.readFully(textSignatureFromClient);
String cipherText = in.readLine() + "";
try {
byte[] IV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
String decryptedVal = decrypt(AESSecretKey, IV, cipherText.trim());
System.out.println("Decrypted Text: " + decryptedVal);
}
catch(Exception e){
System.out.println("Decryption error" + e);
}
Client.java
String encodedTextString = new String(Base64.getEncoder().encode(
textString.getBytes(StandardCharsets.UTF_8)));
byte[] textByte = encodedTextString.getBytes();
byte[] textSignature = signDigitalSignature(textByte, clientPrivateKey, "SHA512withRSA");
output.write(textSignature);
output.flush();
String cipherText = encrypt(key256AES, IV, textString);
System.out.println("Cipher" + cipherText);
output.write(cipherText.getBytes(StandardCharsets.UTF_8));
output.flush(); ```

Java String not equal String?

I want to decrypt a String. Here my Decryption and Encryption methods.
public String encrypt(String message) throws Exception {
byte[] messageInBytes = message.getBytes();
encryptionCipher = Cipher.getInstance("AES/GCM/NoPadding");
encryptionCipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes = encryptionCipher.doFinal(messageInBytes);
return encode(encryptedBytes);
}
public String decrypt(String encryptedMessage) throws Exception {
byte[] messageInBytes = decode(encryptedMessage);
Cipher decryptionCipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec spec = new GCMParameterSpec(T_LEN , encryptionCipher.getIV());
decryptionCipher.init(Cipher.DECRYPT_MODE, key, spec);
byte[] decryptedBytes = decryptionCipher.doFinal(messageInBytes);
return new String(decryptedBytes);
}
Here the main:
public static void main(String[] args) {
try {
AES aes = new AES();
aes.convertStringKeyToSecretKey();
String encryptedMessage = aes.encrypt("Peter");
String decryptedMessage = aes.decrypt(encryptedMessage);
System.err.println("Encrypted Message : " + encryptedMessage);
System.err.println("Decrypted Message : " + decryptedMessage);
} catch (Exception ignored) {
}
}
When I change encryptedMessage to a own String like:
String decryptedMessage = aes.decrypt("xDFzl9HsenqKspdEbL/m9I5X6dqn");
It does nothing
I hope you can help me.
Best Regards
Christian
public static String encryptAES(String toEncrypt, final String key1, final String key2) throws Exception {
try {
byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec keySpec = new PBEKeySpec(key1.toCharArray(), key2.getBytes(), 65536, 256);
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
return Base64.getEncoder().encodeToString(cipher.doFinal(toEncrypt.getBytes(StandardCharsets.UTF_8)));
} catch (Exception ex) {
throw new Exception(ex);
}
}
public static String decryptAES(String toDecrypt, final String key1, final String key2) throws Exception {
try {
byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec keySpec = new PBEKeySpec(key1.toCharArray(), key2.getBytes(), 65536, 256);
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
return new String(cipher.doFinal(Base64.getDecoder().decode(toDecrypt)));
} catch (Exception ex) {
throw new Exception(ex);
}
}
Here you can still expand its secureness by creating your own IV Spec key, which should contain only 16 character.
Actually, this is how AES encryption worked for me, You can also check this repo in GitHub for additional encryption methods.

When I am trying to decrypt getting following error

I am getting following error while decrypting.
Once it was working fine but suddenly I am getting this error.
How can I solve this problem?
I have read many articles but couldn't get help.
java.security.InvalidKeyException: Parameters missing
at com.sun.crypto.provider.CipherCore.init(CipherCore.java:388)
at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:186)
at javax.crypto.Cipher.implInit(Cipher.java:786)
at javax.crypto.Cipher.chooseProvider(Cipher.java:848)
at javax.crypto.Cipher.init(Cipher.java:1212)
at javax.crypto.Cipher.init(Cipher.java:1152)
at
com.test.security.TestEncryptDecrypt.decrypt(TestEncryptDecrypt.java:92)
at com.test.security.TestEncryptDecrypt.main(TestEncryptDecrypt.java:59)
The code is give below:
public static void main(String []args){
try {
String encString = encrypt("PID=0000000003|ITC=NA|PRN=MNKB0701511135|AMT=1.00|CRN=INR|RU=https://www.testsite.com/testsk/servlet/TestResponseHandler?");
System.out.println("Enc : " + encString);
System.out.println("Dec : "+ decrypt(encString));
} catch (Exception e) {
e.printStackTrace();
}
}
Encrypt method
public static String encrypt(String data) throws Exception {
String keyFile = "E:\\testpath\\Keys\\0000000003.key";
byte[] keyb = Files.readAllBytes(Paths.get(keyFile));
SecretKeySpec skey = new SecretKeySpec(keyb, "AES");
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, skey);
byte[] encVal = c.doFinal(data.getBytes());
return new BASE64Encoder().encode(encVal);
}
Decrypt method
public static String decrypt(String encryptedData)
throws InvalidKeyException, IllegalBlockSizeException,
BadPaddingException, NoSuchAlgorithmException,
NoSuchPaddingException, IOException {
String keyFile = "E:\\testpath\\Keys\\0000000003.key";
byte[] keyb = Files.readAllBytes(Paths.get(keyFile));
SecretKeySpec skey = new SecretKeySpec(keyb, "AES");
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
c.init(Cipher.DECRYPT_MODE, skey);
byte[] decordedValue = Base64.decodeBase64(encryptedData.getBytes());
byte[] decValue = c.doFinal(decordedValue);
return new String(decValue);
}
As the error message says, you are missing a parameter in the init methods. If you're using CBC you should also specify the AlgorithmParameterSpec.
Could you perhaps try the following:
byte[] paramSpecBytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
IvParameterSpec paramSpec = new IvParameterSpec(paramSpecBytes);
And in your encrypt and decrypt methods:
c.init(Cipher.ENCRYPT_MODE, skey, paramSpec);
c.init(Cipher.DECRYPT_MODE, skey, paramSpec);
You could fill the bytes with any value you like though, doesn't need to be zero's. Best would be some random value.

Received byte array has different values than sent, AES encryption + IV

I'm trying to encrypt communication using AES, in java.
The key is hardcoded, and the IV is generated randomly through a SecureRandom and sent as the first 16 bytes of the encrypted message. However, when I try to read the first 16 bytes of the received message, I don't get the same byte array that I generated.
Here's the problematic code:
static byte[] bytes = new byte[16];
public static byte[] encrypt(String key, String message) {
try {
SecureRandom random = new SecureRandom();
random.nextBytes(bytes);
System.out.println("Outputting generated IV:");
for(int i=0; i < bytes.length; i++){
System.out.println(bytes[i]);
}
IvParameterSpec iv = new IvParameterSpec(bytes);
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = Base64.encodeBase64(cipher.doFinal(message.getBytes()));
System.out.println("encrypted string: "
+ Base64.encodeBase64String(encrypted));
byte[] sendMe = new byte[bytes.length + encrypted.length];
System.arraycopy(bytes, 0, sendMe, 0, bytes.length);
System.arraycopy(encrypted, 0, sendMe, 0, encrypted.length);
return sendMe;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static String decrypt(String key, byte[] received) {
try {
byte[] initVector = Arrays.copyOfRange(received, 0, 16);
byte[] encrypted = Arrays.copyOfRange(received, 16, received.length+1);
System.out.println("Outputting received IV:");
for(int i = 0; i < initVector.length; i++){
System.out.println(initVector[i]);
}
IvParameterSpec iv = new IvParameterSpec(initVector);
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;
}
Running this once, for example's sake, with the text "Hello world!" yielded the following output:
Outputting generated IV:
-79
-3
102
-103
-13
67
-63
-18
23
-114
74
26
18
-97
77
115
Outputting received IV:
36
-118
-87
-72
-119
43
101
55
50
-62
125
-98
65
35
48
-87
Which are obviously not the same.
Any help would be appreciated.
You are overwriting your IV with the encrypted data:
System.arraycopy(bytes, 0, sendMe, 0, bytes.length);
System.arraycopy(encrypted, 0, sendMe, 0, encrypted.length); // Overwrites the iv
You probably want:
System.arraycopy(bytes, 0, sendMe, 0, bytes.length);
System.arraycopy(encrypted, 0, sendMe, 16, encrypted.length);

Categories

Resources