crypto/weakcrypto/docs/symmetric.dox
author Santosh V Patil <santosh.v.patil@nokia.com>
Fri, 14 Aug 2009 11:20:13 +0530
changeset 3 d2beca08722f
parent 0 2c201484c85f
permissions -rw-r--r--
Added missed out swi certificate store data file (Bug 284)

/**
@page symmetric_ciphers Symmetric Cipher

- @ref symmetricWhat
- @ref symmetricHow
- @ref symmetricModes
- @ref symmetricWhich
- @ref symmetricBuffering

<hr>

@section symmetricWhat What are symmetric ciphers?

In an informal setting, symmetric ciphers can be thought of as a mapping of some
plaintext to ciphertext, via some well-known transformation function, dependent
on a secret key.  There are two basic types of symmetric ciphers:
	- Stream ciphers -- These map an n-bit stream of plaintext to a n-bit stream of 
	  ciphertext.
	- Block ciphers -- These map m n-bit blocks of plaintext to m n-bit blocks
	  of ciphertext.  Because the base unit of transformation is the n-bit
	  block, messages that are not exactly divisible by n must be padded (\c CPadding) 
	  to allow for their encryption.  Optionally, instead of padding out a
	  plaintext message to fit in a block, block ciphers allow buffering of
	  partial input blocks until the remainder of the block is given as input.
	  (@ref symmetricBuffering).  Finally, block ciphers have a concept of modes
	  (@ref symmetricModes) that provide a mechanism for making subsequent
	  blocks dependent on some number of previous blocks.

<hr>
@section symmetricHow How do I use the symmetric cipher framework?

- @ref symmetricHowIntro
- @ref symmetricHowInterface
- @ref symmetricHowFactory

@subsection symmetricHowIntro An introduction to the symmetric cipher framework.
The symmetric cipher framework collates the behaviour of all symmetric ciphers
under one interface: \c CSymmetricCipher.  This interface is intended to represent
one direction of one instance of any symmetric cipher.  One direction means
either encryption or decryption, but not both.
	  
@subsection symmetricHowInterface CSymmetricCipher interface basics.
- Block ciphers -- Here one must create an underlying transformation (\c
  CBlockTransformation) and create a \c CBufferedTransformation (which is an
  \c CSymmetricCipher) from that.  
- Stream ciphers -- These have no concept of buffering and are treated as
  specialisations of \c CSymmetricCipher.  They require no intermediate container
  class.  
	  
The following code illustrates the creation of a buffered AES ECB encryptor and an
ARC4 stream cipher.  

@code
CBlockTransformation* block = 0;
block = CAESEncryptor::NewLC(aKey);
CPadding* padding = CPaddingSSLv3::NewLC(KAESBlockSize); //The blocksize of AES (16 bytes)
CSymmetricCipher* cipher = CBufferedEncryptor::NewL(block, padding);
CleanupStack::Pop(2, block); //padding, block -> both owned by cipher
@endcode

@code
CSymmetricCipher* cipher = new(ELeave)TARC4(aKey);
CleanupStack::PushL(cipher):
@endcode

After creation, both examples are usable through the \c CSymmetricCipher interface.
So, to encrypt with either of the above ciphers one could do:

@code
HBufC8* output = HBufC8::NewLC(cipher->MaxOutputLength(input.Size()));
cipher->Process(input, output);
HBufC8* output2 = HBufC8::NewLC(cipher->MaxFinalOutputLength(input2.Size()));
cipher->ProcessFinalL(input2, output2);
@endcode

In this example, \c input and \c input2 are two arbitrary, finite length descriptors.
The derived implementations of \c CSymmetricCipher (\c CBufferedEncryptor / \c CBufferedDecryptor
and \c CStreamCipher) are responsible for handling what to do in each specific
case.  For example, in the case of an encrypting block cipher, \c ProcessFinalL()
will call the underlying padding system, which will in turn ensure that the
overall length of input plaintext is of a suitable length for encryption. For more
information on how the values returned from \c MaxOutputLength() and
\c MaxFinalOutputLength() are calculated see @ref symmetricBuffering.

@subsection symmetricHowFactory Example code for a symmetric factory class.

To simplify the process of creating symmetric encryptors and decryptors, it is
strongly recommended that applications create a factory that automates the
process for them.  The following code gives a sample factory that applications
might like to use as a reference.  It is not supplied as part of the framework
as every application has different ways of identifying symmetric cipher suites.

@code
CSymmetricCipher* CCipherFactory::BuildEncryptorL(
	TSymmetricCipherType aType,const TDesC8& aKey,const TDesC8& aIV)
	{
	CSymmetricCipher* cipher = NULL;

	if (aType==ERc4)
		{
		cipher = new(ELeave) TARC4(aKey);
		}
	else
		{
		CBlockTransformation* bT = NULL;
		switch (aType)
			{
			case EDes_cbc:
				bT = CDESEncryptor::NewL(aKey);
				break;
			case EDes_ede3_cbc:
				bT = C3DESEncryptor::NewL(aKey);
				break;
			case ERc2_cbc:
				bT = CRC2Encryptor::NewL(aKey);
				break;
			default:
				User::Leave(KErrNotSupported);
			};
		CleanupStack::PushL(bT);
		CBlockTransformation* mode = CModeCBCEncryptor::NewL(bT, aIV);
		CleanupStack::Pop(bT);	//	owned by mode
		CleanupStack::PushL(mode);
	 
		CPadding* padding = CPaddingSSLv3::NewLC(KBlockSize); //All of these ciphers use 8 byte blocks
		cipher = CBufferedEncryptor::NewL(mode, padding);
		CleanupStack::Pop(2, mode);	//padding, mode	now owned by cipher
		}
	return cipher;
	}
@endcode

Applications creating these factories need to supply an equivalent to the
\c TSymmetricCipherType enum which contains the list of identifiers representing
the cipher, padding, and mode requirements of the application.  

Note that a similar \c BuildDecryptorL() will also have to be created.

Good naming conventions dictate that applications should not pollute the
global namespace and either use their own namespace or prefix their factory
classes with identifiers that associated it with that specific application.
	 
<hr>
@section symmetricModes Symmetric Modes

When the amount of plaintext to be encrypted is larger than a single block, some
method must be employed to specify how subsequent blocks are dependent on
previous blocks.  The simplest method, known as ECB (Electronic CodeBook),
specifies that subsequent blocks are completely independent.  Therefore, two
identical blocks of plaintext will encrypt to two identical blocks of
ciphertext.  ECB has significant security drawbacks, thus most applications use
more advanced modes in which subsequent blocks are dependent on the ciphertext
of previous blocks.  The symmetric framework handles these modes through the
\c CBlockChainingMode class, which is a specialisation of \c CBlockTransformation.
The idea is that one gives an implementation of a \c CBlockChainingMode another
\c CBlockTransformation (\c CAESEncryptor, for instance) and then performs all
operations on the \c CBlockChainingMode instance.  When
<code>CBlockTransformation::Transform()</code> is called on the mode it is responsible for
calling \c Transform() on the underlying transformation that it owns and then
applying its own chaining mode transformation.

The following example shows how to create a buffered AES CBC encryptor.

@code
CBlockTransformation* basicAesBlock = 0;
CBlockTransformation* cbcBlock = 0;
basicAesBlock = CAESEncryptor::NewLC(aKey);
cbcBlock = CModeCBCEncryptor::NewL(basicAesBlock, iv);
CleanupStack::Pop(basicAesBlock); //owned by cbcBlock
CleanupStack::PushL(cbcBlock);
CPadding* padding = CPaddingSSLv3::NewLC(KAESBlockSize); //The blocksize of AES (16 bytes)
CSymmetricCipher* cipher = CBufferedEncryptor::NewL(cbcBlock, padding);
CleanupStack::Pop(2, cbcBlock); //padding, cbcBlock -> both owned by cipher
@endcode

<hr>
@section symmetricWhich Which symmetric cipher should I use?  
Generally, when implementing secure comms protocols, the cipher you use will be
dictated by the protocol specification.  However, if you are writing your own
application you should consider the use of AES (CAESEncryptor).  This is the
cipher recommended by <A HREF="http://csrc.nist.gov/cryptval/">NIST</A>.

<hr>
@section symmetricBuffering How does buffering work within the symmetric cipher framework?  

- Stream ciphers consume all content they are given.  That is, the value
  returned from <code>CSymmetricCipher::MaxOutputLength()</code> is always the same as the
  \c aInputLength parameter passed in.
- Block ciphers controlled through a \c CBufferedTransformation operate under the
  following rules:
  	- \c Process()
		-# Any previously buffered data is (logically) prepended to \c aInput.
		-# All whole blocks are transformed and appended to \c aOutput.
		-# Any remaining partial blocks, orphaned by the the above rule, are
		buffered.
	- \c ProcessFinalL()
		- Encryption
			-# Any previously buffered data is (logically) prepended to \c aInput.
			-# All whole block are transformed and appended to \c aOutput.
			-# Any remaining partial blocks are padded with underlying padding
			system to be block aligned <I>to the padding block size</I>. (In the
			vast majority of cases, the padding block size is equal to the
			block cipher block size).
			-# The resulting block(s) are transformed and appended to \c aOutput.
		- Decryption
			-# The input <b>must</b> be a multiple of the block size.
			-# Data is decrypted and unpadded using underlying padding system.
			-# Decrypted, unpadded data is appended to \c aOutput.

In all cases <code>CSymmetricCipher::MaxOutputLength()</code> returns as tight an upper bound
as possible on the number of bytes that will be returned by a call to
<code>CSymmetricCipher::Process()</code> with a specified number of input bytes.
Correspondingly, <code>CSymmetricCipher::MaxFinalOutputLength()</code> returns a similar
bound but for a pending call to <code>CSymmetricCipher::ProcessFinalL()</code>.
*/