|
1 /** |
|
2 @page symmetric_ciphers Symmetric Cipher |
|
3 |
|
4 - @ref symmetricWhat |
|
5 - @ref symmetricHow |
|
6 - @ref symmetricModes |
|
7 - @ref symmetricWhich |
|
8 - @ref symmetricBuffering |
|
9 |
|
10 <hr> |
|
11 |
|
12 @section symmetricWhat What are symmetric ciphers? |
|
13 |
|
14 In an informal setting, symmetric ciphers can be thought of as a mapping of some |
|
15 plaintext to ciphertext, via some well-known transformation function, dependent |
|
16 on a secret key. There are two basic types of symmetric ciphers: |
|
17 - Stream ciphers -- These map an n-bit stream of plaintext to a n-bit stream of |
|
18 ciphertext. |
|
19 - Block ciphers -- These map m n-bit blocks of plaintext to m n-bit blocks |
|
20 of ciphertext. Because the base unit of transformation is the n-bit |
|
21 block, messages that are not exactly divisible by n must be padded (\c CPadding) |
|
22 to allow for their encryption. Optionally, instead of padding out a |
|
23 plaintext message to fit in a block, block ciphers allow buffering of |
|
24 partial input blocks until the remainder of the block is given as input. |
|
25 (@ref symmetricBuffering). Finally, block ciphers have a concept of modes |
|
26 (@ref symmetricModes) that provide a mechanism for making subsequent |
|
27 blocks dependent on some number of previous blocks. |
|
28 |
|
29 <hr> |
|
30 @section symmetricHow How do I use the symmetric cipher framework? |
|
31 |
|
32 - @ref symmetricHowIntro |
|
33 - @ref symmetricHowInterface |
|
34 - @ref symmetricHowFactory |
|
35 |
|
36 @subsection symmetricHowIntro An introduction to the symmetric cipher framework. |
|
37 The symmetric cipher framework collates the behaviour of all symmetric ciphers |
|
38 under one interface: \c CSymmetricCipher. This interface is intended to represent |
|
39 one direction of one instance of any symmetric cipher. One direction means |
|
40 either encryption or decryption, but not both. |
|
41 |
|
42 @subsection symmetricHowInterface CSymmetricCipher interface basics. |
|
43 - Block ciphers -- Here one must create an underlying transformation (\c |
|
44 CBlockTransformation) and create a \c CBufferedTransformation (which is an |
|
45 \c CSymmetricCipher) from that. |
|
46 - Stream ciphers -- These have no concept of buffering and are treated as |
|
47 specialisations of \c CSymmetricCipher. They require no intermediate container |
|
48 class. |
|
49 |
|
50 The following code illustrates the creation of a buffered AES ECB encryptor and an |
|
51 ARC4 stream cipher. |
|
52 |
|
53 @code |
|
54 CBlockTransformation* block = 0; |
|
55 block = CAESEncryptor::NewLC(aKey); |
|
56 CPadding* padding = CPaddingSSLv3::NewLC(KAESBlockSize); //The blocksize of AES (16 bytes) |
|
57 CSymmetricCipher* cipher = CBufferedEncryptor::NewL(block, padding); |
|
58 CleanupStack::Pop(2, block); //padding, block -> both owned by cipher |
|
59 @endcode |
|
60 |
|
61 @code |
|
62 CSymmetricCipher* cipher = new(ELeave)TARC4(aKey); |
|
63 CleanupStack::PushL(cipher): |
|
64 @endcode |
|
65 |
|
66 After creation, both examples are usable through the \c CSymmetricCipher interface. |
|
67 So, to encrypt with either of the above ciphers one could do: |
|
68 |
|
69 @code |
|
70 HBufC8* output = HBufC8::NewLC(cipher->MaxOutputLength(input.Size())); |
|
71 cipher->Process(input, output); |
|
72 HBufC8* output2 = HBufC8::NewLC(cipher->MaxFinalOutputLength(input2.Size())); |
|
73 cipher->ProcessFinalL(input2, output2); |
|
74 @endcode |
|
75 |
|
76 In this example, \c input and \c input2 are two arbitrary, finite length descriptors. |
|
77 The derived implementations of \c CSymmetricCipher (\c CBufferedEncryptor / \c CBufferedDecryptor |
|
78 and \c CStreamCipher) are responsible for handling what to do in each specific |
|
79 case. For example, in the case of an encrypting block cipher, \c ProcessFinalL() |
|
80 will call the underlying padding system, which will in turn ensure that the |
|
81 overall length of input plaintext is of a suitable length for encryption. For more |
|
82 information on how the values returned from \c MaxOutputLength() and |
|
83 \c MaxFinalOutputLength() are calculated see @ref symmetricBuffering. |
|
84 |
|
85 @subsection symmetricHowFactory Example code for a symmetric factory class. |
|
86 |
|
87 To simplify the process of creating symmetric encryptors and decryptors, it is |
|
88 strongly recommended that applications create a factory that automates the |
|
89 process for them. The following code gives a sample factory that applications |
|
90 might like to use as a reference. It is not supplied as part of the framework |
|
91 as every application has different ways of identifying symmetric cipher suites. |
|
92 |
|
93 @code |
|
94 CSymmetricCipher* CCipherFactory::BuildEncryptorL( |
|
95 TSymmetricCipherType aType,const TDesC8& aKey,const TDesC8& aIV) |
|
96 { |
|
97 CSymmetricCipher* cipher = NULL; |
|
98 |
|
99 if (aType==ERc4) |
|
100 { |
|
101 cipher = new(ELeave) TARC4(aKey); |
|
102 } |
|
103 else |
|
104 { |
|
105 CBlockTransformation* bT = NULL; |
|
106 switch (aType) |
|
107 { |
|
108 case EDes_cbc: |
|
109 bT = CDESEncryptor::NewL(aKey); |
|
110 break; |
|
111 case EDes_ede3_cbc: |
|
112 bT = C3DESEncryptor::NewL(aKey); |
|
113 break; |
|
114 case ERc2_cbc: |
|
115 bT = CRC2Encryptor::NewL(aKey); |
|
116 break; |
|
117 default: |
|
118 User::Leave(KErrNotSupported); |
|
119 }; |
|
120 CleanupStack::PushL(bT); |
|
121 CBlockTransformation* mode = CModeCBCEncryptor::NewL(bT, aIV); |
|
122 CleanupStack::Pop(bT); // owned by mode |
|
123 CleanupStack::PushL(mode); |
|
124 |
|
125 CPadding* padding = CPaddingSSLv3::NewLC(KBlockSize); //All of these ciphers use 8 byte blocks |
|
126 cipher = CBufferedEncryptor::NewL(mode, padding); |
|
127 CleanupStack::Pop(2, mode); //padding, mode now owned by cipher |
|
128 } |
|
129 return cipher; |
|
130 } |
|
131 @endcode |
|
132 |
|
133 Applications creating these factories need to supply an equivalent to the |
|
134 \c TSymmetricCipherType enum which contains the list of identifiers representing |
|
135 the cipher, padding, and mode requirements of the application. |
|
136 |
|
137 Note that a similar \c BuildDecryptorL() will also have to be created. |
|
138 |
|
139 Good naming conventions dictate that applications should not pollute the |
|
140 global namespace and either use their own namespace or prefix their factory |
|
141 classes with identifiers that associated it with that specific application. |
|
142 |
|
143 <hr> |
|
144 @section symmetricModes Symmetric Modes |
|
145 |
|
146 When the amount of plaintext to be encrypted is larger than a single block, some |
|
147 method must be employed to specify how subsequent blocks are dependent on |
|
148 previous blocks. The simplest method, known as ECB (Electronic CodeBook), |
|
149 specifies that subsequent blocks are completely independent. Therefore, two |
|
150 identical blocks of plaintext will encrypt to two identical blocks of |
|
151 ciphertext. ECB has significant security drawbacks, thus most applications use |
|
152 more advanced modes in which subsequent blocks are dependent on the ciphertext |
|
153 of previous blocks. The symmetric framework handles these modes through the |
|
154 \c CBlockChainingMode class, which is a specialisation of \c CBlockTransformation. |
|
155 The idea is that one gives an implementation of a \c CBlockChainingMode another |
|
156 \c CBlockTransformation (\c CAESEncryptor, for instance) and then performs all |
|
157 operations on the \c CBlockChainingMode instance. When |
|
158 <code>CBlockTransformation::Transform()</code> is called on the mode it is responsible for |
|
159 calling \c Transform() on the underlying transformation that it owns and then |
|
160 applying its own chaining mode transformation. |
|
161 |
|
162 The following example shows how to create a buffered AES CBC encryptor. |
|
163 |
|
164 @code |
|
165 CBlockTransformation* basicAesBlock = 0; |
|
166 CBlockTransformation* cbcBlock = 0; |
|
167 basicAesBlock = CAESEncryptor::NewLC(aKey); |
|
168 cbcBlock = CModeCBCEncryptor::NewL(basicAesBlock, iv); |
|
169 CleanupStack::Pop(basicAesBlock); //owned by cbcBlock |
|
170 CleanupStack::PushL(cbcBlock); |
|
171 CPadding* padding = CPaddingSSLv3::NewLC(KAESBlockSize); //The blocksize of AES (16 bytes) |
|
172 CSymmetricCipher* cipher = CBufferedEncryptor::NewL(cbcBlock, padding); |
|
173 CleanupStack::Pop(2, cbcBlock); //padding, cbcBlock -> both owned by cipher |
|
174 @endcode |
|
175 |
|
176 <hr> |
|
177 @section symmetricWhich Which symmetric cipher should I use? |
|
178 Generally, when implementing secure comms protocols, the cipher you use will be |
|
179 dictated by the protocol specification. However, if you are writing your own |
|
180 application you should consider the use of AES (CAESEncryptor). This is the |
|
181 cipher recommended by <A HREF="http://csrc.nist.gov/cryptval/">NIST</A>. |
|
182 |
|
183 <hr> |
|
184 @section symmetricBuffering How does buffering work within the symmetric cipher framework? |
|
185 |
|
186 - Stream ciphers consume all content they are given. That is, the value |
|
187 returned from <code>CSymmetricCipher::MaxOutputLength()</code> is always the same as the |
|
188 \c aInputLength parameter passed in. |
|
189 - Block ciphers controlled through a \c CBufferedTransformation operate under the |
|
190 following rules: |
|
191 - \c Process() |
|
192 -# Any previously buffered data is (logically) prepended to \c aInput. |
|
193 -# All whole blocks are transformed and appended to \c aOutput. |
|
194 -# Any remaining partial blocks, orphaned by the the above rule, are |
|
195 buffered. |
|
196 - \c ProcessFinalL() |
|
197 - Encryption |
|
198 -# Any previously buffered data is (logically) prepended to \c aInput. |
|
199 -# All whole block are transformed and appended to \c aOutput. |
|
200 -# Any remaining partial blocks are padded with underlying padding |
|
201 system to be block aligned <I>to the padding block size</I>. (In the |
|
202 vast majority of cases, the padding block size is equal to the |
|
203 block cipher block size). |
|
204 -# The resulting block(s) are transformed and appended to \c aOutput. |
|
205 - Decryption |
|
206 -# The input <b>must</b> be a multiple of the block size. |
|
207 -# Data is decrypted and unpadded using underlying padding system. |
|
208 -# Decrypted, unpadded data is appended to \c aOutput. |
|
209 |
|
210 In all cases <code>CSymmetricCipher::MaxOutputLength()</code> returns as tight an upper bound |
|
211 as possible on the number of bytes that will be returned by a call to |
|
212 <code>CSymmetricCipher::Process()</code> with a specified number of input bytes. |
|
213 Correspondingly, <code>CSymmetricCipher::MaxFinalOutputLength()</code> returns a similar |
|
214 bound but for a pending call to <code>CSymmetricCipher::ProcessFinalL()</code>. |
|
215 */ |