Sunday, October 25, 2009

Symmetric Block Cipher Modes


















































Symmetric Block Cipher Modes


Quite a number of modes have been proposed for
symmetric block ciphers. This chapter restricts itself to the most well
known, but you can find further details on cipher modes by referring to
Applied Cryptography—Second Edition and Practical Cryptography, both of which are listed in Appendix D.



The
first one, known as ECB mode, is the mode closest to the actual cipher.
The other modes—CBC mode, CTS mode, CTR mode, OFB mode, and CFB
mode—are all really constructed on top of ECB mode and attempt to work
around problems that can result from using ECB mode directly or because
the cipher requires a block of bits at a time to do its job, rather
than being able to stream the data.


Let's start with ECB mode.




ECB Mode


ECB, or Electronic Code Book,
mode describes the use of a symmetric cipher in its rawest form. The
problem with ECB mode is that if there are patterns in your data, there
will be patterns in your encrypted data as well. A pattern,
in this case, is any block of bytes that contains the same values as
another block of bytes. This is more common than you might imagine,
especially if you are processing data that is structured.




Try It Out: Ciphertext Patterns in ECB Mode






Try running the following example. The example
uses DES not so much as a recommendation, but more because having an
8-byte block size (rather than the 16-byte one AES has) makes it much
easier to see the patterns.


package chapter2;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;


/**
* Basic symmetric encryption example with padding and ECB using DES
*/
public class SimpleECBExample
{
public static void main(String[] args) throws Exception
{
byte[] input = new byte[] {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
byte[] keyBytes = new byte[] {
0x01, 0x23, 0x45, 0x67,
(byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef };

SecretKeySpec key = new SecretKeySpec(keyBytes, "DES");

Cipher cipher = Cipher.getInstance("DES/ECB/PKCS7Padding", "BC");

System.out.println("input : " + Utils.toHex(input));

// encryption pass

cipher.init(Cipher.ENCRYPT_MODE, key);

byte[] cipherText = new byte[cipher.getOutputSize(input.length)];

int ctLength = cipher.update(input, 0, input.length, cipherText, 0);

ctLength += cipher.doFinal(cipherText, ctLength);

System.out.println("cipher: " + Utils.toHex(cipherText, ctLength)
+ " bytes: " + ctLength);

// decryption pass

cipher.init(Cipher.DECRYPT_MODE, key);

byte[] plainText = new byte[cipher.getOutputSize(ctLength)];

int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0);

ptLength += cipher.doFinal(plainText, ptLength);

System.out.println("plain : " + Utils.toHex(plainText, ptLength)
+ " bytes: " + ptLength);
}
}

When you run this example, you should see the output:


input : 000102030405060708090a0b0c0d0e0f0001020304050607
cipher: 3260266c2cf202e28325790654a444d93260266c2cf202e2086f9a1d74c94d4e bytes: 32
plain : 000102030405060708090a0b0c0d0e0f0001020304050607 bytes: 24
















How It Works


The words "Code Book" really sum up ECB mode.
Given a particular block of bytes on input, the cipher performs a set
of deterministic calculations, looking up a virtual code book as it
were, and returns a particular block of bytes as output. So given the
same block of input bytes, you will always get the same block of output
bytes. This is how a cipher works in its rawest form.


Notice how the hex string 3260266c2cf202e2 repeats in the ciphertext as the string 001020304050607
does in the input. If you imagine you know nothing about the input data
and are looking at the encrypted data and hoping to work out what the
input data might contain, that pattern will tell you the input data is
repeating. If you already know something about the input data and would
like to know more, the pattern might tell you a lot. If the person who
is generating the encrypted data is also using the same key repeatedly,
a beautiful world might be about to unfold for you if you are the
attacker. As for the person doing the encryption, you can see there is
a problem.






CBC Mode


CBC, or Cipher Block Chaining,
mode reduces the likelihood of patterns appearing in the ciphertext by
XORing the block of data to be encrypted with the last block of
ciphertext produced and then applying the raw cipher to produce the
next block of ciphertext.




Try It Out: Using CBC Mode







Try the following example:


package chapter2;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
* Basic symmetric encryption example with padding and CBC using DES
*/
public class SimpleCBCExample
{
public static void main(String[] args) throws Exception
{
byte[] input = new byte[] {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
byte[] keyBytes = new byte[] {
0x01, 0x23, 0x45, 0x67,
(byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef };
byte[] ivBytes = new byte[] {
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };

SecretKeySpec key = new SecretKeySpec(keyBytes, "DES");
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS7Padding", "BC");


System.out.println("input : " + Utils.toHex(input));

// encryption pass

cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);

byte[] cipherText = new byte[cipher.getOutputSize(input.length)];

int ctLength = cipher.update(input, 0, input.length, cipherText, 0);

ctLength += cipher.doFinal(cipherText, ctLength);

System.out.println("cipher: " + Utils.toHex(cipherText, ctLength)
+ " bytes: " + ctLength);

// decryption pass

cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);

byte[] plainText = new byte[cipher.getOutputSize(ctLength)];

int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0);

ptLength += cipher.doFinal(plainText, ptLength);

System.out.println("plain : " + Utils.toHex(plainText, ptLength)
+ " bytes: " + ptLength);

}
}

