14

What are some of the simplest ways to AES encrypt and decrypt a 16 byte array without the automatic padding? I have found solutions that use external libraries, but I want to avoid that if possible.

My current code is

SecretKeySpec skeySpec = new SecretKeySpec(getCryptoKeyByteArray(length=16)); // 128 bits
Cipher encryptor = Cipher.getInstance("AES");
encryptor.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = encryptor.doFinal(plain);

How can I prevent the padding? The plain data is always fixed length and includes its own padding. How can I allow plain to be 16 bytes without causing encrypted to become 32 bytes?

rossum
  • 15,344
  • 1
  • 24
  • 38
700 Software
  • 85,281
  • 83
  • 234
  • 341
  • 1
    Did you try `Cipher.getInstance("AES/CBC/NoPadding");`? – Cratylus Sep 30 '11 at 20:36
  • Was the information at *[AES No Padding](https://developer-content.emc.com/docs/rsashare/share_for_java/1.1/dev_guide/group__JCESAMPLES__ENCDEC__SYMCIPHER__AESNOPAD.html)* helpful? – maerics Sep 30 '11 at 20:40
  • @user384706, I already tried that. I got `java.security.InvalidKeyException: Parameters missing` when trying to create the decryption cypher: `decryptor.init(Cipher.DECRYPT_MODE, skeySpec);` After searching again, I found the solution. See my answer. – 700 Software Sep 30 '11 at 20:46
  • @maerics, I found it over-sized. Particularly all the stuff about `ivParamSpec`. I already had my keys generated well ahead of time and did not see a reason for all that. I did not realize that [you can fill the `decryptor` parameters from the `encryptor` parameters](http://www.coderanch.com/t/134143/Security/Java-encryption#648018). – 700 Software Sep 30 '11 at 20:54
  • @GeorgeBailey: neither did I, interesting find! – maerics Sep 30 '11 at 20:59

3 Answers3

18

See my comment. Sorry I probably should have taken a closer look the first time.

  1. Change "AES" to "AES/CBC/NoPadding"
  2. Change decryptor.init(Cipher.DECRYPT_MODE, skeySpec); to decryptor.init(Cipher.DECRYPT_MODE, skeySpec, encryptor.gerParameters());

To encrypt only 16 bytes of data, fixed length, using a method that requires no initialization vector to be saved, Change "AES" to "AES/ECB/NoPadding"

I pick ECB because that is the default.

If you need to encrypt more than 16 bytes, consider using something other than ECB, which suffers a certain repetition detection flaw

In this bitmap example, this image has repeated white blocks, so you can deduce the outline of the image simply by looking for where the blocks become different.

before encryption encrypted

If you are only encrypting one block, it doesn't really matter though, only if you are encrypting multiple blocks that are combined does ECB become revealing.

Related: https://security.stackexchange.com/questions/15740/what-are-the-variables-of-aes

Community
  • 1
  • 1
700 Software
  • 85,281
  • 83
  • 234
  • 341
  • 2
    You normally don't want to use CBC with NoPadding (or only if your data size is always a multiple of 16 bytes). CTR, OFB and CFB mode are usable with NoPadding, CBC not. (Edit: Ah, I missed that your data is already a 16-byte-array. Then it is okay.) – Paŭlo Ebermann Oct 01 '11 at 00:07
  • 3
    Also, your `encrypter.getParameters()` in effect mainly transfers the initialization vector. If you don't encrypt and decrypt in the same process, you would instead send this IV together with your data. – Paŭlo Ebermann Oct 01 '11 at 00:11
  • @Paŭlo, I now discovered what you are referring to. What I wanted was to use ECB so that the IV was not required. – 700 Software Jun 07 '12 at 14:51
  • A good article on why ECB is usually not a good choice: http://www.codinghorror.com/blog/2009/05/why-isnt-my-encryption-encrypting.html – David Carboni Jun 25 '12 at 10:46
6

Agree with @rossum, but there's more to it:

CTR mode needs an initialisation vector (IV). This is a "counter" (which is what "CTR" refers to). If you can store the IV separately (it doesn't need to be protected) that would work. You'll need the same IV value when you decrypt the data.

If you don't want to store the IV and you can guarantee that no two values will be encrypted with the same key, it's fine to use a fixed IV (even an array of 0s).

The above is very important because encrypting more than one message with the same key/IV combination destroys security. See the Initialization vector (IV) section in this Wikipedia article: http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation

An AES CTR implementation of your code might be:

SecretKeySpec skeySpec = new SecretKeySpec(getCryptoKeyByteArray(length=16)); 
Cipher encryptor = Cipher.getInstance("AES/CTR/NoPadding");

// Initialisation vector:
byte[] iv = new byte[encryptor.getBlockSize()];
SecureRandom.getInstance("SHA1PRNG").nextBytes(iv); // If storing separately
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

encryptor.init(Cipher.ENCRYPT_MODE, skeySpec, ivParameterSpec); 
byte[] encrypted = encryptor.doFinal(plain); 
David Carboni
  • 1,556
  • 23
  • 24
2

CTR mode does not require padding: "AES/CTR/NoPadding".

rossum
  • 15,344
  • 1
  • 24
  • 38