cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
ctx_idea.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib IDEA Encryption Routines *
4 * Copyright Peter Gutmann 1992-2005 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "context.h"
11  #include "idea.h"
12 #else
13  #include "crypt.h"
14  #include "context/context.h"
15  #include "crypt/idea.h"
16 #endif /* Compiler-specific includes */
17 
18 #ifdef USE_IDEA
19 
20 /* Defines to map from EAY to native naming */
21 
22 #define IDEA_BLOCKSIZE IDEA_BLOCK
23 
24 /* A structure to hold the two expanded IDEA keys */
25 
26 typedef struct {
27  IDEA_KEY_SCHEDULE eKey, dKey;
28  } IDEA_KEY;
29 
30 /* The size of the expanded IDEA keys */
31 
32 #define IDEA_EXPANDED_KEYSIZE sizeof( IDEA_KEY )
33 
34 /****************************************************************************
35 * *
36 * IDEA Self-test Routines *
37 * *
38 ****************************************************************************/
39 
40 #ifndef CONFIG_NO_SELFTEST
41 
42 /* IDEA test vectors, from the ETH reference implementation */
43 
44 /* The data structure for the ( key, plaintext, ciphertext ) triplets */
45 
46 typedef struct {
47  const BYTE key[ IDEA_KEY_LENGTH ];
48  const BYTE plaintext[ IDEA_BLOCKSIZE ];
49  const BYTE ciphertext[ IDEA_BLOCKSIZE ];
50  } IDEA_TEST;
51 
52 static const IDEA_TEST FAR_BSS testIdea[] = {
53  { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
54  0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 },
55  { 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03 },
56  { 0x11, 0xFB, 0xED, 0x2B, 0x01, 0x98, 0x6D, 0xE5 } },
57  { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
58  0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 },
59  { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 },
60  { 0x54, 0x0E, 0x5F, 0xEA, 0x18, 0xC2, 0xF8, 0xB1 } },
61  { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
62  0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 },
63  { 0x00, 0x19, 0x32, 0x4B, 0x64, 0x7D, 0x96, 0xAF },
64  { 0x9F, 0x0A, 0x0A, 0xB6, 0xE1, 0x0C, 0xED, 0x78 } },
65  { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
66  0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 },
67  { 0xF5, 0x20, 0x2D, 0x5B, 0x9C, 0x67, 0x1B, 0x08 },
68  { 0xCF, 0x18, 0xFD, 0x73, 0x55, 0xE2, 0xC5, 0xC5 } },
69  { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
70  0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 },
71  { 0xFA, 0xE6, 0xD2, 0xBE, 0xAA, 0x96, 0x82, 0x6E },
72  { 0x85, 0xDF, 0x52, 0x00, 0x56, 0x08, 0x19, 0x3D } },
73  { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
74  0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 },
75  { 0x0A, 0x14, 0x1E, 0x28, 0x32, 0x3C, 0x46, 0x50 },
76  { 0x2F, 0x7D, 0xE7, 0x50, 0x21, 0x2F, 0xB7, 0x34 } },
77  { { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
78  0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 },
79  { 0x05, 0x0A, 0x0F, 0x14, 0x19, 0x1E, 0x23, 0x28 },
80  { 0x7B, 0x73, 0x14, 0x92, 0x5D, 0xE5, 0x9C, 0x09 } },
81  { { 0x00, 0x05, 0x00, 0x0A, 0x00, 0x0F, 0x00, 0x14,
82  0x00, 0x19, 0x00, 0x1E, 0x00, 0x23, 0x00, 0x28 },
83  { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 },
84  { 0x3E, 0xC0, 0x47, 0x80, 0xBE, 0xFF, 0x6E, 0x20 } },
85  { { 0x3A, 0x98, 0x4E, 0x20, 0x00, 0x19, 0x5D, 0xB3,
86  0x2E, 0xE5, 0x01, 0xC8, 0xC4, 0x7C, 0xEA, 0x60 },
87  { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 },
88  { 0x97, 0xBC, 0xD8, 0x20, 0x07, 0x80, 0xDA, 0x86 } },
89  { { 0x00, 0x64, 0x00, 0xC8, 0x01, 0x2C, 0x01, 0x90,
90  0x01, 0xF4, 0x02, 0x58, 0x02, 0xBC, 0x03, 0x20 },
91  { 0x05, 0x32, 0x0A, 0x64, 0x14, 0xC8, 0x19, 0xFA },
92  { 0x65, 0xBE, 0x87, 0xE7, 0xA2, 0x53, 0x8A, 0xED } },
93  { { 0x9D, 0x40, 0x75, 0xC1, 0x03, 0xBC, 0x32, 0x2A,
94  0xFB, 0x03, 0xE7, 0xBE, 0x6A, 0xB3, 0x00, 0x06 },
95  { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 },
96  { 0xF5, 0xDB, 0x1A, 0xC4, 0x5E, 0x5E, 0xF9, 0xF9 } }
97  };
98 
99 /* Test the IDEA code against the test vectors from the ETH reference
100  implementation */
101 
102 static int selfTest( void )
103  {
104  const CAPABILITY_INFO *capabilityInfo = getIDEACapability();
105  BYTE keyData[ IDEA_EXPANDED_KEYSIZE + 8 ];
106  int i, status;
107 
108  for( i = 0; i < sizeof( testIdea ) / sizeof( IDEA_TEST ); i++ )
109  {
110  status = testCipher( capabilityInfo, keyData, testIdea[ i ].key,
111  16, testIdea[ i ].plaintext,
112  testIdea[ i ].ciphertext );
113  if( cryptStatusError( status ) )
114  return( status );
115  }
116 
117  return( CRYPT_OK );
118  }
119 #else
120  #define selfTest NULL
121 #endif /* !CONFIG_NO_SELFTEST */
122 
123 /****************************************************************************
124 * *
125 * Control Routines *
126 * *
127 ****************************************************************************/
128 
129 /* Return context subtype-specific information */
130 
132 static int getInfo( IN_ENUM( CAPABILITY_INFO ) const CAPABILITY_INFO_TYPE type,
134  OUT void *data,
135  IN_INT_Z const int length )
136  {
137  assert( contextInfoPtr == NULL || \
138  isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) );
139  assert( ( length == 0 && isWritePtr( data, sizeof( int ) ) ) || \
140  ( length > 0 && isWritePtr( data, length ) ) );
141 
143 
144  if( type == CAPABILITY_INFO_STATESIZE )
145  {
146  int *valuePtr = ( int * ) data;
147 
148  *valuePtr = IDEA_EXPANDED_KEYSIZE;
149 
150  return( CRYPT_OK );
151  }
152 
153  return( getDefaultInfo( type, contextInfoPtr, data, length ) );
154  }
155 
156 /****************************************************************************
157 * *
158 * IDEA En/Decryption Routines *
159 * *
160 ****************************************************************************/
161 
162 /* Encrypt/decrypt data in ECB mode */
163 
164 static int encryptECB( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
165  int noBytes )
166  {
167  CONV_INFO *convInfo = contextInfoPtr->ctxConv;
168  IDEA_KEY *ideaKey = ( IDEA_KEY * ) convInfo->key;
169  int blockCount = noBytes / IDEA_BLOCKSIZE;
170 
171  while( blockCount-- > 0 )
172  {
173  /* Encrypt a block of data */
174  idea_ecb_encrypt( buffer, buffer, &ideaKey->eKey );
175 
176  /* Move on to next block of data */
177  buffer += IDEA_BLOCKSIZE;
178  }
179 
180  return( CRYPT_OK );
181  }
182 
183 static int decryptECB( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
184  int noBytes )
185  {
186  CONV_INFO *convInfo = contextInfoPtr->ctxConv;
187  IDEA_KEY *ideaKey = ( IDEA_KEY * ) convInfo->key;
188  int blockCount = noBytes / IDEA_BLOCKSIZE;
189 
190  while( blockCount-- > 0 )
191  {
192  /* Decrypt a block of data */
193  idea_ecb_encrypt( buffer, buffer, &ideaKey->dKey );
194 
195  /* Move on to next block of data */
196  buffer += IDEA_BLOCKSIZE;
197  }
198 
199  return( CRYPT_OK );
200  }
201 
202 /* Encrypt/decrypt data in CBC mode */
203 
204 static int encryptCBC( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
205  int noBytes )
206  {
207  CONV_INFO *convInfo = contextInfoPtr->ctxConv;
208 
209  idea_cbc_encrypt( buffer, buffer, noBytes,
210  &( ( IDEA_KEY * ) convInfo->key )->eKey,
211  convInfo->currentIV, IDEA_ENCRYPT );
212 
213  return( CRYPT_OK );
214  }
215 
216 static int decryptCBC( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
217  int noBytes )
218  {
219  CONV_INFO *convInfo = contextInfoPtr->ctxConv;
220 
221  idea_cbc_encrypt( buffer, buffer, noBytes,
222  &( ( IDEA_KEY * ) convInfo->key )->dKey,
223  convInfo->currentIV, IDEA_DECRYPT );
224 
225  return( CRYPT_OK );
226  }
227 
228 /* Encrypt/decrypt data in CFB mode */
229 
230 static int encryptCFB( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
231  int noBytes )
232  {
233  CONV_INFO *convInfo = contextInfoPtr->ctxConv;
234  IDEA_KEY *ideaKey = ( IDEA_KEY * ) convInfo->key;
235  int i, ivCount = convInfo->ivCount;
236 
237  /* If there's any encrypted material left in the IV, use it now */
238  if( ivCount > 0 )
239  {
240  int bytesToUse;
241 
242  /* Find out how much material left in the encrypted IV we can use */
243  bytesToUse = IDEA_BLOCKSIZE - ivCount;
244  if( noBytes < bytesToUse )
245  bytesToUse = noBytes;
246 
247  /* Encrypt the data */
248  for( i = 0; i < bytesToUse; i++ )
249  buffer[ i ] ^= convInfo->currentIV[ i + ivCount ];
250  memcpy( convInfo->currentIV + ivCount, buffer, bytesToUse );
251 
252  /* Adjust the byte count and buffer position */
253  noBytes -= bytesToUse;
254  buffer += bytesToUse;
255  ivCount += bytesToUse;
256  }
257 
258  while( noBytes > 0 )
259  {
260  ivCount = ( noBytes > IDEA_BLOCKSIZE ) ? IDEA_BLOCKSIZE : noBytes;
261 
262  /* Encrypt the IV */
263  idea_ecb_encrypt( convInfo->currentIV, convInfo->currentIV,
264  &ideaKey->eKey );
265 
266  /* XOR the buffer contents with the encrypted IV */
267  for( i = 0; i < ivCount; i++ )
268  buffer[ i ] ^= convInfo->currentIV[ i ];
269 
270  /* Shift the ciphertext into the IV */
271  memcpy( convInfo->currentIV, buffer, ivCount );
272 
273  /* Move on to next block of data */
274  noBytes -= ivCount;
275  buffer += ivCount;
276  }
277 
278  /* Remember how much of the IV is still available for use */
279  convInfo->ivCount = ( ivCount % IDEA_BLOCKSIZE );
280 
281  return( CRYPT_OK );
282  }
283 
284 /* Decrypt data in CFB mode. Note that the transformation can be made
285  faster (but less clear) with temp = buffer, buffer ^= iv, iv = temp
286  all in one loop */
287 
288 static int decryptCFB( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
289  int noBytes )
290  {
291  CONV_INFO *convInfo = contextInfoPtr->ctxConv;
292  IDEA_KEY *ideaKey = ( IDEA_KEY * ) convInfo->key;
293  BYTE temp[ IDEA_BLOCKSIZE + 8 ];
294  int i, ivCount = convInfo->ivCount;
295 
296  /* If there's any encrypted material left in the IV, use it now */
297  if( ivCount > 0 )
298  {
299  int bytesToUse;
300 
301  /* Find out how much material left in the encrypted IV we can use */
302  bytesToUse = IDEA_BLOCKSIZE - ivCount;
303  if( noBytes < bytesToUse )
304  bytesToUse = noBytes;
305 
306  /* Decrypt the data */
307  memcpy( temp, buffer, bytesToUse );
308  for( i = 0; i < bytesToUse; i++ )
309  buffer[ i ] ^= convInfo->currentIV[ i + ivCount ];
310  memcpy( convInfo->currentIV + ivCount, temp, bytesToUse );
311 
312  /* Adjust the byte count and buffer position */
313  noBytes -= bytesToUse;
314  buffer += bytesToUse;
315  ivCount += bytesToUse;
316  }
317 
318  while( noBytes > 0 )
319  {
320  ivCount = ( noBytes > IDEA_BLOCKSIZE ) ? IDEA_BLOCKSIZE : noBytes;
321 
322  /* Encrypt the IV */
323  idea_ecb_encrypt( convInfo->currentIV, convInfo->currentIV,
324  &ideaKey->eKey );
325 
326  /* Save the ciphertext */
327  memcpy( temp, buffer, ivCount );
328 
329  /* XOR the buffer contents with the encrypted IV */
330  for( i = 0; i < ivCount; i++ )
331  buffer[ i ] ^= convInfo->currentIV[ i ];
332 
333  /* Shift the ciphertext into the IV */
334  memcpy( convInfo->currentIV, temp, ivCount );
335 
336  /* Move on to next block of data */
337  noBytes -= ivCount;
338  buffer += ivCount;
339  }
340 
341  /* Remember how much of the IV is still available for use */
342  convInfo->ivCount = ( ivCount % IDEA_BLOCKSIZE );
343 
344  /* Clear the temporary buffer */
345  zeroise( temp, IDEA_BLOCKSIZE );
346 
347  return( CRYPT_OK );
348  }
349 
350 /* Encrypt/decrypt data in OFB mode */
351 
352 static int encryptOFB( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
353  int noBytes )
354  {
355  CONV_INFO *convInfo = contextInfoPtr->ctxConv;
356  IDEA_KEY *ideaKey = ( IDEA_KEY * ) convInfo->key;
357  int i, ivCount = convInfo->ivCount;
358 
359  /* If there's any encrypted material left in the IV, use it now */
360  if( ivCount > 0 )
361  {
362  int bytesToUse;
363 
364  /* Find out how much material left in the encrypted IV we can use */
365  bytesToUse = IDEA_BLOCKSIZE - ivCount;
366  if( noBytes < bytesToUse )
367  bytesToUse = noBytes;
368 
369  /* Encrypt the data */
370  for( i = 0; i < bytesToUse; i++ )
371  buffer[ i ] ^= convInfo->currentIV[ i + ivCount ];
372 
373  /* Adjust the byte count and buffer position */
374  noBytes -= bytesToUse;
375  buffer += bytesToUse;
376  ivCount += bytesToUse;
377  }
378 
379  while( noBytes > 0 )
380  {
381  ivCount = ( noBytes > IDEA_BLOCKSIZE ) ? IDEA_BLOCKSIZE : noBytes;
382 
383  /* Encrypt the IV */
384  idea_ecb_encrypt( convInfo->currentIV, convInfo->currentIV,
385  &ideaKey->eKey );
386 
387  /* XOR the buffer contents with the encrypted IV */
388  for( i = 0; i < ivCount; i++ )
389  buffer[ i ] ^= convInfo->currentIV[ i ];
390 
391  /* Move on to next block of data */
392  noBytes -= ivCount;
393  buffer += ivCount;
394  }
395 
396  /* Remember how much of the IV is still available for use */
397  convInfo->ivCount = ( ivCount % IDEA_BLOCKSIZE );
398 
399  return( CRYPT_OK );
400  }
401 
402 /* Decrypt data in OFB mode */
403 
404 static int decryptOFB( CONTEXT_INFO *contextInfoPtr, BYTE *buffer,
405  int noBytes )
406  {
407  CONV_INFO *convInfo = contextInfoPtr->ctxConv;
408  IDEA_KEY *ideaKey = ( IDEA_KEY * ) convInfo->key;
409  int i, ivCount = convInfo->ivCount;
410 
411  /* If there's any encrypted material left in the IV, use it now */
412  if( ivCount > 0 )
413  {
414  int bytesToUse;
415 
416  /* Find out how much material left in the encrypted IV we can use */
417  bytesToUse = IDEA_BLOCKSIZE - ivCount;
418  if( noBytes < bytesToUse )
419  bytesToUse = noBytes;
420 
421  /* Decrypt the data */
422  for( i = 0; i < bytesToUse; i++ )
423  buffer[ i ] ^= convInfo->currentIV[ i + ivCount ];
424 
425  /* Adjust the byte count and buffer position */
426  noBytes -= bytesToUse;
427  buffer += bytesToUse;
428  ivCount += bytesToUse;
429  }
430 
431  while( noBytes > 0 )
432  {
433  ivCount = ( noBytes > IDEA_BLOCKSIZE ) ? IDEA_BLOCKSIZE : noBytes;
434 
435  /* Encrypt the IV */
436  idea_ecb_encrypt( convInfo->currentIV, convInfo->currentIV,
437  &ideaKey->eKey );
438 
439  /* XOR the buffer contents with the encrypted IV */
440  for( i = 0; i < ivCount; i++ )
441  buffer[ i ] ^= convInfo->currentIV[ i ];
442 
443  /* Move on to next block of data */
444  noBytes -= ivCount;
445  buffer += ivCount;
446  }
447 
448  /* Remember how much of the IV is still available for use */
449  convInfo->ivCount = ( ivCount % IDEA_BLOCKSIZE );
450 
451  return( CRYPT_OK );
452  }
453 
454 /****************************************************************************
455 * *
456 * IDEA Key Management Routines *
457 * *
458 ****************************************************************************/
459 
460 /* Key schedule an IDEA key */
461 
462 static int initKey( CONTEXT_INFO *contextInfoPtr, const void *key,
463  const int keyLength )
464  {
465  CONV_INFO *convInfo = contextInfoPtr->ctxConv;
466  IDEA_KEY *ideaKey = ( IDEA_KEY * ) convInfo->key;
467 
468  /* Copy the key to internal storage */
469  if( convInfo->userKey != key )
470  memcpy( convInfo->userKey, key, keyLength );
471  convInfo->userKeyLength = keyLength;
472 
473  /* Generate the expanded IDEA encryption and decryption keys */
474  idea_set_encrypt_key( key, &ideaKey->eKey );
475  idea_set_decrypt_key( &ideaKey->eKey, &ideaKey->dKey );
476 
477  return( CRYPT_OK );
478  }
479 
480 /****************************************************************************
481 * *
482 * Capability Access Routines *
483 * *
484 ****************************************************************************/
485 
486 static const CAPABILITY_INFO FAR_BSS capabilityInfo = {
487  CRYPT_ALGO_IDEA, bitsToBytes( 64 ), "IDEA", 4,
488  MIN_KEYSIZE, bitsToBytes( 128 ), bitsToBytes( 128 ),
489  selfTest, getInfo, NULL, initGenericParams, initKey, NULL,
490  encryptECB, decryptECB, encryptCBC, decryptCBC,
491  encryptCFB, decryptCFB, encryptOFB, decryptOFB
492  };
493 
494 const CAPABILITY_INFO *getIDEACapability( void )
495  {
496  return( &capabilityInfo );
497  }
498 
499 #endif /* USE_IDEA */