You should see the following output:


input : 000102030405060708090a0b0c0d0e0f0001020304050607
cipher: 8a87d41c5d3caead0c21f1b3f12a6cd75424fa086e029e404c89d4c1b9457818 bytes: 32
plain : 000102030405060708090a0b0c0d0e0f0001020304050607 bytes: 24

Notice that this time every block of the encrypted
output is different, even though you can see that the first and third
blocks of the input data are the same. The other item of interest about
the ciphertext in this example is that the first block is also
different from the first block in the ECB example, despite the fact
that they use the same key.

















How It Works


You can see from the highlighted changes that we
are now passing "CBC" rather than "ECB" to the static
Cipher.getInstance() method. This explains how I have moved from ECB to
CBC mode, but how does that explain the change in the output?


Remember, I said earlier that CBC mode works by XORing
the last block of ciphertext produced with the current block of input
and then applying the raw cipher. This explains how the first and the
third blocks of the ciphertext are now different, as the third block of
the ciphertext is now the result of encrypting the XOR of the third
block of input with the second block of ciphertext. The question is,
what do you do about the first block? At that stage nothing has been
encrypted yet.


This is where the javax.crypto.spec.IvParameterSpec object comes in. It is used to carry the initialization vector, or IV, and as the name indicates, the IvParameterSpec is required, in addition to the key, to initialize the Cipher
object. It is the initialization vector that provides the initial block
of "cipher text" that is XORed with the first block of input.






Important 

Forgetting to set the IV or setting it to the
wrong value is a very common programmer error. The indicator for this
error is that the first block of the message will decrypt to garbage,
but the rest of the message will appear to decrypt correctly.






Inline IVs


As you can see, the JCE assumes that the IV will
be passed as an out-of-band parameter. Although this is often the case,
there is another way of dealing with IVs apart from introducing the IV
as an out-of-band parameter to the encryption. In some cases people
also write the IV out at the start of the stream and then rely on the
receiver to read past it before attempting to reconstruct the message.
It's okay to do this, as the IV does not need to be kept secret, but if
you are using the JCE, you still need to provide an IV to Cipher.init()
if you are using a cipher and mode that expects one. Fortunately, this
is easy to do as well; in this case you can simply use an IV, which is
a block of zeros.




Try It Out: Using an Inline IV







Look at the following example:


