1 /****************************************************************************
2 *																			*
3 *						  cryptlib Internal String API						*
4 *						Copyright Peter Gutmann 1992-2014					*
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 /****************************************************************************
15 *																			*
16 *						General-purpose String Functions					*
17 *																			*
18 ****************************************************************************/
19 
20 /* Perform various string-processing operations */
21 
22 CHECK_RETVAL_STRINGOP STDC_NONNULL_ARG( ( 1 ) ) \
strFindCh(IN_BUFFER (strLen)const char * str,IN_LENGTH_SHORT const int strLen,IN_CHAR const int findCh)23 int strFindCh( IN_BUFFER( strLen ) const char *str,
24 			   IN_LENGTH_SHORT const int strLen,
25 			   IN_CHAR const int findCh )
26 	{
27 	int i;
28 
29 	assert( isReadPtr( str, strLen ) );
30 
31 	REQUIRES( strLen > 0 && strLen < MAX_INTLENGTH_SHORT );
32 	REQUIRES( findCh >= 0 && findCh <= 0x7F );
33 
34 	for( i = 0; i < strLen; i++ )
35 		{
36 		if( str[ i ] == findCh )
37 			return( i );
38 		}
39 
40 	return( -1 );
41 	}
42 
43 CHECK_RETVAL_STRINGOP STDC_NONNULL_ARG( ( 1, 3 ) ) \
strFindStr(IN_BUFFER (strLen)const char * str,IN_LENGTH_SHORT const int strLen,IN_BUFFER (findStrLen)const char * findStr,IN_LENGTH_SHORT const int findStrLen)44 int strFindStr( IN_BUFFER( strLen ) const char *str,
45 				IN_LENGTH_SHORT const int strLen,
46 				IN_BUFFER( findStrLen ) const char *findStr,
47 				IN_LENGTH_SHORT const int findStrLen )
48 	{
49 	const int findCh = toUpper( findStr[ 0 ] );
50 	int i;
51 
52 	assert( isReadPtr( str, strLen ) );
53 	assert( isReadPtr( findStr, findStrLen ) );
54 
55 	REQUIRES( strLen > 0 && strLen < MAX_INTLENGTH_SHORT );
56 	REQUIRES( findStrLen > 0 && findStrLen < MAX_INTLENGTH_SHORT );
57 	REQUIRES( findCh >= 0 && findCh <= 0x7F );
58 
59 	for( i = 0; i <= strLen - findStrLen; i++ )
60 		{
61 		if( toUpper( str[ i ] ) == findCh && \
62 			!strCompare( str + i, findStr, findStrLen ) )
63 			return( i );
64 		}
65 
66 	return( -1 );
67 	}
68 
69 CHECK_RETVAL_STRINGOP STDC_NONNULL_ARG( ( 1 ) ) \
strSkipWhitespace(IN_BUFFER (strLen)const char * str,IN_LENGTH_SHORT const int strLen)70 int strSkipWhitespace( IN_BUFFER( strLen ) const char *str,
71 					   IN_LENGTH_SHORT const int strLen )
72 	{
73 	int i;
74 
75 	assert( isReadPtr( str, strLen ) );
76 
77 	REQUIRES( strLen > 0 && strLen < MAX_INTLENGTH_SHORT );
78 
79 	for( i = 0; i < strLen && ( str[ i ] == ' ' || str[ i ] == '\t' ); i++ );
80 	return( ( i < strLen ) ? i : -1 );
81 	}
82 
83 CHECK_RETVAL_STRINGOP STDC_NONNULL_ARG( ( 1 ) ) \
strSkipNonWhitespace(IN_BUFFER (strLen)const char * str,IN_LENGTH_SHORT const int strLen)84 int strSkipNonWhitespace( IN_BUFFER( strLen ) const char *str,
85 						  IN_LENGTH_SHORT const int strLen )
86 	{
87 	int i;
88 
89 	assert( isReadPtr( str, strLen ) );
90 
91 	REQUIRES( strLen > 0 && strLen < MAX_INTLENGTH_SHORT );
92 
93 	/* This differs slightly from strSkipWhitespace() in that EOL is also
94 	   counted as whitespace so there's never an error condition unless
95 	   we don't find anything at all */
96 	for( i = 0; i < strLen && str[ i ] != ' ' && str[ i ] != '\t'; i++ );
97 	return( i > 0 ? i : -1 );
98 	}
99 
100 CHECK_RETVAL_STRINGOP STDC_NONNULL_ARG( ( 1, 2 ) ) \
strStripWhitespace(OUT_PTR_COND const char ** newStringPtr,IN_BUFFER (strLen)const char * string,IN_LENGTH_SHORT const int strLen)101 int strStripWhitespace( OUT_PTR_COND const char **newStringPtr,
102 						IN_BUFFER( strLen ) const char *string,
103 						IN_LENGTH_SHORT const int strLen )
104 	{
105 	int startPos, endPos;
106 
107 	assert( isReadPtr( newStringPtr, sizeof( char * ) ) );
108 	assert( isReadPtr( string, strLen ) );
109 
110 	REQUIRES( strLen > 0 && strLen < MAX_INTLENGTH_SHORT );
111 
112 	/* Clear return value */
113 	*newStringPtr = NULL;
114 
115 	/* Skip leading and trailing whitespace */
116 	for( startPos = 0;
117 		 startPos < strLen && \
118 			( string[ startPos ] == ' ' || string[ startPos ] == '\t' );
119 		 startPos++ );
120 	if( startPos >= strLen )
121 		return( -1 );
122 	*newStringPtr = string + startPos;
123 	for( endPos = strLen;
124 		 endPos > startPos && \
125 			( string[ endPos - 1 ] == ' ' || string[ endPos - 1 ] == '\t' );
126 		 endPos-- );
127 	ENSURES( endPos - startPos > 0 );
128 	return( endPos - startPos );
129 	}
130 
131 /****************************************************************************
132 *																			*
133 *						Special-purpose String Functions					*
134 *																			*
135 ****************************************************************************/
136 
137 /* Extract a substring from a string.  This converts:
138 
139 	 string				startOffset							 strLen
140 		|					|									|
141 		v					v									v
142 		+-------------------+---------------+-------------------+
143 		|	Processed data	|	Whitespace	|	Remaining data	|
144 		+-------------------+---------------+-------------------+
145 
146    into:
147 
148 	 newStr				 length
149 		|					|
150 		v					v
151 		+-------------------+
152 		|	Remaining data	|
153 		+-------------------+
154 
155    The order of the parameters is a bit unusual, normally we'd use
156    { str, strLen } but this makes things a bit confusing for the caller, for
157    whom it's more logical to group the parameters based on the overall
158    operation being performed, which to extract a substring beginning at
159    startOffset is { str, startOffset, strLen } */
160 
161 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
strExtract(OUT_PTR_COND const char ** newStringPtr,IN_BUFFER (strLen)const char * string,IN_LENGTH_SHORT_Z const int startOffset,IN_LENGTH_SHORT const int strLen)162 int strExtract( OUT_PTR_COND const char **newStringPtr,
163 				IN_BUFFER( strLen ) const char *string,
164 				IN_LENGTH_SHORT_Z const int startOffset,
165 				IN_LENGTH_SHORT const int strLen )
166 	{
167 	const int newLen = strLen - startOffset;
168 
169 	assert( isReadPtr( newStringPtr, sizeof( char * ) ) );
170 	assert( isReadPtr( string, strLen ) );
171 
172 	REQUIRES( strLen > 0 && strLen < MAX_INTLENGTH_SHORT );
173 	REQUIRES( startOffset >= 0 && startOffset <= strLen && \
174 			  startOffset < MAX_INTLENGTH_SHORT );
175 			  /* May be zero if we're extracting from the start of the
176 			     string; may be equal to strLen if it's the entire
177 				 remaining string */
178 
179 	/* Clear return value */
180 	*newStringPtr = NULL;
181 
182 	if( newLen < 1 || newLen > strLen || newLen >= MAX_INTLENGTH_SHORT )
183 		return( -1 );
184 	return( strStripWhitespace( newStringPtr, string + startOffset, newLen ) );
185 	}
186 
187 /* Parse a numeric or hex string into an integer value.  Safe conversion of a
188    numeric string gets a bit problematic because atoi() can't really
189    indicate an error except by returning 0, which is indistinguishable from
190    a zero numeric value.  To handle this we have to perform the conversion
191    ourselves */
192 
193 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
IN_BUFFER(strLen)194 int strGetNumeric( IN_BUFFER( strLen ) const char *str,
195 				   IN_LENGTH_SHORT const int strLen,
196 				   OUT_INT_Z int *numericValue,
197 				   IN_RANGE( 0, 100 ) const int minValue,
198 				   IN_RANGE( minValue, MAX_INTLENGTH ) const int maxValue )
199 	{
200 	int i, value;
201 
202 	assert( isReadPtr( str, strLen ) );
203 	assert( isWritePtr( numericValue, sizeof( int ) ) );
204 
205 	REQUIRES( strLen > 0 && strLen < MAX_INTLENGTH_SHORT );
206 	REQUIRES( minValue >= 0 && minValue < maxValue && \
207 			  maxValue <= MAX_INTLENGTH );
208 
209 	/* Clear return value */
210 	*numericValue = 0;
211 
212 	/* Make sure that the value is within the range 'n' ... 'nnnnnnn' */
213 	if( strLen < 1 || strLen > 7 )
214 		return( CRYPT_ERROR_BADDATA );
215 
216 	/* Process the numeric string.  Note that the redundant 'value < 0'
217 	   check is necessary in order to prevent gcc from detecting what it
218 	   thinks is Undefined Behaviour (UB) and removing further checks from
219 	   the code.  In addition the second check for MAX_INTLENGTH - ch isn't
220 	   really necessary because we know that value < MAX_INTLENGTH / 10,
221 	   which means that value <= MAX_INTLENGTH / 10 - 1, so
222 	   value * 10 <= MAX_INTLENGTH - 10, therefore
223 	   value * 10 < MAX_INTLENGTH - 9, so value * 10 < MAX_INTLENGTH - ch,
224 	   however we leave it in to make the condition explicit */
225 	for( value = 0, i = 0; i < strLen; i++ )
226 		{
227 		const int ch = byteToInt( str[ i ] ) - '0';
228 
229 		if( ch < 0 || ch > 9 )
230 			return( CRYPT_ERROR_BADDATA );
231 		if( value < 0 || value >= MAX_INTLENGTH / 10 )
232 			return( CRYPT_ERROR_BADDATA );
233 		value *= 10;
234 		if( value >= MAX_INTLENGTH - ch )
235 			return( CRYPT_ERROR_BADDATA );
236 		value += ch;
237 		ENSURES( value >= 0 && value < MAX_INTLENGTH );
238 		}
239 
240 	/* Make sure that the final value is within the specified range */
241 	if( value < minValue || value > maxValue )
242 		return( CRYPT_ERROR_BADDATA );
243 
244 	*numericValue = value;
245 	return( CRYPT_OK );
246 	}
247 
248 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
IN_BUFFER(strLen)249 int strGetHex( IN_BUFFER( strLen ) const char *str,
250 			   IN_LENGTH_SHORT const int strLen,
251 			   OUT_INT_Z int *numericValue,
252 			   IN_RANGE( 0, 100 ) const int minValue,
253 			   IN_RANGE( minValue, MAX_INTLENGTH ) const int maxValue )
254 	{
255 #ifdef SYSTEM_16BIT
256 	const int strMaxLen = ( maxValue > 0xFFF ) ? 4 : \
257 						  ( maxValue > 0xFF ) ? 3 : \
258 						  ( maxValue > 0xF ) ? 2 : 1;
259 #else
260 	const int strMaxLen = ( maxValue > 0xFFFF ) ? 5 : \
261 						  ( maxValue > 0xFFF ) ? 4 : \
262 						  ( maxValue > 0xFF ) ? 3 : \
263 						  ( maxValue > 0xF ) ? 2 : 1;
264 #endif /* SYSTEM_16BIT */
265 	int i, value = 0;
266 
267 	assert( isReadPtr( str, strLen ) );
268 	assert( isWritePtr( numericValue, sizeof( int ) ) );
269 
270 	REQUIRES( strLen > 0 && strLen < MAX_INTLENGTH_SHORT );
271 	REQUIRES( minValue >= 0 && minValue < maxValue && \
272 			  maxValue <= MAX_INTLENGTH );
273 
274 	/* Clear return value */
275 	*numericValue = 0;
276 
277 	/* Make sure that the length is sensible for the value that we're
278 	   reading */
279 	if( strLen < 1 || strLen > strMaxLen )
280 		return( CRYPT_ERROR_BADDATA );
281 
282 	/* Process the numeric string.  We don't have to perform the same level
283 	   of overflow checking as we do in strGetNumeric() because the maximum
284 	   value is capped to fit into an int */
285 	for( i = 0; i < strLen; i++ )
286 		{
287 		const int ch = toLower( str[ i ] );
288 
289 		if( !isXDigit( ch ) )
290 			return( CRYPT_ERROR_BADDATA );
291 		value = ( value << 4 ) | \
292 				( ( ch <= '9' ) ? ch - '0' : ch - ( 'a' - 10 ) );
293 		}
294 	if( value < minValue || value > maxValue )
295 		return( CRYPT_ERROR_BADDATA );
296 
297 	*numericValue = value;
298 
299 	return( CRYPT_OK );
300 	}
301 
302 /* Determine whether a string is printable or not, used when checking whether
303    it should be displayed to the caller as a text string or a hex dump */
304 
305 CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
strIsPrintable(IN_BUFFER (strLen)const void * str,IN_LENGTH_SHORT const int strLen)306 BOOLEAN strIsPrintable( IN_BUFFER( strLen ) const void *str,
307 						IN_LENGTH_SHORT const int strLen )
308 	{
309 	const BYTE *strPtr = str;
310 	int i;
311 
312 	assert( isReadPtr( str, strLen ) );
313 
314 	REQUIRES( strLen > 0 && strLen < MAX_INTLENGTH_SHORT );
315 
316 	for( i = 0; i < strLen; i++ )
317 		{
318 		const int ch = byteToInt( strPtr[ i ] );
319 
320 		if( !isValidTextChar( ch ) )
321 			return( FALSE );
322 		}
323 
324 	return( TRUE );
325 	}
326 
327 /* Sanitise a string before passing it back to the user.  This is used to
328    clear potential problem characters (for example control characters)
329    from strings passed back from untrusted sources (nec verbum verbo
330    curabis reddere fidus interpres - Horace).
331 
332    This function assumes that the string is in ASCII form rather than some
333    exotic character set, since this is used for processing text error
334    messages sent to us by remote systems we can reasonably assume that
335    they should be be, well, text error messages so that we're within our
336    rights to filter out non-text data.
337 
338    The function returns a pointer to the string to allow it to be used in
339    the form printf( "..%s..", sanitiseString( string, strLen ) ).  In
340    addition it formats the data to fit a fixed-length buffer, if the string
341    is longer than the indicated buffer size then it appends a '[...]' at the
342    end of the buffer to indicate that further data was truncated.   The
343    transformation applied is as follows:
344 
345 	  buffer					strMaxLen
346 		|							|
347 		v							v
348 		+---------------------------+		.								.
349 		|							|  ==>	.								.
350 		+---------------------------+		.								.
351 		.							.		.								.
352 		|---------------|			.		|---------------|\0|			.
353 		.				^			.		.								.
354 		|--------------------------------|	|-----------------------|[...]\0|
355 						|				 ^
356 						+---- strLen ----+
357 
358    so "Error string of arbitrary length..." with a buffer size of 20 would
359    become "Error string [...]" */
360 
361 STDC_NONNULL_ARG( ( 1 ) ) \
sanitiseString(INOUT_BUFFER (strMaxLen,strLen)void * string,IN_LENGTH_SHORT const int strMaxLen,IN_LENGTH_SHORT const int strLen)362 char *sanitiseString( INOUT_BUFFER( strMaxLen, strLen ) void *string,
363 					  IN_LENGTH_SHORT const int strMaxLen,
364 					  IN_LENGTH_SHORT const int strLen )
365 	{
366 	BYTE *strPtr = string;	/* See comment below */
367 	const int strDataLen = min( strLen, strMaxLen );
368 	int i;
369 
370 	assert( isWritePtr( string, strMaxLen ) );
371 
372 	REQUIRES_EXT( ( strLen > 0 && strLen < MAX_INTLENGTH_SHORT ), \
373 				  "(Internal error)" );
374 	REQUIRES_EXT( ( strMaxLen > 0 && strMaxLen < MAX_INTLENGTH_SHORT ), \
375 				  "(Internal error)" );
376 
377 	/* Remove any potentially unsafe characters from the string, effectively
378 	   converting it from a 'BYTE *' to a 'char *'.  This is also the reason
379 	   why the function prototype declares it as a 'void *', if it's declared
380 	   as a 'BYTE *' then the conversion process gives compilers and static
381 	   analysers headaches */
382 	for( i = 0; i < strDataLen; i++ )
383 		{
384 		const int ch = byteToInt( strPtr[ i ] );
385 
386 		if( !isValidTextChar( ch ) )
387 			strPtr[ i ] = '.';
388 		}
389 
390 	/* If there was more input than we could fit into the buffer and
391 	   there's room for a continuation indicator, add this to the output
392 	   string */
393 	if( ( strLen >= strMaxLen ) && ( strMaxLen > 8 ) )
394 		memcpy( strPtr + strMaxLen - 6, "[...]", 5 );	/* Extra -1 for '\0' */
395 
396 	/* Terminate the string to allow it to be used in printf()-style
397 	   functions */
398 	if( strLen < strMaxLen )
399 		strPtr[ strLen ] = '\0';
400 	else
401 		strPtr[ strMaxLen - 1 ] = '\0';
402 
403 	/* We've converted the string from BYTE * to char * so it can be
404 	   returned as a standard text string */
405 	return( ( char * ) strPtr );
406 	}
407 
408 /****************************************************************************
409 *																			*
410 *						TR 24731 Safe stdlib Extensions						*
411 *																			*
412 ****************************************************************************/
413 
414 #ifndef __STDC_LIB_EXT1__
415 
416 /* Minimal wrappers for the TR 24731 functions to map them to older stdlib
417    equivalents.  Because of potential issues when comparing a (signed)
418    literal value -1 to the unsigned size_t we explicitly check for both
419    '( size_t ) -1' as well as a general check for a negative return value */
420 
421 RETVAL_RANGE( -1, 0 ) \
mbstowcs_s(OUT size_t * retval,OUT_BUFFER_FIXED (dstmax)wchar_t * dst,IN_LENGTH_SHORT size_t dstmax,IN_BUFFER (len)const char * src,IN_LENGTH_SHORT size_t len)422 int mbstowcs_s( OUT size_t *retval,
423 				OUT_BUFFER_FIXED( dstmax ) wchar_t *dst,
424 				IN_LENGTH_SHORT size_t dstmax,
425 				IN_BUFFER( len ) const char *src,
426 				IN_LENGTH_SHORT size_t len )
427 	{
428 	size_t bytesCopied;
429 
430 	assert( isWritePtr( retval, sizeof( size_t ) ) );
431 	assert( isWritePtr( dst, dstmax ) );
432 	assert( isReadPtr( src, len ) );
433 
434 	REQUIRES_EXT( ( dstmax > 0 && dstmax < MAX_INTLENGTH_SHORT ), -1 );
435 	REQUIRES_EXT( ( len > 0 && len <= dstmax && \
436 					len < MAX_INTLENGTH_SHORT ), -1 );
437 
438 	/* Clear return value */
439 	*retval = 0;
440 
441 	bytesCopied = mbstowcs( dst, src, len );
442 	if( ( bytesCopied == ( size_t ) -1 ) || ( bytesCopied <= 0 ) )
443 		return( -1 );
444 	*retval = bytesCopied;
445 	return( 0 );
446 	}
447 
448 RETVAL_RANGE( -1, 0 ) \
wcstombs_s(OUT size_t * retval,OUT_BUFFER_FIXED (dstmax)char * dst,IN_LENGTH_SHORT size_t dstmax,IN_BUFFER (len)const wchar_t * src,IN_LENGTH_SHORT size_t len)449 int wcstombs_s( OUT size_t *retval,
450 				OUT_BUFFER_FIXED( dstmax ) char *dst,
451 				IN_LENGTH_SHORT size_t dstmax,
452 				IN_BUFFER( len) const wchar_t *src,
453 				IN_LENGTH_SHORT size_t len )
454 	{
455 	size_t bytesCopied;
456 
457 	assert( isWritePtr( retval, sizeof( size_t ) ) );
458 	assert( isWritePtr( dst, dstmax ) );
459 	assert( isReadPtr( src, len ) );
460 
461 	REQUIRES_EXT( ( dstmax > 0 && dstmax < MAX_INTLENGTH_SHORT ), -1 );
462 	REQUIRES_EXT( ( len > 0 && len <= dstmax && \
463 					len < MAX_INTLENGTH_SHORT ), -1 );
464 
465 	/* Clear return value */
466 	*retval = 0;
467 
468 	bytesCopied = wcstombs( dst, src, len );
469 	if( ( bytesCopied == ( size_t ) -1 ) || ( bytesCopied <= 0 ) )
470 		return( -1 );
471 	*retval = bytesCopied;
472 	return( 0 );
473 	}
474 #endif /* !__STDC_LIB_EXT1__ */
475 
476 /****************************************************************************
477 *																			*
478 *								Self-test Functions							*
479 *																			*
480 ****************************************************************************/
481 
482 /* Test code for the above functions */
483 
484 #ifndef NDEBUG
485 
486 CHECK_RETVAL_BOOL \
testIntString(void)487 BOOLEAN testIntString( void )
488 	{
489 	BYTE buffer[ 16 + 8 ];
490 	const char *stringPtr;
491 	int stringLen, value;
492 
493 	/* Test strFindCh() */
494 	if( strFindCh( "abcdefgh", 8, 'a' ) != 0 || \
495 		strFindCh( "abcdefgh", 8, 'd' ) != 3 || \
496 		strFindCh( "abcdefgh", 8, 'h' ) != 7 || \
497 		strFindCh( "abcdefgh", 8, 'x' ) != -1 )
498 		return( FALSE );
499 
500 	/* Test strFindStr() */
501 	if( strFindStr( "abcdefgh", 8, "abc", 3 ) != 0 || \
502 		strFindStr( "abcdefgh", 8, "fgh", 3 ) != 5 || \
503 		strFindStr( "abcdefgh", 8, "ghi", 3 ) != -1 || \
504 		strFindStr( "abcdefgh", 8, "abcdefghi", 9 ) != -1 )
505 		return( FALSE );
506 
507 	/* Test strSkipWhitespace() */
508 	if( strSkipWhitespace( "abcdefgh", 8 ) != 0 || \
509 		strSkipWhitespace( " abcdefgh", 9 ) != 1 || \
510 		strSkipWhitespace( " \t abcdefgh", 11 ) != 3 || \
511 		strSkipWhitespace( " x abcdefgh", 11 ) != 1 || \
512 		strSkipWhitespace( "  \t ", 4 ) != -1 )
513 		return( FALSE );
514 
515 	/* Test strSkipNonWhitespace() */
516 	if( strSkipNonWhitespace( "abcdefgh", 8 ) != 8 || \
517 		strSkipNonWhitespace( " abcdefgh", 9 ) != -1 || \
518 		strSkipNonWhitespace( "abcdefgh ", 9 ) != 8 || \
519 		strSkipNonWhitespace( "abcdefgh x ", 11 ) != 8 )
520 		return( FALSE );
521 
522 	/* Test strStripWhitespace() */
523 	stringLen = strStripWhitespace( &stringPtr, "abcdefgh", 8 );
524 	if( stringLen != 8 || memcmp( stringPtr, "abcdefgh", 8 ) )
525 		return( FALSE );
526 	stringLen = strStripWhitespace( &stringPtr, " abcdefgh", 9 );
527 	if( stringLen != 8 || memcmp( stringPtr, "abcdefgh", 8 ) )
528 		return( FALSE );
529 	stringLen = strStripWhitespace( &stringPtr, "abcdefgh ", 9 );
530 	if( stringLen != 8 || memcmp( stringPtr, "abcdefgh", 8 ) )
531 		return( FALSE );
532 	stringLen = strStripWhitespace( &stringPtr, " abcdefgh ", 10 );
533 	if( stringLen != 8 || memcmp( stringPtr, "abcdefgh", 8 ) )
534 		return( FALSE );
535 	stringLen = strStripWhitespace( &stringPtr, " x abcdefgh ", 12 );
536 	if( stringLen != 10 || memcmp( stringPtr, "x abcdefgh", 10 ) )
537 		return( FALSE );
538 	stringLen = strStripWhitespace( &stringPtr, " abcdefgh x ", 12 );
539 	if( stringLen != 10 || memcmp( stringPtr, "abcdefgh x", 10 ) )
540 		return( FALSE );
541 	stringLen = strStripWhitespace( &stringPtr, "  \t ", 4 );
542 	if( stringLen != -1 || stringPtr != NULL )
543 		return( FALSE );
544 
545 	/* Test strExtract() */
546 	stringLen = strExtract( &stringPtr, "abcdefgh", 4, 8 );
547 	if( stringLen != 4 || memcmp( stringPtr, "efgh", 4 ) )
548 		return( FALSE );
549 	stringLen = strExtract( &stringPtr, "abcd  efgh", 4, 10 );
550 	if( stringLen != 4 || memcmp( stringPtr, "efgh", 4 ) )
551 		return( FALSE );
552 	stringLen = strExtract( &stringPtr, "abcd  efgh  ", 4, 12 );
553 	if( stringLen != 4 || memcmp( stringPtr, "efgh", 4 ) )
554 		return( FALSE );
555 	stringLen = strExtract( &stringPtr, "abcd  efgh  ij  ", 4, 16 );
556 	if( stringLen != 8 || memcmp( stringPtr, "efgh  ij", 8 ) )
557 		return( FALSE );
558 
559 
560 	/* Test strGetNumeric() */
561 	if( strGetNumeric( "0", 1, &value, 0, 10 ) != CRYPT_OK || value != 0 || \
562 		strGetNumeric( "00", 2, &value, 0, 10 ) != CRYPT_OK || value != 0 || \
563 		strGetNumeric( "1234", 4, &value, 0, 2000 ) != CRYPT_OK || value != 1234 || \
564 		strGetNumeric( "1234x", 5, &value, 0, 2000 ) != CRYPT_ERROR_BADDATA || value != 0 || \
565 		strGetNumeric( "x1234", 5, &value, 0, 2000 ) != CRYPT_ERROR_BADDATA || value != 0 || \
566 		strGetNumeric( "1000", 4, &value, 0, 1000 ) != CRYPT_OK || value != 1000 || \
567 		strGetNumeric( "1001", 4, &value, 0, 1000 ) != CRYPT_ERROR_BADDATA || value != 0 )
568 		return( FALSE );
569 
570 	/* Test strGetHex() */
571 	if( strGetHex( "0", 1, &value, 0, 1000 ) != CRYPT_OK || value != 0 || \
572 		strGetHex( "1234", 4, &value, 0, 0x2000 ) != CRYPT_OK || value != 0x1234 || \
573 		strGetHex( "1234x", 5, &value, 0, 0x2000 ) != CRYPT_ERROR_BADDATA || value != 0 || \
574 		strGetHex( "x1234", 5, &value, 0, 0x2000 ) != CRYPT_ERROR_BADDATA || value != 0 || \
575 		strGetHex( "12EE", 4, &value, 0, 0x12EE ) != CRYPT_OK || value != 0x12EE || \
576 		strGetHex( "12EF", 4, &value, 0, 0x12EE ) != CRYPT_ERROR_BADDATA || value != 0 )
577 		return( FALSE );
578 
579 	/* Test sanitiseString() */
580 	memcpy( buffer, "abcdefgh", 8 );
581 	stringPtr = sanitiseString( buffer, 16, 8 );
582 	if( memcmp( stringPtr, "abcdefgh", 9 ) )
583 		return( FALSE );
584 	memcpy( buffer, "abc\x12" "efgh", 8 );
585 	stringPtr = sanitiseString( buffer, 16, 8 );
586 	if( memcmp( stringPtr, "abc.efgh", 9 ) )
587 		return( FALSE );
588 	memcpy( buffer, "abcdefgh", 8 );
589 	stringPtr = sanitiseString( buffer, 7, 8 );
590 	if( memcmp( stringPtr, "abcdef", 7 ) )
591 		return( FALSE );
592 	memcpy( buffer, "abcdefgh", 8 );
593 	stringPtr = sanitiseString( buffer, 8, 8 );
594 	if( memcmp( stringPtr, "abcdefg", 8 ) )
595 		return( FALSE );
596 	memcpy( buffer, "abcdefghij", 10 );
597 	stringPtr = sanitiseString( buffer, 9, 10 );
598 	if( memcmp( stringPtr, "abc[...]", 9 ) )
599 		return( FALSE );
600 	memcpy( buffer, "abcdefghij", 10 );
601 	stringPtr = sanitiseString( buffer, 10, 10 );
602 	if( memcmp( stringPtr, "abcd[...]", 10 ) )
603 		return( FALSE );
604 	memcpy( buffer, "abcdefghij", 10 );
605 	stringPtr = sanitiseString( buffer, 11, 10 );
606 	if( memcmp( stringPtr, "abcdefghij", 11 ) )
607 		return( FALSE );
608 
609 	return( TRUE );
610 	}
611 #endif /* !NDEBUG */
612