cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
ctx_rc5.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib RC5 Encryption Routines *
4 * Copyright Peter Gutmann 1997-2005 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "context.h"
11  #include "rc5.h"
12 #else
13  #include "crypt.h"
14  #include "context/context.h"
15  #include "crypt/rc5.h"
16 #endif /* Compiler-specific includes */
17 
18 #ifdef USE_RC5
19 
20 /* The default number of RC5 rounds */
21 
22 #define RC5_DEFAULT_ROUNDS RC5_12_ROUNDS
23 
24 /* Defines to map from EAY to native naming */
25 
26 #define RC5_BLOCKSIZE RC5_32_BLOCK
27 #define RC5_KEY RC5_32_KEY
28 #define RC5_EXPANDED_KEYSIZE sizeof( RC5_KEY )
29 
30 /****************************************************************************
31 * *
32 * RC5 Self-test Routines *
33 * *
34 ****************************************************************************/
35 
36 #ifndef CONFIG_NO_SELFTEST
37 
38 /* RC5 test vectors from RC5 specification */
39 
40 static const struct RC5_TEST {
41  const BYTE key[ 16 ];
42  const BYTE plaintext[ 8 ];
43  const BYTE ciphertext[ 8 ];
44  } FAR_BSS testRC5[] = {
45  { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
46  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
47  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
48  { 0x21, 0xA5, 0xDB, 0xEE, 0x15, 0x4B, 0x8F, 0x6D } },
49  { { 0x91, 0x5F, 0x46, 0x19, 0xBE, 0x41, 0xB2, 0x51,
50  0x63, 0x55, 0xA5, 0x01, 0x10, 0xA9, 0xCE, 0x91 },
51  { 0x21, 0xA5, 0xDB, 0xEE, 0x15, 0x4B, 0x8F, 0x6D },
52  { 0xF7, 0xC0, 0x13, 0xAC, 0x5B, 0x2B, 0x89, 0x52 } },
53  { { 0x78, 0x33, 0x48, 0xE7, 0x5A, 0xEB, 0x0F, 0x2F,
54  0xD7, 0xB1, 0x69, 0xBB, 0x8D, 0xC1, 0x67, 0x87 },
55  { 0xF7, 0xC0, 0x13, 0xAC, 0x5B, 0x2B, 0x89, 0x52 },
56  { 0x2F, 0x42, 0xB3, 0xB7, 0x03, 0x69, 0xFC, 0x92 } },
57  { { 0xDC, 0x49, 0xDB, 0x13, 0x75, 0xA5, 0x58, 0x4F,
58  0x64, 0x85, 0xB4, 0x13, 0xB5, 0xF1, 0x2B, 0xAF },
59  { 0x2F, 0x42, 0xB3, 0xB7, 0x03, 0x69, 0xFC, 0x92 },
60  { 0x65, 0xC1, 0x78, 0xB2, 0x84, 0xD1, 0x97, 0xCC } },
61  { { 0x52, 0x69, 0xF1, 0x49, 0xD4, 0x1B, 0xA0, 0x15,
62  0x24, 0x97, 0x57, 0x4D, 0x7F, 0x15, 0x31, 0x25 },
63  { 0x65, 0xC1, 0x78, 0xB2, 0x84, 0xD1, 0x97, 0xCC },
64  { 0xEB, 0x44, 0xE4, 0x15, 0xDA, 0x31, 0x98, 0x24 } }
65  };
66 
67 /* Test the RC5 code against the RC5 test vectors */
68 
69 static int selfTest( void )
70  {
71  const CAPABILITY_INFO *capabilityInfo = getRC5Capability();
72  BYTE keyData[ RC5_EXPANDED_KEYSIZE + 8 ];
73  int i, status;
74 
75  for( i = 0; i < sizeof( testRC5 ) / sizeof( struct RC5_TEST ); i++ )
76  {
77  status = testCipher( capabilityInfo, keyData, testRC5[ i ].key,
78  16, testRC5[ i ].plaintext,
79  testRC5[ i ].ciphertext );
80  if( cryptStatusError( status ) )
81  return( status );
82  }
83 
84  return( CRYPT_OK );
85  }
86 #else
87  #define selfTest NULL
88 #endif /* !CONFIG_NO_SELFTEST */
89 
90 /****************************************************************************
91 * *
92 * Control Routines *
93 * *
94 ****************************************************************************/
95 
96 /* Return context subtype-specific information */
97 
99 static int getInfo( IN_ENUM( CAPABILITY_INFO ) const CAPABILITY_INFO_TYPE type,
101  OUT void *data,
102  IN_INT_Z const int length )
103  {
104  assert( contextInfoPtr == NULL || \
105  isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
106  assert( ( length == 0 && isWritePtr( data, sizeof( int ) ) ) || \
107  ( length > 0 && isWritePtr( data, length ) ) );
108 
110 
111  if( type == CAPABILITY_INFO_STATESIZE )
112  {
113  int *valuePtr = ( int * ) data;
114 
115  *valuePtr = RC5_EXPANDED_KEYSIZE;
116 
117  return( CRYPT_OK );
118  }
119 
120  return( getDefaultInfo( type, contextInfoPtr, data, length ) );
121  }
122 
123 /****************************************************************************
124 * *
125 * RC5 En/Decryption Routines *
126 * *
127 ****************************************************************************/
128 
129 /* Encrypt/decrypt data in ECB mode */
130 
131 static int encryptECB( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
132  int noBytes )
133  {
134  CONV_INFO *convInfo = contextInfoPtr->ctxConv;
135  RC5_KEY *rc5Key = ( RC5_KEY * ) convInfo->key;
136  int blockCount = noBytes / RC5_BLOCKSIZE;
137 
138  while( blockCount-- > 0 )
139  {
140  /* Encrypt a block of data */
141  RC5_32_ecb_encrypt( buffer, buffer, rc5Key, RC5_ENCRYPT );
142 
143  /* Move on to next block of data */
144  buffer += RC5_BLOCKSIZE;
145  }
146 
147  return( CRYPT_OK );
148  }
149 
150 static int decryptECB( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
151  int noBytes )
152  {
153  CONV_INFO *convInfo = contextInfoPtr->ctxConv;
154  RC5_KEY *rc5Key = ( RC5_KEY * ) convInfo->key;
155  int blockCount = noBytes / RC5_BLOCKSIZE;
156 
157  while( blockCount-- > 0 )
158  {
159  /* Decrypt a block of data */
160  RC5_32_ecb_encrypt( buffer, buffer, rc5Key, RC5_DECRYPT );
161 
162  /* Move on to next block of data */
163  buffer += RC5_BLOCKSIZE;
164  }
165 
166  return( CRYPT_OK );
167  }
168 
169 /* Encrypt/decrypt data in CBC mode */
170 
171 static int encryptCBC( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
172  int noBytes )
173  {
174  CONV_INFO *convInfo = contextInfoPtr->ctxConv;
175 
176  RC5_32_cbc_encrypt( buffer, buffer, noBytes, convInfo->key,
177  convInfo->currentIV, RC5_ENCRYPT );
178 
179  return( CRYPT_OK );
180  }
181 
182 static int decryptCBC( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
183  int noBytes )
184  {
185  CONV_INFO *convInfo = contextInfoPtr->ctxConv;
186 
187  RC5_32_cbc_encrypt( buffer, buffer, noBytes, convInfo->key,
188  convInfo->currentIV, RC5_DECRYPT );
189 
190  return( CRYPT_OK );
191  }
192 
193 /* Encrypt/decrypt data in CFB mode */
194 
195 static int encryptCFB( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
196  int noBytes )
197  {
198  CONV_INFO *convInfo = contextInfoPtr->ctxConv;
199  RC5_KEY *rc5Key = ( RC5_KEY * ) convInfo->key;
200  int i, ivCount = convInfo->ivCount;
201 
202  /* If there's any encrypted material left in the IV, use it now */
203  if( ivCount > 0 )
204  {
205  int bytesToUse;
206 
207  /* Find out how much material left in the encrypted IV we can use */
208  bytesToUse = RC5_BLOCKSIZE - ivCount;
209  if( noBytes < bytesToUse )
210  bytesToUse = noBytes;
211 
212  /* Encrypt the data */
213  for( i = 0; i < bytesToUse; i++ )
214  buffer[ i ] ^= convInfo->currentIV[ i + ivCount ];
215  memcpy( convInfo->currentIV + ivCount, buffer, bytesToUse );
216 
217  /* Adjust the byte count and buffer position */
218  noBytes -= bytesToUse;
219  buffer += bytesToUse;
220  ivCount += bytesToUse;
221  }
222 
223  while( noBytes > 0 )
224  {
225  ivCount = ( noBytes > RC5_BLOCKSIZE ) ? RC5_BLOCKSIZE : noBytes;
226 
227  /* Encrypt the IV */
228  RC5_32_ecb_encrypt( convInfo->currentIV, convInfo->currentIV, rc5Key,
229  RC5_ENCRYPT );
230 
231  /* XOR the buffer contents with the encrypted IV */
232  for( i = 0; i < ivCount; i++ )
233  buffer[ i ] ^= convInfo->currentIV[ i ];
234 
235  /* Shift the ciphertext into the IV */
236  memcpy( convInfo->currentIV, buffer, ivCount );
237 
238  /* Move on to next block of data */
239  noBytes -= ivCount;
240  buffer += ivCount;
241  }
242 
243  /* Remember how much of the IV is still available for use */
244  convInfo->ivCount = ( ivCount % RC5_BLOCKSIZE );
245 
246  return( CRYPT_OK );
247  }
248 
249 /* Decrypt data in CFB mode. Note that the transformation can be made
250  faster (but less clear) with temp = buffer, buffer ^= iv, iv = temp
251  all in one loop */
252 
253 static int decryptCFB( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
254  int noBytes )
255  {
256  CONV_INFO *convInfo = contextInfoPtr->ctxConv;
257  RC5_KEY *rc5Key = ( RC5_KEY * ) convInfo->key;
258  BYTE temp[ RC5_BLOCKSIZE + 8 ];
259  int i, ivCount = convInfo->ivCount;
260 
261  /* If there's any encrypted material left in the IV, use it now */
262  if( ivCount > 0 )
263  {
264  int bytesToUse;
265 
266  /* Find out how much material left in the encrypted IV we can use */
267  bytesToUse = RC5_BLOCKSIZE - ivCount;
268  if( noBytes < bytesToUse )
269  bytesToUse = noBytes;
270 
271  /* Decrypt the data */
272  memcpy( temp, buffer, bytesToUse );
273  for( i = 0; i < bytesToUse; i++ )
274  buffer[ i ] ^= convInfo->currentIV[ i + ivCount ];
275  memcpy( convInfo->currentIV + ivCount, temp, bytesToUse );
276 
277  /* Adjust the byte count and buffer position */
278  noBytes -= bytesToUse;
279  buffer += bytesToUse;
280  ivCount += bytesToUse;
281  }
282 
283  while( noBytes > 0 )
284  {
285  ivCount = ( noBytes > RC5_BLOCKSIZE ) ? RC5_BLOCKSIZE : noBytes;
286 
287  /* Encrypt the IV */
288  RC5_32_ecb_encrypt( convInfo->currentIV, convInfo->currentIV, rc5Key,
289  RC5_ENCRYPT );
290 
291  /* Save the ciphertext */
292  memcpy( temp, buffer, ivCount );
293 
294  /* XOR the buffer contents with the encrypted IV */
295  for( i = 0; i < ivCount; i++ )
296  buffer[ i ] ^= convInfo->currentIV[ i ];
297 
298  /* Shift the ciphertext into the IV */
299  memcpy( convInfo->currentIV, temp, ivCount );
300 
301  /* Move on to next block of data */
302  noBytes -= ivCount;
303  buffer += ivCount;
304  }
305 
306  /* Remember how much of the IV is still available for use */
307  convInfo->ivCount = ( ivCount % RC5_BLOCKSIZE );
308 
309  /* Clear the temporary buffer */
310  zeroise( temp, RC5_BLOCKSIZE );
311 
312  return( CRYPT_OK );
313  }
314 
315 /* Encrypt/decrypt data in OFB mode */
316 
317 static int encryptOFB( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
318  int noBytes )
319  {
320  CONV_INFO *convInfo = contextInfoPtr->ctxConv;
321  RC5_KEY *rc5Key = ( RC5_KEY * ) convInfo->key;
322  int i, ivCount = convInfo->ivCount;
323 
324  /* If there's any encrypted material left in the IV, use it now */
325  if( ivCount > 0 )
326  {
327  int bytesToUse;
328 
329  /* Find out how much material left in the encrypted IV we can use */
330  bytesToUse = RC5_BLOCKSIZE - ivCount;
331  if( noBytes < bytesToUse )
332  bytesToUse = noBytes;
333 
334  /* Encrypt the data */
335  for( i = 0; i < bytesToUse; i++ )
336  buffer[ i ] ^= convInfo->currentIV[ i + ivCount ];
337 
338  /* Adjust the byte count and buffer position */
339  noBytes -= bytesToUse;
340  buffer += bytesToUse;
341  ivCount += bytesToUse;
342  }
343 
344  while( noBytes > 0 )
345  {
346  ivCount = ( noBytes > RC5_BLOCKSIZE ) ? RC5_BLOCKSIZE : noBytes;
347 
348  /* Encrypt the IV */
349  RC5_32_ecb_encrypt( convInfo->currentIV, convInfo->currentIV, rc5Key,
350  RC5_ENCRYPT );
351 
352  /* XOR the buffer contents with the encrypted IV */
353  for( i = 0; i < ivCount; i++ )
354  buffer[ i ] ^= convInfo->currentIV[ i ];
355 
356  /* Move on to next block of data */
357  noBytes -= ivCount;
358  buffer += ivCount;
359  }
360 
361  /* Remember how much of the IV is still available for use */
362  convInfo->ivCount = ( ivCount % RC5_BLOCKSIZE );
363 
364  return( CRYPT_OK );
365  }
366 
367 /* Decrypt data in OFB mode */
368 
369 static int decryptOFB( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
370  int noBytes )
371  {
372  CONV_INFO *convInfo = contextInfoPtr->ctxConv;
373  RC5_KEY *rc5Key = ( RC5_KEY * ) convInfo->key;
374  int i, ivCount = convInfo->ivCount;
375 
376  /* If there's any encrypted material left in the IV, use it now */
377  if( ivCount > 0 )
378  {
379  int bytesToUse;
380 
381  /* Find out how much material left in the encrypted IV we can use */
382  bytesToUse = RC5_BLOCKSIZE - ivCount;
383  if( noBytes < bytesToUse )
384  bytesToUse = noBytes;
385 
386  /* Decrypt the data */
387  for( i = 0; i < bytesToUse; i++ )
388  buffer[ i ] ^= convInfo->currentIV[ i + ivCount ];
389 
390  /* Adjust the byte count and buffer position */
391  noBytes -= bytesToUse;
392  buffer += bytesToUse;
393  ivCount += bytesToUse;
394  }
395 
396  while( noBytes > 0 )
397  {
398  ivCount = ( noBytes > RC5_BLOCKSIZE ) ? RC5_BLOCKSIZE : noBytes;
399 
400  /* Encrypt the IV */
401  RC5_32_ecb_encrypt( convInfo->currentIV, convInfo->currentIV, rc5Key,
402  RC5_ENCRYPT );
403 
404  /* XOR the buffer contents with the encrypted IV */
405  for( i = 0; i < ivCount; i++ )
406  buffer[ i ] ^= convInfo->currentIV[ i ];
407 
408  /* Move on to next block of data */
409  noBytes -= ivCount;
410  buffer += ivCount;
411  }
412 
413  /* Remember how much of the IV is still available for use */
414  convInfo->ivCount = ( ivCount % RC5_BLOCKSIZE );
415 
416  return( CRYPT_OK );
417  }
418 
419 /****************************************************************************
420 * *
421 * RC5 Key Management Routines *
422 * *
423 ****************************************************************************/
424 
425 /* Key schedule a RC5 key */
426 
427 static int initKey( CONTEXT_INFO *contextInfoPtr, const void *key,
428  const int keyLength )
429  {
430  CONV_INFO *convInfo = contextInfoPtr->ctxConv;
431  RC5_KEY *rc5Key = ( RC5_KEY * ) convInfo->key;
432 
433  /* Copy the key to internal storage */
434  if( convInfo->userKey != key )
435  memcpy( convInfo->userKey, key, keyLength );
436  convInfo->userKeyLength = keyLength;
437 
438  RC5_32_set_key( rc5Key, keyLength, key, RC5_DEFAULT_ROUNDS );
439  return( CRYPT_OK );
440  }
441 
442 /****************************************************************************
443 * *
444 * Capability Access Routines *
445 * *
446 ****************************************************************************/
447 
448 static const CAPABILITY_INFO FAR_BSS capabilityInfo = {
449  CRYPT_ALGO_RC5, bitsToBytes( 64 ), "RC5", 3,
450  MIN_KEYSIZE, bitsToBytes( 128 ), bitsToBytes( 832 ),
451  selfTest, getInfo, NULL, initGenericParams, initKey, NULL,
452  encryptECB, decryptECB, encryptCBC, decryptCBC,
453  encryptCFB, decryptCFB, encryptOFB, decryptOFB
454  };
455 
456 const CAPABILITY_INFO *getRC5Capability( void )
457  {
458  return( &capabilityInfo );
459  }
460 
461 #endif /* USE_RC5 */