package chapter2;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
* Symmetric encryption example with padding and CBC using DES
* with the initialization vector inline.
*/
public class InlineIvCBCExample
{
public static void main(String[] args) throws Exception
{
byte[] input = new byte[] {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
byte[] keyBytes = new byte[] {
0x01, 0x23, 0x45, 0x67,
(byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef };
byte[] ivBytes = new byte[] {
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };

SecretKeySpec key = new SecretKeySpec(keyBytes, "DES");
IvParameterSpec ivSpec = new IvParameterSpec(new byte[8]);
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS7Padding", "BC");

System.out.println("input : " + Utils.toHex(input));

// encryption pass

cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);

byte[] cipherText = new byte[
cipher.getOutputSize(ivBytes.length + input.length)];

int ctLength = cipher.update(ivBytes, 0, ivBytes.length, cipherText, 0);

ctLength += cipher.update(input, 0, input.length, cipherText, ctLength);


ctLength += cipher.doFinal(cipherText, ctLength);

System.out.println("cipher: " + Utils.toHex(cipherText, ctLength)
+ " bytes: " + ctLength);

// decryption pass

cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);

byte[] buf = new byte[cipher.getOutputSize(ctLength)];

int bufLength = cipher.update(cipherText, 0, ctLength, buf, 0);

bufLength += cipher.doFinal(buf, bufLength);

// remove the iv from the start of the message

byte[] plainText = new byte[bufLength - ivBytes.length];

System.arraycopy(buf, ivBytes.length, plainText, 0, plainText.length);

System.out.println("plain : " + Utils.toHex(plainText, plainText.length)
+ " bytes: " + plainText.length);
}

}

Run this example and you should see the following output:


input : 000102030405060708090a0b0c0d0e0f0001020304050607
cipher: 159fc9af021f30024211a5d7bf88fd0b9e2a82facabb493f39c5a9febe6a659e85039332be5 6f6a4 bytes: 40
plain : 000102030405060708090a0b0c0d0e0f0001020304050607 bytes: 24

















How It Works


You can see by examining the highlighted pieces of code that there are only two real changes, apart from the use of an IvParameterSpec
with an array of zero value. First, you now call update twice when you
encrypt the message, once to feed in the IV and a second time to feed
in the message. Second, you trim the IV block off the start of the
plaintext so that you only display the bytes making up the message.


This does save you the trouble of passing the IV
out of band with the encrypted message; on the other hand, it makes the
encrypted message a block longer, thus increasing the overhead required
to send the message. It also complicates the code required to process
it.





Creating an IV


The examples in this chapter use a fixed IV.
Although this is very useful for demonstrating what is going on, as it
makes the output of the examples predictable, producing predictable
ciphertext is not something you want in a real-life application. In
real life the messages your applications are encrypting are often very
similar, and in any case, you often cannot control what will be
encrypted generating IVs, dealing with the worst-case scenario appears
to be the best approach. A sensible IV should be as random as you can
make it and preferably unique to a given message. This gives you two
ways of generating an IV: generate a random IV from a random source or
generate a pseudorandom IV using some piece of data unique to the
message you want to encrypt, such as the message number.


As you can see, there are a few things to think
about. If you are interested in a more thorough but still approachable
discussion of IV generation, read the discussion on initialization
vectors in Chapter 5 of Practical Cryptography. (See Appendix D.)





Random IVs



How
you generate an IV depends a lot on what the environment is like. If
you are thinking about using a random IV, the major consideration is
really whether the overhead that is added when you use one is
acceptable. If your messages are short and you are sending a lot of
them, this can rapidly build up. That being said, if you decide to use
a random IV, your best bet is to use a SecureRandom object, see that it is seeded appropriately, and generate the bytes you need. You will look at creating a SecureRandom object in the next section. For now, it enough to say that generating a random IV will often involve no more than the following:


byte[]            ivBytes = new byte[cipherBlockSize];
random.nextBytes(ivBytes);
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);

where cipherBlockSize is the block size of the particular cipher you are using and random is a SecureRandom object.


