cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
pgp_misc.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * PGP Support Routines *
4 * Copyright Peter Gutmann 1992-2007 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "misc_rw.h"
11  #include "pgp.h"
12 #else
13  #include "crypt.h"
14  #include "enc_dec/misc_rw.h"
15  #include "misc/pgp.h"
16 #endif /* Compiler-specific includes */
17 
18 #if defined( USE_PGP ) || defined( USE_PGPKEYS )
19 
20 /****************************************************************************
21 * *
22 * PGP <-> Cryptlib Algorithm Conversion *
23 * *
24 ****************************************************************************/
25 
26 /* Convert algorithm IDs from cryptlib to PGP and back */
27 
28 typedef struct {
29  const int pgpAlgo;
30  const PGP_ALGOCLASS_TYPE pgpAlgoClass;
31  const CRYPT_ALGO_TYPE cryptlibAlgo;
32  } PGP_ALGOMAP_INFO;
33 static const PGP_ALGOMAP_INFO FAR_BSS pgpAlgoMap[] = {
34  /* Encryption algos */
36 #ifdef USE_BLOWFISH
38 #endif /* USE_BLOWFISH */
39 #ifdef USE_IDEA
41 #endif /* USE_IDEA */
45 
46  /* Password-based encryption algos */
48 #ifdef USE_BLOWFISH
50 #endif /* USE_BLOWFISH */
51 #ifdef USE_IDEA
53 #endif /* USE_IDEA */
57 
58  /* PKC encryption algos */
61 #ifdef USE_ELGAMAL
63 #endif /* USE_ELGAMAL */
64 
65  /* PKC sig algos */
69 
70  /* Hash algos */
71 #ifdef USE_MD5
73 #endif /* USE_MD5 */
75 #ifdef USE_RIPEMD160
77 #endif /* USE_RIPEMD160 */
78 #ifdef USE_SHA2
80 #endif /* USE_SHA2 */
81 
84  };
85 
87 int pgpToCryptlibAlgo( IN_RANGE( PGP_ALGO_NONE, 0xFF ) const int pgpAlgo,
88  IN_ENUM( PGP_ALGOCLASS ) \
89  const PGP_ALGOCLASS_TYPE pgpAlgoClass,
91  {
92  int i;
93 
94  assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
95 
96  REQUIRES( pgpAlgo >= 0 && pgpAlgo <= 0xFF );
97  REQUIRES( pgpAlgoClass > PGP_ALGOCLASS_NONE && \
98  pgpAlgoClass < PGP_ALGOCLASS_LAST );
99 
100  /* Clear return value */
101  *cryptAlgo = CRYPT_ALGO_NONE;
102 
103  for( i = 0;
104  ( pgpAlgoMap[ i ].pgpAlgo != pgpAlgo || \
105  pgpAlgoMap[ i ].pgpAlgoClass != pgpAlgoClass ) && \
106  pgpAlgoMap[ i ].pgpAlgo != PGP_ALGO_NONE && \
107  i < FAILSAFE_ARRAYSIZE( pgpAlgoMap, PGP_ALGOMAP_INFO );
108  i++ );
109  ENSURES( i < FAILSAFE_ARRAYSIZE( pgpAlgoMap, PGP_ALGOMAP_INFO ) );
110  if( pgpAlgoMap[ i ].cryptlibAlgo == PGP_ALGO_NONE )
111  return( CRYPT_ERROR_NOTAVAIL );
112  *cryptAlgo = pgpAlgoMap[ i ].cryptlibAlgo;
113 
114  return( CRYPT_OK );
115  }
116 
118 int cryptlibToPgpAlgo( IN_ALGO const CRYPT_ALGO_TYPE cryptlibAlgo,
120  int *pgpAlgo )
121  {
122  int i;
123 
124  assert( isWritePtr( pgpAlgo, sizeof( int ) ) );
125 
126  REQUIRES( cryptlibAlgo > CRYPT_ALGO_NONE && \
127  cryptlibAlgo < CRYPT_ALGO_LAST );
128 
129  /* Clear return value */
130  *pgpAlgo = PGP_ALGO_NONE;
131 
132  for( i = 0;
133  pgpAlgoMap[ i ].cryptlibAlgo != cryptlibAlgo && \
134  pgpAlgoMap[ i ].cryptlibAlgo != CRYPT_ALGO_NONE && \
135  i < FAILSAFE_ARRAYSIZE( pgpAlgoMap, PGP_ALGOMAP_INFO );
136  i++ );
137  ENSURES( i < FAILSAFE_ARRAYSIZE( pgpAlgoMap, PGP_ALGOMAP_INFO ) );
138  if( pgpAlgoMap[ i ].cryptlibAlgo == CRYPT_ALGO_NONE )
139  return( CRYPT_ERROR_NOTAVAIL );
140  *pgpAlgo = pgpAlgoMap[ i ].pgpAlgo;
141 
142  return( CRYPT_OK );
143  }
144 
145 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
146 int readPgpAlgo( INOUT STREAM *stream,
147  OUT_ALGO_Z CRYPT_ALGO_TYPE *cryptAlgo,
148  IN_ENUM( PGP_ALGOCLASS ) \
149  const PGP_ALGOCLASS_TYPE pgpAlgoClass )
150  {
152  int value, status;
153 
154  assert( isWritePtr( stream, sizeof( STREAM ) ) );
155  assert( isWritePtr( cryptAlgo, sizeof( CRYPT_ALGO_TYPE ) ) );
156 
157  REQUIRES( pgpAlgoClass > PGP_ALGOCLASS_NONE && \
158  pgpAlgoClass < PGP_ALGOCLASS_LAST );
159 
160  /* Clear return value */
161  *cryptAlgo = CRYPT_ALGO_NONE;
162 
163  value = sgetc( stream );
164  if( cryptStatusError( value ) )
165  return( value );
166  status = pgpToCryptlibAlgo( value, pgpAlgoClass, &algo );
167  if( cryptStatusError( status ) )
168  return( status );
169  *cryptAlgo = algo;
170 
171  return( CRYPT_OK );
172  }
173 
174 /****************************************************************************
175 * *
176 * Misc. PGP-related Routines *
177 * *
178 ****************************************************************************/
179 
180 /* Create an encryption key from a password */
181 
183 int pgpPasswordToKey( IN_HANDLE const CRYPT_CONTEXT iCryptContext,
185  IN_BUFFER( passwordLength ) const char *password,
186  IN_LENGTH_SHORT const int passwordLength,
188  IN_BUFFER_OPT( saltSize ) const BYTE *salt,
189  IN_RANGE( 0, CRYPT_MAX_HASHSIZE ) const int saltSize,
190  IN_INT const int iterations )
191  {
193  BYTE hashedKey[ CRYPT_MAX_KEYSIZE + 8 ];
194  int algorithm, keySize = DUMMY_INIT, status; /* int vs.enum */
195 
196  assert( isReadPtr( password, passwordLength ) );
197  assert( ( salt == NULL && saltSize == 0 ) || \
198  isReadPtr( salt, saltSize ) );
199 
200  REQUIRES( isHandleRangeValid( iCryptContext ) );
201  REQUIRES( passwordLength > 0 && passwordLength < MAX_INTLENGTH );
202  REQUIRES( ( optKeyLength == CRYPT_UNUSED ) || \
203  ( optKeyLength >= MIN_KEYSIZE && \
204  optKeyLength <= CRYPT_MAX_KEYSIZE ) );
205  REQUIRES( isHashAlgo( hashAlgo ) );
206  REQUIRES( ( salt == NULL && saltSize == 0 ) || \
207  ( saltSize > 0 && saltSize <= CRYPT_MAX_HASHSIZE ) );
208  REQUIRES( iterations >= 0 && iterations < MAX_INTLENGTH );
209 
210  /* Get various parameters needed to process the password */
211  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
212  &algorithm, CRYPT_CTXINFO_ALGO );
213  if( cryptStatusOK( status ) )
214  status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
215  &keySize, CRYPT_CTXINFO_KEYSIZE );
216  if( cryptStatusError( status ) )
217  return( status );
218  if( algorithm == CRYPT_ALGO_BLOWFISH )
219  {
220  /* PGP limits the Blowfish key size to 128 bits rather than the more
221  usual 448 bits */
222  keySize = 16;
223  }
224  if( algorithm == CRYPT_ALGO_AES && optKeyLength != CRYPT_UNUSED )
225  {
226  /* PGP allows various AES key sizes and then encodes the size in the
227  algorithm ID (ugh), to handle this we allow the caller to specify
228  the actual size */
229  keySize = optKeyLength;
230  }
231  ENSURES( keySize >= MIN_KEYSIZE && keySize <= CRYPT_MAX_KEYSIZE );
232 
233  /* Hash the password */
234  if( salt != NULL )
235  {
237 
238  /* Turn the user key into an encryption context key */
239  setMechanismDeriveInfo( &mechanismInfo, hashedKey, keySize,
240  password, passwordLength, hashAlgo,
241  salt, saltSize, iterations );
243  &mechanismInfo, MECHANISM_DERIVE_PGP );
244  if( cryptStatusError( status ) )
245  return( status );
246 
247  /* Save the derivation info with the context */
248  setMessageData( &msgData, ( MESSAGE_CAST ) salt, saltSize );
249  status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE_S,
250  &msgData, CRYPT_CTXINFO_KEYING_SALT );
251  if( cryptStatusOK( status ) && iterations > 0 )
252  {
253  /* The number of key setup iterations may be zero for non-
254  iterated hashing */
255  status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE,
256  ( MESSAGE_CAST ) &iterations,
258  }
259  if( cryptStatusOK( status ) )
260  {
261  const int value = hashAlgo; /* int vs.enum */
262  status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE,
263  ( MESSAGE_CAST ) &value,
265  }
266  if( cryptStatusError( status ) )
267  {
268  zeroise( hashedKey, CRYPT_MAX_KEYSIZE );
269  return( cryptArgError( status ) ? CRYPT_ERROR_BADDATA : status );
270  }
271  }
272  else
273  {
274  HASHFUNCTION_ATOMIC hashFunctionAtomic;
275 
276  getHashAtomicParameters( hashAlgo, 0, &hashFunctionAtomic, NULL );
277  hashFunctionAtomic( hashedKey, CRYPT_MAX_KEYSIZE, password,
278  passwordLength );
279  }
280 
281  /* Load the key into the context */
282  setMessageData( &msgData, hashedKey, keySize );
283  status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE_S,
284  &msgData, CRYPT_CTXINFO_KEY );
285  zeroise( hashedKey, CRYPT_MAX_KEYSIZE );
286 
287  return( status );
288  }
289 
290 /* Process a PGP-style IV. This isn't a standard IV but contains an extra
291  two bytes of check value, which is why it's denoted as 'ivInfo' rather
292  than a pure 'iv' */
293 
295 int pgpProcessIV( IN_HANDLE const CRYPT_CONTEXT iCryptContext,
296  INOUT_BUFFER_FIXED( ivInfoSize ) BYTE *ivInfo,
297  IN_RANGE( 8 + 2, CRYPT_MAX_IVSIZE + 2 ) const int ivInfoSize,
298  IN_LENGTH_IV const int ivDataSize,
299  const BOOLEAN isEncrypt,
300  const BOOLEAN resyncIV )
301  {
302  static const BYTE zeroIV[ CRYPT_MAX_IVSIZE ] = { 0 };
304  int status;
305 
306  assert( isReadPtr( ivInfo, ivInfoSize ) );
307 
308  REQUIRES( isHandleRangeValid( iCryptContext ) );
309  REQUIRES( ivDataSize >= 8 && ivDataSize <= CRYPT_MAX_IVSIZE );
310  REQUIRES( ivInfoSize == ivDataSize + 2 );
311 
312  /* PGP uses a bizarre way of handling IVs that resyncs the data on some
313  boundaries and doesn't actually use an IV but instead prefixes the
314  data with ivSize bytes of random information (which is effectively
315  the IV) followed by two bytes of key check value after which there's a
316  resync boundary that requires reloading the IV from the last ivSize
317  bytes of ciphertext. Two exceptions are the encrypted private key,
318  which does use an IV (although this can also be regarded as an
319  ivSize-byte prefix) without a key check or resync, and an encrypted
320  packet with MDC, which doesn't do the resync (if it weren't for that
321  it would be trivial to roll an MDC packet back to a non-MDC packet,
322  only the non-resync prevents this since the first bytes of the
323  encapsulated data packet will be corrupted).
324 
325  First, we load the all-zero IV */
326  setMessageData( &msgData, ( MESSAGE_CAST ) zeroIV, ivDataSize );
327  status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE_S,
328  &msgData, CRYPT_CTXINFO_IV );
329  if( cryptStatusError( status ) )
330  return( status );
331 
332  /* Then we encrypt or decrypt the IV info, which consists of the actual
333  IV data plus two bytes of check value */
334  if( isEncrypt )
335  {
336  /* Get some random data to serve as the IV, duplicate the last two
337  bytes to create the check value, and encrypt the lot */
338  setMessageData( &msgData, ivInfo, ivDataSize );
340  &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
341  if( cryptStatusOK( status ) )
342  {
343  memcpy( ivInfo + ivDataSize, ivInfo + ivDataSize - 2, 2 );
344  status = krnlSendMessage( iCryptContext, IMESSAGE_CTX_ENCRYPT,
345  ivInfo, ivInfoSize );
346  }
347  }
348  else
349  {
350  BYTE ivInfoBuffer[ CRYPT_MAX_IVSIZE + 2 + 8 ];
351 
352  /* Decrypt the first ivSize bytes (the IV data) and the following 2-
353  byte check value. There's a potential problem here in which an
354  attacker that convinces us to act as an oracle for the valid/not
355  valid status of the checksum can determine the contents of 16
356  bits of the encrypted data in 2^15 queries on average. This is
357  incredibly unlikely (which implementation would auto-respond to
358  32,000 reqpeated queries on a block of data and return the
359  results to an external agent?), however if it's a concern then
360  one ameliorating change would be to not perform the check for
361  keys that were PKC-encrypted, because the PKC decryption process
362  would check the key for us */
363  memcpy( ivInfoBuffer, ivInfo, ivInfoSize );
364  status = krnlSendMessage( iCryptContext, IMESSAGE_CTX_DECRYPT,
365  ivInfoBuffer, ivInfoSize );
366  if( cryptStatusOK( status ) && \
367  ( ivInfoBuffer[ ivDataSize - 2 ] != ivInfoBuffer[ ivDataSize + 0 ] || \
368  ivInfoBuffer[ ivDataSize - 1 ] != ivInfoBuffer[ ivDataSize + 1 ] ) )
369  status = CRYPT_ERROR_WRONGKEY;
370  }
371  if( cryptStatusError( status ) )
372  return( status );
373 
374  /* IF we've been told not to resync the IV, we're done */
375  if( !resyncIV )
376  return( CRYPT_OK );
377 
378  /* Finally we've got the data the way that we want it, resync the IV by
379  setting it to the last ivSize bytes of data processed */
380  setMessageData( &msgData, ivInfo + 2, ivDataSize );
381  return( krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE_S,
382  &msgData, CRYPT_CTXINFO_IV ) );
383  }
384 #endif /* USE_PGP || USE_PGPKEYS */