diff -r 000000000000 -r 2c201484c85f crypto/weakcrypto/docs/symmetric.dox --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crypto/weakcrypto/docs/symmetric.dox Wed Jul 08 11:25:26 2009 +0100 @@ -0,0 +1,215 @@ +/** +@page symmetric_ciphers Symmetric Cipher + +- @ref symmetricWhat +- @ref symmetricHow +- @ref symmetricModes +- @ref symmetricWhich +- @ref symmetricBuffering + +
+ +@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. + +
+@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. + +
+@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 +CBlockTransformation::Transform() 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 + +
+@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 NIST. + +
+@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 CSymmetricCipher::MaxOutputLength() 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 to the padding block size. (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 must 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 CSymmetricCipher::MaxOutputLength() returns as tight an upper bound +as possible on the number of bytes that will be returned by a call to +CSymmetricCipher::Process() with a specified number of input bytes. +Correspondingly, CSymmetricCipher::MaxFinalOutputLength() returns a similar +bound but for a pending call to CSymmetricCipher::ProcessFinalL(). +*/