Alternatively, you can let the Cipher object
generate an IV for you. This will only happen on encryption—obviously,
to decrypt a message, you need to be told the IV. In any case, you
could replace the encryption initialization step in the CBC example with



           cipher.init(Cipher.ENCRYPT_MODE, key);
IvParameterSpec ivSpec = new IvParameterSpec(cipher.getIV());


and take advantage of the Cipher object's ability to generate a random IV. Of course, in real life, you would probably just retrieve the raw bytes using Cipher.getIV() and pass them along with the message to the receiver, who would then create an IvParameterSpec.





Creating a SecureRandom Object


An object based on the java.security.SecureRandom
class can be as simple or as complicated to create as you want.
Initially, they were created solely using constructors and a Sun
provider implementation based on using a SHA-1 hash. In earlier
versions of the JDK, the default initialization of the class caused
major performance issues. These days there is support for the creation
of SecureRandom objects through the factory pattern, meaning that the JCA provider implementers can provide their own, and the default SecureRandom implementation will take advantage of hardware support for random number generation as well.


The upshot is that for the most part, new SecureRandom() will probably do the right thing by you.


If you are using an older version of the JDK and
the default seeding mechanism is destroying performance by causing a
substantial delay when the first SecureRandom is created, you can prevent the default initialization from taking place by using the SecureRandom constructor that takes a byte array.Just make sure you add enough seed material,
in the shape of random timings from mouse events, network events, or
input from the keyboard or any other source available to you, to the SecureRandom
object you have created to make sure you are getting a good-quality
random seed. Things like just the process identifier and system time
are not enough. You need to have enough sources of entropy to make sure
the initial state of your SecureRandom is not easily
guessable. Covering all the possible ways to collect seed material is a
discussion that is not really appropriate to this book; however, if you
are interested in looking into this further, you might want to look at
RFC 1750 and also Chapter 10 of Practical Cryptography (see Appendix D for more information about this book).





Pseudorandom IVs



Most
systems incorporate some idea of message numbering, if for no other
reason than to avoid replay attacks. In any case, I mention message
numbers because they are generally unique to the message across the
system, but the general idea is to find something that travels along
with the message that occurs only once. Another name for such a value
is a nonce, which is short for number used once.


Having found a suitable nonce value, you can generate
an IV for your message by using the nonce as a seed to some other
function that will generate the bytes you need for the IV. As you are
after a block size for the cipher worth of bytes and you would like it
to be unique, just encrypting the nonce with the cipher will work
nicely. In this case you only need to use ECB mode; however, you can
avoid creation of an extra Cipher object by using the CBC cipher with a zero IV—which is exactly the same.




Try It Out: Using an IV Based on a Nonce






Try the following example:


package chapter2;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
* CBC using DES with an IV based on a nonce. In this
* case a hypothetical message number.
*/
public class NonceIvCBCExample
{
public static void main(String[] args) throws Exception
{
byte[] input = new byte[] {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
byte[] keyBytes = new byte[] {
0x01, 0x23, 0x45, 0x67,
(byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef };
byte[] msgNumber = new byte[] {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

IvParameterSpec zeroIv = new IvParameterSpec(new byte[8]);


SecretKeySpec key = new SecretKeySpec(keyBytes, "DES");

Cipher cipher = Cipher.getInstance("DES/CBC/PKCS7Padding", "BC");


System.out.println("input : " + Utils.toHex(input));

// encryption pass

// generate IV

cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);

IvParameterSpec encryptionIv = new IvParameterSpec(
cipher.doFinal(msgNumber), 0, 8);


// encrypt message

cipher.init(Cipher.ENCRYPT_MODE, key, encryptionIv);

byte[] cipherText = new byte[cipher.getOutputSize(input.length)];

int ctLength = cipher.update(input, 0, input.length, cipherText, 0);

ctLength += cipher.doFinal(cipherText, ctLength);

System.out.println("cipher: " + Utils.toHex(cipherText, ctLength)
+ " bytes: " + ctLength);

// decryption pass

// generate IV

cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);

IvParameterSpec decryptionIv = new IvParameterSpec(
cipher.doFinal(msgNumber), 0, 8);


// decrypt message

cipher.init(Cipher.DECRYPT_MODE, key, decryptionIv);

byte[] plainText = new byte[cipher.getOutputSize(ctLength)];

int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0);

ptLength += cipher.doFinal(plainText, ptLength);

System.out.println("plain : " + Utils.toHex(plainText, ptLength)
+ " bytes: " + ptLength);
}
}

