cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
base64_id.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib PKI UserID En/Decoding Routines *
4 * Copyright Peter Gutmann 1998-2007 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10 #else
11  #include "crypt.h"
12 #endif /* Compiler-specific includes */
13 
14 /* The number of bits in each code group of 5 characters */
15 
16 #define BITS_PER_GROUP ( 5 * 5 ) /* 5 chars encoding 5 bits each */
17 
18 /* En/decode tables for text representations of binary keys */
19 
20 static const char codeTable[] = \
21  "ABCDEFGHJKLMNPQRSTUVWXYZ23456789____"; /* No O/0, I/1 */
22 static const int hiMask[] = { 0x00, 0x00, 0x00, 0x00, 0x0F, 0x07, 0x03, 0x01 };
23 static const int loMask[] = { 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0 };
24 
25 /****************************************************************************
26 * *
27 * PKI User ID Encoding Functions *
28 * *
29 ****************************************************************************/
30 
31 /* Adjust the binary form of a PKI user ID so that it can be encoded into a
32  fixed number of text characters. This function is required because key
33  lookup is performed on the decoded form of the ID that's supplied via PKI
34  user requests, if we used the non-adjusted form for the key lookup then
35  we couldn't locate the stored user info that's indexed from the adjusted
36  form */
37 
39 static int adjustPKIUserValue( INOUT_BUFFER( valueMaxLength, *valueLength ) \
40  BYTE *value,
43  IN_RANGE( 3, 4 ) const int noCodeGroups )
44  {
45  assert( isWritePtr( value, valueMaxLength ) );
46  assert( isWritePtr( valueLength, sizeof( int ) ) );
47 
48  REQUIRES( valueMaxLength >= roundUp( 3 * BITS_PER_GROUP, 8 ) / 8 && \
49  valueMaxLength < MAX_INTLENGTH_SHORT );
50  REQUIRES( noCodeGroups == 3 || noCodeGroups == 4 );
51 
52  /* Mask off any bits at the end of the data that can't be encoded using
53  the given number of code groups */
54  if( noCodeGroups == 3 )
55  {
56  /* Length = ( ( roundUp( 3 * BITS_PER_GROUP, 8 ) / 8 ) - 1 )
57  = ( 80 / 8 ) - 1
58  = 9
59  Mask = ( 0xFF << ( 8 - ( ( 3 * BITS_PER_GROUP ) % 8 ) ) )
60  = ( 0xFF << ( 8 - 3 ) )
61  = 0xE0 */
62  value[ 8 ] &= 0xE0;
63  *valueLength = 9;
64  }
65  else
66  {
67  /* Length = ( ( roundUp( 4 * BITS_PER_GROUP, 8 ) / 8 ) - 1 )
68  = ( 104 / 8 ) - 1
69  = 12
70  Mask = ( 0xFF << ( 8 - ( ( 4 * BITS_PER_GROUP ) % 8 ) ) )
71  = ( 0xFF << ( 8 - 4 ) )
72  = 0xF0 */
73  value[ 11 ] &= 0xF0;
74  *valueLength = 12;
75  }
76 
77  return( CRYPT_OK );
78  }
79 
80 /* Encode a text representation of a binary key */
81 
83 int encodePKIUserValue( OUT_BUFFER( encValMaxLen, *encValLen ) char *encVal,
84  IN_LENGTH_SHORT_MIN( 10 ) const int encValMaxLen,
86  IN_BUFFER( valueLen ) const BYTE *value,
87  IN_LENGTH_SHORT_MIN( 8 ) const int valueLen,
88  IN_RANGE( 3, 4 ) const int noCodeGroups )
89  {
90  BYTE valBuf[ 128 + 8 ];
91  const int dataBytes = ( roundUp( noCodeGroups * BITS_PER_GROUP, 8 ) / 8 );
92  int i, byteCount = 0, bitCount = 0, length, status;
93 
94  assert( isWritePtr( encVal, encValMaxLen ) );
95  assert( isWritePtr( encValLen, sizeof( int ) ) );
96  assert( isReadPtr( value, dataBytes ) );
97 
98  REQUIRES( encValMaxLen >= 10 && encValMaxLen < MAX_INTLENGTH_SHORT );
99  REQUIRES( valueLen >= 8 && valueLen < MAX_INTLENGTH_SHORT );
100  REQUIRES( noCodeGroups == 3 || noCodeGroups == 4 );
101  REQUIRES( dataBytes >= 10 && dataBytes < 64 );
102  REQUIRES( valueLen >= dataBytes - 1 );
103  /* There must be enough input data present to produce the
104  required number of output bytes minus one for the checksum
105  at the start */
106 
107  /* Clear return values */
108  memset( encVal, 0, min( 16, encValMaxLen ) );
109  *encValLen = 0;
110 
111  /* Copy across the data bytes, leaving a gap at the start for the
112  checksum */
113  memcpy( valBuf + 1, value, dataBytes - 1 );
114  status = adjustPKIUserValue( valBuf + 1, 128 - 1, &length,
115  noCodeGroups );
116  if( cryptStatusError( status ) )
117  return( status );
118  length += 1;
119 
120  /* Calculate the Fletcher checksum and prepend it to the data bytes
121  This is easier than handling the addition of a non-byte-aligned
122  quantity to the end of the data */
123  valBuf[ 0 ] = intToByte( checksumData( valBuf + 1, length - 1 ) & 0xFF );
124 
125  /* Encode the binary data as text */
126  for( length = 0, i = 1; i <= noCodeGroups * 5; i++ )
127  {
128  int chunkValue;
129 
130  /* Extract the next 5-bit chunk and convert it to text form */
131  if( bitCount < 3 )
132  {
133  /* Everything's present in one byte, shift it down to the LSB */
134  chunkValue = ( valBuf[ byteCount ] >> ( 3 - bitCount ) ) & 0x1F;
135  }
136  else
137  {
138  if( bitCount == 3 )
139  {
140  /* It's the 5 LSBs */
141  chunkValue = valBuf[ byteCount ] & 0x1F;
142  }
143  else
144  {
145  /* The data spans two bytes, shift the bits from the high
146  byte up and the bits from the low byte down */
147  chunkValue = ( ( valBuf[ byteCount ] & \
148  hiMask[ bitCount ] ) << ( bitCount - 3 ) ) | \
149  ( ( valBuf[ byteCount + 1 ] & \
150  loMask[ bitCount ] ) >> ( 11 - bitCount ) );
151  }
152  }
153  ENSURES( chunkValue >= 0 && chunkValue <= 0x20 );
154  encVal[ length++ ] = codeTable[ chunkValue ];
155  if( length < encValMaxLen && ( i % 5 ) == 0 && i < noCodeGroups * 5 )
156  encVal[ length++ ] = '-';
157  ENSURES( length < encValMaxLen );
158 
159  /* Advance by 5 bits */
160  bitCount += 5;
161  if( bitCount >= 8 )
162  {
163  bitCount -= 8;
164  byteCount++;
165  }
166  ENSURES( byteCount >= 0 && byteCount < 64 );
167  }
168  *encValLen = length;
169 
170  return( CRYPT_OK );
171  }
172 
173 /****************************************************************************
174 * *
175 * PKI User ID Decoding Functions *
176 * *
177 ****************************************************************************/
178 
179 /* Check whether a text string appears to be an encoded PKI user value */
180 
182 BOOLEAN isPKIUserValue( IN_BUFFER( encValLength ) const char *encVal,
183  IN_LENGTH_SHORT_MIN( 10 ) const int encValLength )
184  {
185  int i = 0;
186 
187  assert( isReadPtr( encVal, encValLength ) );
188 
189  REQUIRES_B( encValLength > 10 && encValLength < MAX_INTLENGTH_SHORT );
190 
191  /* Check whether a user value is of the form XXXXX-XXXXX-XXXXX{-XXXXX}.
192  Although we shouldn't be seeing O/0 or I/1 in the input we don't
193  specifically check for these since they could be present as typos.
194  In other words we're checking for the presence of an input pattern
195  that matches an encoded PKI user value, not for the validity of the
196  value itself, which will be checked by decodePKIUserValue() */
197  if( ( encValLength != ( 3 * 5 ) + 2 ) && \
198  ( encValLength != ( 4 * 5 ) + 3 ) )
199  return( FALSE );
200  while( i < encValLength )
201  {
202  int j;
203 
204  /* Decode each character group. We know from the length check above
205  that this won't run off the end of the data, so we don't have to
206  check the index value */
207  for( j = 0; j < 5; j++ )
208  {
209  const int ch = byteToInt( encVal[ i++ ] );
210 
211  if( !isAlnum( ch ) )
212  return( FALSE );
213  }
214  if( i < encValLength && encVal[ i++ ] != '-' )
215  return( FALSE );
216  }
217  return( TRUE );
218  }
219 
220 /* Decode a text representation of a binary key */
221 
222 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
223 int decodePKIUserValue( OUT_BUFFER( valueMaxLen, *valueLen ) BYTE *value,
224  IN_LENGTH_SHORT_MIN( 10 ) const int valueMaxLen,
225  OUT_LENGTH_SHORT_Z int *valueLen,
226  IN_BUFFER( encValLength ) const char *encVal,
227  IN_LENGTH_SHORT const int encValLength )
228  {
229  BYTE valBuf[ 128 + 8 ];
230  char encBuf[ CRYPT_MAX_TEXTSIZE + 8 ];
231  int i = 0, byteCount = 0, bitCount = 0, length = 0;
232 
233  assert( isWritePtr( value, valueMaxLen ) );
234  assert( isWritePtr( valueLen, sizeof( int ) ) );
235  assert( isReadPtr( encVal, encValLength ) );
236 
237  REQUIRES( valueMaxLen >= 10 && valueMaxLen < MAX_INTLENGTH_SHORT );
238  REQUIRES( encValLength > 0 && encValLength < MAX_INTLENGTH_SHORT );
239 
240  /* Clear return values */
241  memset( value, 0, min( 16, valueMaxLen ) );
242  *valueLen = 0;
243 
244  /* Make sure that the input has a reasonable length (this should have
245  been checked by the caller using isPKIUserValue(), so we throw an
246  exception if the check fails). We return CRYPT_ERROR_BADDATA rather
247  than the more obvious CRYPT_ERROR_OVERFLOW since something returned
248  from this low a level should be a consistent error code indicating
249  that there's a problem with the PKI user value as a whole */
250  if( encValLength < ( 3 * 5 ) || encValLength > CRYPT_MAX_TEXTSIZE )
251  {
252  DEBUG_DIAG(( "PKI user value has invalid length" ));
253  assert( DEBUG_WARN );
254  return( CRYPT_ERROR_BADDATA );
255  }
256 
257  REQUIRES( isPKIUserValue( encVal, encValLength ) );
258 
259  /* Undo the formatting of the encoded value from XXXXX-XXXXX-XXXXX...
260  to XXXXXXXXXXXXXXX... */
261  while( i < encValLength )
262  {
263  int j;
264 
265  for( j = 0; j < 5; j++ )
266  {
267  const int ch = byteToInt( encVal[ i++ ] );
268 
269  /* Note that we've just incremented 'i', so the range check is
270  '>' rather than '>=' */
271  if( !isAlnum( ch ) || i > encValLength )
272  return( CRYPT_ERROR_BADDATA );
273  encBuf[ length++ ] = intToByte( toUpper( ch ) );
274  }
275  if( i < encValLength && encVal[ i++ ] != '-' )
276  return( CRYPT_ERROR_BADDATA );
277  }
278  if( ( length % 5 ) != 0 || length > CRYPT_MAX_TEXTSIZE )
279  return( CRYPT_ERROR_BADDATA );
280 
281  /* Decode the text data into binary */
282  memset( valBuf, 0, 128 );
283  for( i = 0; i < length; i ++ )
284  {
285  const int ch = byteToInt( encBuf[ i ] );
286  int chunkValue;
287 
288  for( chunkValue = 0; chunkValue < 0x20; chunkValue++ )
289  {
290  if( codeTable[ chunkValue ] == ch )
291  break;
292  }
293  if( chunkValue >= 0x20 )
294  return( CRYPT_ERROR_BADDATA );
295 
296  /* Extract the next 5-bit chunk and convert it to text form */
297  if( bitCount < 3 )
298  {
299  /* Everything's present in one byte, shift it up into position */
300  valBuf[ byteCount ] |= chunkValue << ( 3 - bitCount );
301  }
302  else
303  {
304  if( bitCount == 3 )
305  {
306  /* It's the 5 LSBs */
307  valBuf[ byteCount ] |= chunkValue;
308  }
309  else
310  {
311  /* The data spans two bytes, shift the bits from the high
312  byte down and the bits from the low byte up */
313  valBuf[ byteCount ] |= \
314  intToByte( ( chunkValue >> ( bitCount - 3 ) ) & \
315  hiMask[ bitCount ] );
316  valBuf[ byteCount + 1 ] = \
317  intToByte( ( chunkValue << ( 11 - bitCount ) ) & \
318  loMask[ bitCount ] );
319  }
320  }
321 
322  /* Advance by 5 bits */
323  bitCount += 5;
324  if( bitCount >= 8 )
325  {
326  bitCount -= 8;
327  byteCount++;
328  }
329  ENSURES( byteCount >= 0 && byteCount < 64 );
330  }
331 
332  /* Calculate the Fletcher checksum and make sure that it matches the
333  value at the start of the data bytes */
334  if( bitCount > 0 )
335  byteCount++; /* More bits in the last partial byte */
336  if( valBuf[ 0 ] != ( checksumData( valBuf + 1, byteCount - 1 ) & 0xFF ) )
337  return( CRYPT_ERROR_BADDATA );
338 
339  /* Return the decoded value to the caller */
340  ENSURES( byteCount - 1 <= valueMaxLen );
341  memcpy( value, valBuf + 1, byteCount - 1 );
342  *valueLen = byteCount - 1;
343 
344  return( CRYPT_OK );
345  }