Search code examples
javaencryptioncryptographyaes

Java Cipher AES not encrypting whole String


I am trying to encrypt and decrypt a string using java Cipher with the AES algorithm. But somehow it does not want to encrypt the whole string. My goal is not to encrypt something particullary safely, I want that someone just cant read the String very easily (later stored in a file).

To encrypt, I use the following code:

Cipher cipher = Cipher.getInstance("AES");
byte[] input = plain.getBytes();
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypted = cipher.doFinal(input);

return new String(encrypted);

And to decrypt, I use the following code:

Cipher cipher = Cipher.getInstance("AES");
byte[] input = encrypted.getBytes();
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypted = cipher.doFinal(input);

return new String(decrypted);

To test the code mentioned above, I use the following parameters:

SecretKeySpec key = new SecretKeySpec(new byte[]{103,38,125,-67,-71,-23,-119,102,78,-3,-33,-23,-5,32,-112,-124}, "AES");
String plain = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur auctor ornare bibendum."

That test results in the encrypted and then again decrypted string:

�T���Ѩ�%���Kr sit amet, consectetur adipiscing elit. Curabitur auctor ornare bibendum.

Solution

  • There are several issues:

    byte[] encrypted = cipher.doFinal(input);
    return new String(encrypted);
    

    The problen is that you cannot just "stringify" a byte array, you need to represent the byte array in a different format, such as Base64 or Hex. String is intended only for printable characters.

    Problems converting byte array to string and back to byte array

    byte[] encrypted = cipher.doFinal(input);
    return Base64.getEncoder().encodeToString(encrypted);
    

    And the same way - you need to decode the encoded string into a byte array before decryption.

    Edit:

    Another issue - you should specify full mode of operation

    By default the "AES" parameter should use the CBC mode if IV (initialization vector) is supplied and ECB mode if IV is not defined (at lease this is how Oracle JDK works as far I know).

    it is not guaranteed for all runtimes. Which platform/jre are you using? . As your first block of bytes is scrambled I assume the implementation is using random IV (you can use cipher. getIV()) and you have to pass the IV when decrypting.

    cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    
    IvParameterSpec ivParamSpec = new IvParameterSpec(iv);
    SecretKey symmetricKey = new 
    SecretKeySpec(encryptionParams.getKey(), SYMMETRIC_KEY_ALG);
    
    cipher.init(Cipher.ENCRYPT_MODE, symmetricKey, ivParamSpec);
    

    For CBC the IV must be a random byte array of length of the AES block size (128 bit =16 bytes) and the common practice is to prepend the IV to the ciphertext.

    Please do learn something about using encryption properly, otherwise you may end up with unsecure solution.

    I have a small reference project you may try to use.