Run this example and you will now see the following output:


input : 000102030405060708090a0b0c0d0e0f0001020304050607
cipher: eb913126049ccdea00f2d86fda94a02fd72e0914fd361400d909f45f73058fc3 bytes: 32
plain : 000102030405060708090a0b0c0d0e0f0001020304050607 bytes: 24

As you can see, the ciphertext in the output has now changed substantially as a consequence of the change in IV.


















How It Works



Looking
at the code, there is only really one major change from the original
CBC example: the creation of and handling of the IV. Note that in both
cases when the IV is calculated from the message number, the Cipher
object is initialized for encryption. The reason is that you are not so
much encrypting the message number (stored in the array msgNumber) as using the cipher's encryption mode to calculate an IV from the message number.


This example also introduces one of the convenience methods on Cipher, a Cipher.doFinal(),
which does the full processing on the input array and produces the
resulting ciphertext, complete with padding. The presence of the
padding is the reason why you specify that you only want the first 8
bytes of the ciphertext used in the creation of the IvParameterSpec object; otherwise, the IV will be two blocks, rather than the required one.






A Look at Cipher Parameter Objects


You have seen already how an IV can be passed into Cipher.init() using an IvParameterSpec object. You may have noticed that Cipher.init() can also take AlgorithmParameters objects. Likewise, just as there is a Cipher.getIV(), there is also a Cipher.getParameters() method.






Important 


Cipher.getIV() and Cipher.getParameters() should only be called after Cipher.int() has been called on the cipher of interest.



At this point it would be worth looking briefly at what the difference is between parameter objects that end in the word Spec
and those that do not. As a rule, in the JCE, objects ending in the
word Spec are just value objects. Although these are useful in their
own right, there are also situations where you need to be able to
retrieve the parameters of a Cipher, or some other processing
class, not as a value object but as an object that will produce an
encoded version suitable for transmission to someone else, or for
preservation in a platform-independent manner.





The AlgorithmParameters Class


The AlgorithmParameters objects serve this purpose and contain not just the values for the parameters but also expose methods such as AlgorithmParameters.getEncoded(), which allow the parameters to be exported in a platform-independent manner. The most common encoding method that AlgorithmParameters objects use is one of the binary encodings associated with ASN.1, which is discussed in Chapter 5. The AlgorithmParameters class also has a method on it, AlgorithmParameters.getParameterSpec(), which enables you to recover the value object associated with the parameters contained in the AlgorithmParameters object.


Consequently, calling Cipher.getParameters() will, amongst other things, return the IV, but in an object that can be used to generate an encoded IV, suitable for export.





CTS Mode: A Special Case of CBC


You could make use of CTS, or Cipher Text Stealing, mode in the previous example by replacing the Cipher.getInstance() call with




Cipher cipher = Cipher.getInstance("DES/CTS/NoPadding", "BC");


CTS is defined in RFC 2040 and combines the use of
CBC mode with some additional XOR operations on the final encrypted
block of the data being processed to produce encrypted data that is the
same length as the input data. In some ways, it is almost a padding
mechanism more than a mode, and as it is based around CBC mode, it
still requires the data to be processed in discrete blocks. If you want
to be able to escape from having to process the data in blocks
altogether, you need to use one of the streaming block modes, which are
covered next.





Streaming Symmetric Block Cipher Modes


