javaencryptioncryptographypassword-encryptionjce

Why does my encryption returns weird string of symbols as the encrypted text?


I am creating an algorithm where it has to encrypt and decrypt passwords by using JCE and AES. I will keep the encrypted text into a database, however I'm facing two problems. The first problem being that the encrypted text is returning weird symbols and not letters, like "c~ù▼=¡£¡?Å♠?¡Ç²?", but it returns the correct normal text. The second problem is that the algorithm would return a different encrypted text every time and if I were to save the encrypted text into a database and decrypt it later, would it still work? Or would I have to store the value as byte[] or String.

public static void main(String[] args) throws Exception {

    byte[] text1 = "welcome back".getBytes();
    byte[] text2 = "hello guys".getBytes();

    KeyGenerator gen = KeyGenerator.getInstance("AES");
    SecretKey key = gen.generateKey();

    Cipher x = Cipher.getInstance("AES");
    x.init(Cipher.ENCRYPT_MODE, key);
    byte[] encryptedText1 = x.doFinal(text1);
    byte[] encryptedText2 = x.doFinal(text2);

    x.init(Cipher.DECRYPT_MODE,key);
    byte[] decryptedText2 = x.doFinal(encryptedText2);
    byte[] decryptedText1 = x.doFinal(encryptedText1);
    System.out.println(new String(encryptedText1));
    System.out.println(new String(encryptedText2));
    System.out.println(new String(decryptedText1));
    System.out.println(new String(decryptedText2));
}

The results are something like this:

c~ù▼=¡£¡?Å♠?¡Ç²?
àÉ?<-??Yò*?b?]?
welcome back
hello guys

Is there anything I can do to fix these problems? Thank you very much.


Solution

  • Second Problem

    The second problem is that the algorithm would return a different encrypted text every time and if I were to save the encrypted text into a database and decrypt it later, would it still work?

    Not completely sure I understand what the problem is. At least for the code in your question, for the same key and same input bytes, you'll get the same encrypted bytes out. But you must use the same key, both when encrypting and decrypting. And this means you need to (securely!) store the key somewhere.

    If you're worried about seeing different output each time you run your example code, then that's because you generate a new key each time.

    This can get complicated though, and I'd like to state I'm not a cryptography expert. I believe to use symmetric encryption properly, you want to avoid the same plain text resulting in the same cipher text. There are also different modes of AES, requiring different approaches. My point is that you should either do a lot of research, or hire an expert (if not both).


    First Problem

    The first problem being that the encrypted text is returning weird symbols and not letters, like "c~ù▼=¡£¡?Å♠?¡Ç²?", but it returns the correct normal text

    Those "weird symbols" are not indicative of a problem. This is the sort of thing you should expect to see when you attempt to decode a random sequence of bytes into characters.

    Your code first encodes a sequence of characters (the String) into a sequence of bytes (a byte[]). You then encrypt this sequence of bytes and receive a new essentially random sequence of bytes back. The encrypted bytes do not represent a sequence of characters anymore. Attempting to decode these encrypted bytes into a sequence of characters can yield anything from the charset used, including the "fallback/error" character. This is okay though because, again, the encrypted bytes do not represent a sequence of characters.

    When you decrypt the encrypted bytes, you get the original sequence of bytes back. The decrypted bytes do, of course, represent a sequence of characters, and thus can be decoded into those characters. Note you must use the same charset when encoding and decoding the plain text in order to guarantee correctness. To ensure this, you should specify a charset. For example:

    // encode
    byte[] bytes = "Hello, World!".getBytes(StandardCharasets.UTF_8);
    // decode
    String string = new String(bytes, StandardCharsets.UTF_8);
    

    Note this does not attempt to decode a sequence of encrypted bytes. It decodes the original bytes, the same bytes you'd get back after decrypting the encrypted bytes.

    If you want to view the encrypted bytes as a String, then encoding those bytes into Base64 is a common solution. Base64 can also be used for other non-character bytes, such as image files, or even bytes representing characters.

    byte[] bytes = "Hello, World!".getBytes(StandardCharasets.UTF_8);
    byte[] encryptedBytes = encrypt(bytes);
    String base64Text = Base64.getEncoder().encodeToString(encryptedBytes);
    

    Note if you store the base64Text, then when you go to decrypt, you'll first need to decode the Base64 bytes into the original encrypted bytes.