Home > Software design >  In Java how to use AES encryption so that a static string/text will result in similar encrypted mess
In Java how to use AES encryption so that a static string/text will result in similar encrypted mess

Time:09-01

I have a situation where I have to store the encrypted from of a text in an excel sheet and my java code should read that encrypted text from a excel sheet and convert it back to original text and hit the server with original plain text. I'm trying to achieve this with AES encryption/decryption logic but I'm not able to achieve it as every time I convert the plain text into encrypted format for it to be stored in the excel sheet it results in a different encrypted string each time so I'm not able to decrypt it back to original, what I want is for a same static string/text my AES encrypted text should also be static. I know even if my encrypted string is dynamic I can convert it back to decrypted format but for my case what I want is my encrypted text should also remain static. How can I achieve this?

Ex. If my plain text is "This is a question" my encrypted string is different each time like below

Enter This is a question Encrypted Data : mFsue8JGwLcJQTiBzM0HLVvdDXKPNGsG/O7N60joH Ozgg== Decrypted Data : This is a question

Enter This is a question Encrypted Data : FdBz3cGS4NphK14Fw8Me4daM4lVzdrK47WUMSRiUVe juQ== Decrypted Data : This is a question

See the encrypted data's are different each time. I want that to be static

The classes which I'm using are as below (please note these are not my exact classes but they implement the same logic which I have used. These example classes may have some non used variables and methods, I have mentioned just for reference)

Method.java

import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class Method {

private static SecretKey key;
private final int KEY_SIZE = 128;
private final int DATA_LENGTH = 128;
private Cipher encryptionCipher;

/*
 * public void init() throws Exception { KeyGenerator keyGenerator =
 * KeyGenerator.getInstance("AES"); keyGenerator.init(KEY_SIZE); key =
 * keyGenerator.generateKey();
 * 
 * 
 * }
 */

// String to Key


  public static void getKeyFromPassword(String toEnc, String salt) throws
  NoSuchAlgorithmException, InvalidKeySpecException { SecretKeyFactory factory
  = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); KeySpec spec = new
  PBEKeySpec(toEnc.toCharArray(), salt.getBytes(), 65536, 128); SecretKey
  originalKey = new SecretKeySpec(factory.generateSecret(spec).getEncoded(),"AES"); 
  key= originalKey; }
  
 
/*
 * public static void convertStringToSecretKeyto(String string) {
 * 
 * 
 * byte[] bytesEncoded = Base64.getEncoder().encode(string.getBytes()); byte[]
 * decodedKey = Base64.getDecoder().decode(string); key = new
 * SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
 * System.out.println(bytesEncoded); System.out.println(decodedKey);
 * 
 * }
 */

   public String encrypt(String data) throws Exception {
    byte[] dataInBytes = data.getBytes();
    encryptionCipher = Cipher.getInstance("AES/GCM/NoPadding");
    
    encryptionCipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] encryptedBytes = encryptionCipher.doFinal(dataInBytes);
    return encode(encryptedBytes);
   }

    public String decrypt(String encryptedData) throws Exception {
    byte[] dataInBytes = decode(encryptedData);
    Cipher decryptionCipher = Cipher.getInstance("AES/GCM/NoPadding");

    GCMParameterSpec spec = new GCMParameterSpec(DATA_LENGTH, 
    encryptionCipher.getIV());
    decryptionCipher.init(Cipher.DECRYPT_MODE, key, spec);
    byte[] decryptedBytes = decryptionCipher.doFinal(dataInBytes);
    return new String(decryptedBytes);
    }

    private String encode(byte[] data) {
    return Base64.getEncoder().encodeToString(data);
    }

    private byte[] decode(String data) {
    return Base64.getDecoder().decode(data);
    } 
}

Main.class

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import java.util.Base64;
import java.util.Scanner;
public class Cypher {

public static void main(String[] args) {
    // TODO Auto-generated method stub
    
    try {
        Method aes_encryption = new Method();
 
        
 //       aes_encryption.init();
       Method.getKeyFromPassword("Texty text","Salty salt");
        
        System.out.println("Enter");
        Scanner sc= new Scanner(System.in);
        String s= sc.nextLine();
        String encryptedData = aes_encryption.encrypt(s);
        String decryptedData = aes_encryption.decrypt(encryptedData);
      

        System.out.println("Encrypted Data : "   encryptedData);
       System.out.println("Decrypted Data : "   decryptedData);
    } catch (Exception ignored) {
    }
}
    
    

}

CodePudding user response:

Nope, you don't want to do that.

In cryprography, data needs to be salted and padded with random bits of data before and/or after the original message in order to preserve it from attacks.

What you are asking for goes against cryprography basic rules. You simply won't find any library that does what you are asking for, except if you create or tweak one by yourself.

Then where's the issue?

My Java is a little bit rusty, however it seems that you are generating a new secret key on the fly each time in this line of code:

originalKey = new SecretKeySpec(factory.generateSecret(spec).getEncoded(),"AES");
key = originalKey;

What you should do is to call originalKey = new SecretKeySpec(factory.generateSecret(spec).getEncoded(),"AES"); only once (outside your function) and save the result somewhere safe. Then, use this same key for your encryptions and decryptions. In this case you'll be able to revert to your original message even when you restart your program.

I tried your code as-is and it works perfectly, just fix the key so you don't use different keys between different sessions.

CodePudding user response:

You want to make sure, that the encryption of the original always produces the same result. Then you have to remove the element of Randomness during encrypting.

You can create the iv yourself once. And use that in your init-calls then the encryption result will always be the same:

    // create the "random" element once, randomly.
    SecureRandom secureRandom = new SecureRandom();
    byte[] fixedIv = new byte[16];
    secureRandom.nextBytes(fixedIv);

// always use the same "random" element
encryptionCipher.init(Cipher.ENCRYPT_MODE, key, fixedIv);

Afterwards you need to make sure to use that fixedIv all the time together with the key.

  • Related