Both ECB and CBC mode use the underlying cipher
in its most basic way, as an engine that takes in a block of data and
outputs a block of data. Of course, the result of doing this was that
in situations where you did not have data that was a multiple of the
block size in length, you needed to use padding. Although this is an
improvement on the situation, it would be useful to be able to use a
regular block cipher in a manner that allows you to produce encrypted
messages that are the same length as the initial unencrypted messages
without having to resort to the kind of shenanigans that take place in
CTS. Streaming block cipher modes allow you to use a block cipher in
this way.


Look at Figure 2-2
and you will see how the streaming is possible. Unlike ECB and CBC
modes, the three following modes work by producing a stream of bits
that is then XORed with the plaintext. One major thing you need to be
careful of: Reusing an IV and a key together is fatal to the security
of the encryption. As mentioned previously, you should not do this with
CBC mode either, but your exposure, if you do so, will normally be
limited. In the case of the stream modes, your exposure from reusing
the initialization vector will be total. The reasons for this vary
slightly depending on which mode you are using, but the principle
remains the same.






Figure 2-2



CTR Mode


Also known as SIC (Segmented Integer Counter) mode. CTR, or Counter mode, has been around for quite a while but has finally been standardized by NIST in SP 800-38a and in RFC 3686.




Try It Out: CTR Mode







Consider the following example:


package chapter2;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
* Basic symmetric encryption example with CTR using DES
*/
public class SimpleCTRExample
{
public static void main(String[] args) throws Exception
{
byte[] input = new byte[] {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
byte[] keyBytes = new byte[] {
0x01, 0x23, 0x45, 0x67,
(byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef };
byte[] ivBytes = new byte[] {
0x00, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x01 };


SecretKeySpec key = new SecretKeySpec(keyBytes, "DES");
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("DES/CTR/NoPadding", "BC");

System.out.println("input : " + Utils.toHex(input));

// encryption pass

cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);

byte[] cipherText = new byte[cipher.getOutputSize(input.length)];

int ctLength = cipher.update(input, 0, input.length, cipherText, 0);

ctLength += cipher.doFinal(cipherText, ctLength);

System.out.println("cipher: " + Utils.toHex(cipherText, ctLength)
+ " bytes: " + ctLength);

// decryption pass

cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);

byte[] plainText = new byte[cipher.getOutputSize(ctLength)];

int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0);

ptLength += cipher.doFinal(plainText, ptLength);

System.out.println("plain : " + Utils.toHex(plainText, ptLength)
+ " bytes: " + ptLength);
}
}

Running the example, you should see the following output:


input : 000102030405060708090a0b0c0d0e0f00010203040506
cipher: 61a1f886ff9bc709dd37cd9ce33adc6ff9ab110e46f387 bytes: 23
plain : 000102030405060708090a0b0c0d0e0f00010203040506 bytes: 23

As you can see, the Cipher object has produced ciphertext that is the same length as the input data.


















How It Works


From a coding point of view, because of the
benefit of the factory pattern, the only major change from the CBC
example is that you have called Cipher.getInstance() with CTR rather than CBC specified in the mode position, and as you are using a streaming mode, NoPadding rather than PKCS7Padding giving a specification string of “DES/CTR/NoPadding”. You do not need to specify any padding because the mode allows you to work with any length of data.


Note also that the IV ends in 3 zero bytes and a one
byte. In this case, it is a way of telling yourself that you should
limit your processing to data that is no more than 235 bytes (232
times the block size). After that, the counter will go back to zero and
begin cycling at the next block. You can see that encrypting two
messages with the same IV and the same key will result in encrypting
both messages with the same stream of bits. How many messages you can
encrypt with a single key depends on how you treat the first four bytes
of the IV. In a situation like this, you might divide the four bytes in
half and use the first two for the message number and the second two
for random data. This would allow you to process 216 messages before recycling keys.


