diff -r 5072524fcc79 -r 80ef3a206772 Symbian3/PDK/Source/GUID-CFF1BCCA-5D07-5B8A-9363-AD11EEEAB485-GENID-1-12-1-26-1-1-9-1-5-1-4-1.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Symbian3/PDK/Source/GUID-CFF1BCCA-5D07-5B8A-9363-AD11EEEAB485-GENID-1-12-1-26-1-1-9-1-5-1-4-1.dita Fri Jul 16 17:23:46 2010 +0100 @@ -0,0 +1,190 @@ + + + + + +Symmetric +ciphers -- HowTo + +
How do I use +the symmetric cipher framework?
    +
  • An introduction to the symmetric cipher framework

  • +
  • CSymmetricCipher interface basics

  • +
  • Example code for a symmetric factory class

  • +

An introduction +to the symmetric cipher framework

The symmetric cipher framework +collates the behaviour of all symmetric ciphers under one interface: 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.

CSymmetricCipher +interface basics

    +
  • Block ciphers -- +Here one must create an underlying transformation (CBlockTransformation) +and create a CBufferedTransformation (which is an CSymmetricCipher) +from that.

  • +
  • Stream ciphers -- +These have no concept of buffering and are treated as specializations of CSymmetricCipher. +They require no intermediate container class.

  • +

The following code illustrates the creation of a buffered AES ECB +encryptor and an ARC4 stream cipher.

+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 + +CSymmetricCipher* cipher = new(ELeave)CARC4(aKey); +CleanupStack::PushL(cipher): +

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

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

In this example, input and input2 are +two arbitrary, finite length descriptors. The derived implementations of CSymmetricCipher (CBufferedEncryptor / CBufferedDecryptor and CStreamCipher) +are responsible for handling what to do in each specific case. For example, +in the case of an encrypting block cipher, 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 MaxOutputLength() and MaxFinalOutputLength() are +calculated see How +does buffering work within the symmetric cipher framework?.

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.

+CSymmetricCipher* CCipherFactory::BuildEncryptorL( + TSymmetricCipherType aType,const TDesC8& aKey,const TDesC8& aIV) + { + CSymmetricCipher* cipher = NULL; + + if (aType==ERc4) + { + cipher = new(ELeave) CARC4(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; + } +

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

Note that a similar 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.

+
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 CBlockChainingMode class, +which is a specialization of CBlockTransformation. The +idea is that one gives an implementation of a CBlockChainingMode another CBlockTransformation (CAESEncryptor, for instance) and then performs all operations on the CBlockChainingMode instance. +When CBlockTransformation::Transform() is called on the +mode, it is responsible for calling 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.

+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 +
+
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.

+
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 aInputLength parameter passed in.

  • +
  • Block ciphers controlled +through a CBufferedTransformation operate under the following +rules:

      +
    • Process()

        +
      • Any previously buffered +data is (logically) prepended to aInput.

      • +
      • All whole blocks are +transformed and appended to aOutput.

      • +
      • Any remaining partial +blocks, orphaned by the above rule, are buffered.

      • +
    • +
    • ProcessFinalL()

        +
      • Encryption

          +
        1. Any previously buffered +data is (logically) prepended to aInput.

        2. +
        3. All whole block are +transformed and appended to aOutput.

        4. +
        5. 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).

        6. +
        7. The resulting block(s) +are transformed and appended to aOutput.

        8. +
      • +
      • Decryption

          +
        1. The input must be +a multiple of the block size.

        2. +
        3. Data is decrypted and +unpadded using underlying padding system.

        4. +
        5. Decrypted, unpadded +data is appended to aOutput.

        6. +
      • +
    • +
  • +

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().

+
\ No newline at end of file