5

I am trying to learn more about AES encryption. AES encryption uses both the key and initialization vector (IV) for encryption, but since each IV is different, how does AES decrypt the ciphertext and return the plaintext?

 

public static byte[] encrypt_cbc(SecretKey skey, String plaintext) {
    /* Precondition: skey is valid; otherwise IllegalStateException will be thrown. */
    try {
        byte[] ciphertext = null;
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final int blockSize = cipher.getBlockSize();
        byte[] initVector = new byte[blockSize];
        (new SecureRandom()).nextBytes(initVector);
        IvParameterSpec ivSpec = new IvParameterSpec(initVector);
        cipher.init(Cipher.ENCRYPT_MODE, skey, ivSpec);
        byte[] encoded = plaintext.getBytes(java.nio.charset.StandardCharsets.UTF_8);
        ciphertext = new byte[initVector.length + cipher.getOutputSize(encoded.length)];
        for (int i=0; i < initVector.length; i++) {
            ciphertext[i] = initVector[i];
        }
        // Perform encryption
        cipher.doFinal(encoded, 0, encoded.length, ciphertext, initVector.length);
        return ciphertext;
    } catch (NoSuchPaddingException | InvalidAlgorithmParameterException | ShortBufferException |
        BadPaddingException | IllegalBlockSizeException | InvalidKeyException | NoSuchAlgorithmException e)
    {
        /* None of these exceptions should be possible if the precondition is met. */
        throw new IllegalStateException(e.toString());
    }
}

public static String decrypt_cbc(SecretKey skey, byte[] ciphertext)
    throws BadPaddingException, IllegalBlockSizeException /* These indicate corrupt or malicious ciphertext */
{
    try {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final int blockSize = cipher.getBlockSize();
        byte[] initVector = Arrays.copyOfRange(ciphertext, 0, blockSize);
        IvParameterSpec ivSpec = new IvParameterSpec(initVector);
        cipher.init(Cipher.DECRYPT_MODE, skey, ivSpec);
        byte[] plaintext = cipher.doFinal(ciphertext, blockSize, ciphertext.length - blockSize);
        return new String(plaintext);
    } catch (NoSuchPaddingException | InvalidAlgorithmParameterException |
        InvalidKeyException | NoSuchAlgorithmException e)
    {
        /* None of these exceptions should be possible if precond is met. */
        throw new IllegalStateException(e.toString());
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ilovetolearn
  • 2,006
  • 5
  • 33
  • 64
  • 1
    Hmm, I recognize my exception handling I think, but I would never use underscores in my method names or remove the entire stacktrace in the catch block. Or use `final` now and then. Or assign `null` to the ciphertext. Or still use CBC. Not all that great an example when it comes to code practices. Could be hell of a lot worse though! – Maarten Bodewes May 27 '17 at 14:36
  • @youcanlearnanything *"How does AES decrypt with **different** IV?"* - Can you give an example where you've seen this? The IV must be the same for one encryption/decryption-cycle – Artjom B. May 27 '17 at 16:48
  • @ArtjomB. If this is what is meant then it could be that the first 16 bytes make a bit of sense by pure luck or because the IV is only partly different (it is XOR'ed with the plaintext, so). Only the first block is affected if the IV differs. – Maarten Bodewes May 27 '17 at 20:26
  • @ArtjomB. byte[] initVector = new byte[blockSize]; (new SecureRandom()).nextBytes(initVector); IvParameterSpec ivSpec = new IvParameterSpec(initVector); cipher.init(Cipher.ENCRYPT_MODE, skey, ivSpec); – ilovetolearn May 28 '17 at 04:03
  • @ArtjomB. Wouldnt new SecureRandom() generates a unique IV? – ilovetolearn May 28 '17 at 04:03
  • @youcanlearnanything *Unique* is a strong word. 128 bits is sufficiently large that a collision with a previous IV is incredibly improbable. But the IV for CBC mode doesn't have to be unique. It has to be unpredictable as Maarten pointed out. I still don't understand what you're actually asking. – Artjom B. May 28 '17 at 07:12
  • I have been reading about the difference between IV and key. In general, it is recommended to use different IV if the same key is re-used for encryption. So how does using different IV helps to prevent the ciphertext being decipher? – ilovetolearn May 28 '17 at 07:37

1 Answers1

1

Generally the random IV - CBC requires an unpredictable IV - is prefixed to the ciphertext and "removed" before decryption. I've put removed in quotes as removing it may as well be copying it and skipping it afterwards. In principle it can be placed about anywhere near the ciphertext though. The IV for CBC mode is equal to the block size of the underlying cipher (Cipher#getBlockSize()), i.e. 16 bytes for AES, so the size is known in advance.

The IV doesn't need to be kept secret from an attacker.

In general the type and security of the IV depends on the mode of encryption. For CBC it is required to be unpredictable, for CTR (counter mode) it should not overlap another counter value and for GCM it needs to be a 12 byte nonce.

There are other ways of sharing an IV. For CBC it is for instance possible to keep a counter on both sides and encrypt that counter to form an IV (after encoding it to 16 bytes, of course). That way the IV doesn't need to be included with the ciphertext.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • What I don't get is that the code fragment that you've shown actually does already prefix the IV, what gives? – Maarten Bodewes May 27 '17 at 14:33
  • I have been reading about the difference between IV and key. In general, it is recommended to use different IV if the same key is re-used for encryption. So how does using different IV helps to prevent the ciphertext being decipher? – ilovetolearn May 28 '17 at 07:37
  • Generally it doesn't. The IV is mainly to make the cipher non-deterministic; if you would repeat (part of) a message you don't want to have the same ciphertext as that leaks information. Repeated messages are quite common. A possible exception is SIV (synthetitic IV) mode where the IV doubles as an authentication tag. So reusing the IV leaks information even without decrypting the ciphertext. – Maarten Bodewes May 28 '17 at 09:48
  • Except where counter mode is used; there reusing the IV breaks the cipher almost completely. – Maarten Bodewes May 28 '17 at 09:52
  • Advanced Encryption Standard (AES) with key sizes of 128 and 256 bits. For traffic flow, AES should be used with either the Counter Mode (CTR) for low bandwidth traffic or the Galois/Counter Mode (GCM) mode of operation for high bandwidth traffic (see Block cipher modes of operation) – symmetric encryption Ref: https://en.wikipedia.org/wiki/Advanced_Encryption_Standard – ilovetolearn May 28 '17 at 15:36
  • My rest API receives data and I would like to write them to text files. In his case, I should use GCM mode as it provides better performance? – ilovetolearn May 28 '17 at 15:38