If you follow these rules, CTR mode works very
well. There are three nice things about CTR mode: It is a stream mode,
so is very easy to work with as you do not have to worry about padding;
it allows for random access to the encrypted data, as you just need to
know the counter value for a particular block; and finally, the areas
where you can get into trouble using CTR mode are obvious from the
design for construction of the IV. Given a particular method of
constructing an IV, it is easy to see how large a message you can
encrypt and how many messages you can process before you have to change
keys. You can be certain of this, as you know that the cipher will be
producing a different block for each increment of the counter until the
counter begins to cycle. You will not have any surprises—in
cryptography, this is a good thing.





OFB Mode


You can make use of OFB, or Output Feedback, mode in the previous example by replacing the Cipher.getInstance() to create the CTR cipher with the following:



           Cipher             cipher = Cipher.getInstance("DES/OFB/NoPadding", "BC");


Like CTR mode, OFB mode works by using the raw block
cipher to produce a stream of pseudorandom bits, which are then XORed
with the input message to produce the encrypted message. The actual
input message
is never used. With OFB mode, rather than considering part of the IV to
be a counter, you just load the IV into a state array, encrypt the
state array, and save the result back to the state array, using the
bits you generated to XOR with the next block of input and generate the
ciphertext.


You might also see the following:



           Cipher             cipher = Cipher.getInstance("DES/OFB8/NoPadding", "BC");


If this is the case, the OFB mode is set so that the
cipher behaves like it has a block size of 8 bits. Virtual block sizes
of 16, 24, 32, and so on are also possible. Do not do this unless you
do so for reasons of compatibility. Security analysis of OFB mode has
shown that it should be used only with an apparent block size that is
the same as the block size of the underlying cipher.


The next biggest problem with OFB mode is that if
the repetition of encrypting the state initialized by the IV leads to
another state value that has occurred before, the value of the state
will simply become a repetition of what occurred previously. You have
to process a lot of data, and be unlucky, for this to be a problem. As
a general rule in cryptography, it is better to avoid anything that
involves the word luck where possible. Current wisdom is to use CTR instead of OFB, as it gives you more control over the key stream.





CFB Mode


CFB, or Cipher Feedback,
is one you will encounter a lot. Its most widespread application is
probably in the OpenPGP message format, described in RFC 2440, where it
used as the mode of choice.


You can make use of CFB mode in the previous example by replacing the Cipher.getInstance() to create the CTR cipher with the following:



           Cipher             cipher = Cipher.getInstance("DES/CFB/NoPadding", "BC");


Like OFB mode and CTR mode, CFB mode produces a stream
of pseudorandom bits that are then used to encrypt the input. Unlike
the others, CFB mode uses the plaintext as part of the process of
generating the stream of bits. In this case, CFB starts with the IV,
encrypts it using the raw cipher and saves it in a state array. As you
encrypt a block of data, you XOR it with the state array to get the
ciphertext and store the resulting ciphertext back in our state array.


Like OFB you can also use CFB mode in the following manner:



           Cipher             cipher = Cipher.getInstance("DES/CFB8/NoPadding", "BC");


This actually changes the way the plaintext gets
fed into the state array. Using the 8-bit mode described previously,
after each encryption step, the bytes in the state array will be
shifted left 8 bits, and the byte of ciphertext that was produced will
be added to the end (something very similar happens in OFB mode as
well, but since you should avoid using OFB mode unless you have to, you
probably do not need to worry about it). Obviously one downside here is
that the smaller the block size dictated by the mode, the more
encryption operations there are. In the case of AES where you have a
16-byte block, using CFB in a 16-bit mode will mean you will have eight
times as many encryption operations. The downside of using CFB in full
block mode is you then risk running into the same problem as OFB with
the bit stream starting to repeat. CFB mode does have some interesting
properties in respect to dealing with synchronization errors, so for
some applications it is probably a contender. It depends on what you
are trying to do.










































1 comment:

Unknown said...

Its a well written article for technical as well as non technical person. With the implementation code you have provided the basic detail to explain how it works. Awesome !
digital signature software