0

I am using the following simple encrypt and decrypt functions just to see that it works before using more complicated security features like padding and hashing. For some reason the returned clear text is not similar to the original message. Here is the code:

public static byte[] encrypt(SecretKey secret, byte[] buffer) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidParameterSpecException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException
{
    /* Encrypt the message. */
    cipher = Cipher.getInstance("AES/CTR/NoPadding");
    cipher.init(Cipher.ENCRYPT_MODE, secret);
    byte[] ciphertext = cipher.doFinal(buffer);

    return ciphertext;
}

public static byte[] decrypt(SecretKey secret, byte[] buffer) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidParameterSpecException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException
{
    /* Decrypt the message. - use cipher instance created at encrypt */
    cipher.init(Cipher.DECRYPT_MODE, secret);
    byte[] clear = cipher.doFinal(buffer);

    return clear;
}

and the calling code:

    SecretKey secret1 = null;
    byte[] ciphertext = null;
    byte[] message = "Hello, World!".getBytes();
    byte[] clear = null;

    try {
// aSecret is a shared secret generated with ECDH
        secret1 = Crypto.createAESKey(aSecret);
        ciphertext = Crypto.encrypt(secret1, message);
        clear = Crypto.decrypt(secret1, ciphertext);

        String s = new  String(clear);//clear.toString();

        keyAText.setText(new String(message));
        keyBText.setText(s);

        return;
    } catch (InvalidKeySpecException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidParameterSpecException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (BadPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
Simon
  • 509
  • 7
  • 25
  • 1
    calling `toString` on a byte array is not doing what you think. Have a look at the `String` constructors. – Henry May 27 '14 at 09:15
  • have a look at this http://stackoverflow.com/questions/17535918/aes-gets-different-results-in-ios-and-java/19219718#19219718 – A.S. May 27 '14 at 09:16
  • Henry - even if the string is not built correctly I would expect both byte arrays to generate the same "string". – Simon May 27 '14 at 09:40
  • @Simon no, since it is not the same instance. The default `toString` method shows the hash code of the object as part of the string. – Henry May 27 '14 at 09:51
  • I just went into the debugger and the byte array sent for encryption is: [72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33] while the onereturned from decrypt is: [-47, -44, 19, 39, 63, 113, -103, 81, 44, -22, -59, 45, 115] – Simon May 27 '14 at 09:58
  • I have updated the question with the right code to build the String. Question is still valid as I don't get the same string. – Simon May 27 '14 at 10:04
  • 1
    Are you sure you want to use AES Counter mode? If yes, the same IV value must be used for encryption and decryption. – Henry May 27 '14 at 10:10
  • Next I am going to use IV and maybe "AES/CBC/PKCS5Padding". I am trying to understand first why this simple code is not working well – Simon May 27 '14 at 10:12
  • Same issue, Henry already gave you a hint in the right direction... – Maarten Bodewes May 27 '14 at 11:46

1 Answers1

2

This is almost certainly due to the fact that you don't provide an IV using IvParameterSpec during initialization. On Java SE, your code won't even run due to the fact that CTR requires this parameter to be set. Other providers may however implement things differently, e.g. they may provide a random IV instead.

Of course, if you use a different random IV during encryption and decryption, your decryption result will likely not match your plaintext.

Try the following amended methods:

public static byte[] encrypt(SecretKey secret, byte[] buffer) throws GeneralSecurityException
{
    /* Encrypt the message. */
    Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");

    SecureRandom rng = new SecureRandom();
    byte[] ivData = new byte[cipher.getBlockSize()];
    rng.nextBytes(ivData);

    cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(ivData));
    byte[] ciphertext = cipher.doFinal(buffer);

    return Arrays.concatenate(ivData, ciphertext);
}

public static byte[] decrypt(SecretKey secret, byte[] buffer) throws GeneralSecurityException
{
    /* Decrypt the message. - use cipher instance created at encrypt */
    Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");

    int n = cipher.getBlockSize();
    byte[] ivData = Arrays.copyOf(buffer, n);

    cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(ivData));
    byte[] clear = cipher.doFinal(buffer, n, buffer.length - n);

    return clear;
}
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • Note that I've not added any checks on parameters in the methods, and I will refrain from giving security advice (such as using GCM mode instead). – Maarten Bodewes May 27 '14 at 11:44