EncryptionTest.mm   [plain text]


//
//  EncryptionTest.mm
//  CommonCrypto
//
//  Created by Jim Murphy on 1/13/10.
//  Copyright 2010 Apple. All rights reserved.
//

#import "EncryptionTest.h"

/* Copyright 2006 Apple Computer, Inc.
 *
 * ccSymTest.c - test CommonCrypto symmetric encrypt/decrypt.
 */
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "CommonCryptor.h"
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
#include "RandomNumberService.h"

int DoTesting(CCEncryptionTest* unitTest);

/*
 * Defaults.
 */
#define LOOPS_DEF		500
#define MIN_DATA_SIZE	8
#define MAX_DATA_SIZE	10000						/* bytes */
#define MAX_KEY_SIZE	kCCKeySizeMaxRC4			/* bytes */
#define MAX_BLOCK_SIZE	kCCBlockSizeAES128			/* bytes */
#define LOOP_NOTIFY		250

/*
 * Enumerate algs our own way to allow iteration.
 */
typedef enum {
	ALG_AES_128 = 1,	/* 128 bit block, 128 bit key */
	ALG_AES_192,		/* 128 bit block, 192 bit key */
	ALG_AES_256,		/* 128 bit block, 256 bit key */
	ALG_DES,
	ALG_3DES,
	ALG_CAST,
	ALG_RC4,
	/* these aren't in CommonCrypto (yet?) */
	ALG_RC2,
	ALG_RC5,
	ALG_BFISH,
	ALG_ASC,
	ALG_NULL					/* normally not used */
} SymAlg;
#define ALG_FIRST			ALG_AES_128
#define ALG_LAST			ALG_RC4


@implementation CCEncryptionTest

@synthesize encrAlg = _encrAlg;
@synthesize blockSize = _blockSize;
@synthesize minKeySizeInBytes = _minKeySizeInBytes;
@synthesize maxKeySizeInBytes = _maxKeySizeInBytes;
@synthesize ctxSize = _ctxSize;
@synthesize algName = _algName;
@synthesize testObject = _testObject;
@synthesize testPassed = _testPassed;


+ (NSArray *)setupEncryptionTests:(id<TestToolProtocol>)testObject
{
	NSMutableArray* result = [NSMutableArray array];
	
	// ============================= DES ==========================
	
	CCEncryptionTest* desTest = [[[CCEncryptionTest alloc]
		initWithEncryptionName:@"DES"
		withEncryptionAlgo:kCCAlgorithmDES
		withBlockSize:kCCBlockSizeDES 
		withMinKeySizeInBytes:kCCKeySizeDES
		withMaxKeySizeInBytes:kCCKeySizeDES
		withContextSize:kCCContextSizeDES
		withUnitTest:testObject
		] autorelease];
		
	[result addObject:desTest];
	
	// ============================= 3DES =========================
	
	CCEncryptionTest* des3Test = [[[CCEncryptionTest alloc]
		initWithEncryptionName:@"3DES"
		withEncryptionAlgo:kCCAlgorithm3DES 
		withBlockSize:kCCBlockSize3DES 
		withMinKeySizeInBytes:kCCKeySize3DES
		withMaxKeySizeInBytes:kCCKeySize3DES
		withContextSize:kCCContextSize3DES
		withUnitTest:testObject
		] autorelease];
		
	[result addObject:des3Test];
	
	// ============================ AES128 =========================
	
	CCEncryptionTest* aes128Test = [[[CCEncryptionTest alloc]
		initWithEncryptionName:@"AES128"
		withEncryptionAlgo:kCCAlgorithmAES128 
		withBlockSize:kCCBlockSizeAES128 
		withMinKeySizeInBytes:kCCKeySizeAES128
		withMaxKeySizeInBytes:kCCKeySizeAES128
		withContextSize:kCCContextSizeAES128
		withUnitTest:testObject
		] autorelease];
		
	[result addObject:aes128Test];
	
	// ============================ AES192 =========================
	
	CCEncryptionTest* aes192Test = [[[CCEncryptionTest alloc]
		initWithEncryptionName:@"AES192"
		withEncryptionAlgo:kCCAlgorithmAES128 
		withBlockSize:kCCBlockSizeAES128 
		withMinKeySizeInBytes:kCCKeySizeAES192
		withMaxKeySizeInBytes:kCCKeySizeAES192
		withContextSize:kCCContextSizeAES128
		withUnitTest:testObject
		] autorelease];
		
	[result addObject:aes192Test];
	
	// ============================ AES256 =========================
	
	CCEncryptionTest* aes256Test = [[[CCEncryptionTest alloc]
		initWithEncryptionName:@"AES256"
		withEncryptionAlgo:kCCAlgorithmAES128 
		withBlockSize:kCCBlockSizeAES128 
		withMinKeySizeInBytes:kCCKeySizeAES256
		withMaxKeySizeInBytes:kCCKeySizeAES256
		withContextSize:kCCContextSizeAES128
		withUnitTest:testObject
		] autorelease];
		
	[result addObject:aes256Test];
	
	// ============================= CAST ==========================
	
	CCEncryptionTest* castTest = [[[CCEncryptionTest alloc]
		initWithEncryptionName:@"CAST"
		withEncryptionAlgo:kCCAlgorithmCAST 
		withBlockSize:kCCBlockSizeCAST 
		withMinKeySizeInBytes:kCCKeySizeMinCAST
		withMaxKeySizeInBytes:kCCKeySizeMaxCAST
		withContextSize:kCCContextSizeCAST
		withUnitTest:testObject
		] autorelease];
		
	[result addObject:castTest];
	
	// ============================== RC4 ==========================
	
	CCEncryptionTest* rc4Test = [[[CCEncryptionTest alloc]
		initWithEncryptionName:@"RC4"
		withEncryptionAlgo:kCCAlgorithmRC4 
		withBlockSize:0 
		withMinKeySizeInBytes:kCCKeySizeMinRC4
		withMaxKeySizeInBytes:kCCKeySizeMaxRC4
		withContextSize:kCCContextSizeRC4
		withUnitTest:testObject
		] autorelease];
		
	[result addObject:rc4Test];
	
	return result;
}

- (id)initWithEncryptionName:(NSString *)name 
		withEncryptionAlgo:(CCAlgorithm)encrAlg
		withBlockSize:(uint32)blockSize 
		withMinKeySizeInBytes:(uint32)minKeySizeInBytes
		withMaxKeySizeInBytes:(uint32)maxKeySizeInBytes
		withContextSize:(size_t)ctxSize
		withUnitTest:(id<TestToolProtocol>)testObject
{
	if ((self = [super init]))
	{
		_encrAlg = encrAlg;
		_blockSize = blockSize;
		_minKeySizeInBytes = minKeySizeInBytes;
		_maxKeySizeInBytes = maxKeySizeInBytes;
		_ctxSize = ctxSize;
		_algName = [name copy];
		_testObject = [testObject retain];
		_testPassed = YES;
	}
	return self;
}

- (void)dealloc
{
	[_algName release];
	[_testObject release];
	[super dealloc];
}

- (void)doAssertTest:(BOOL)result errorString:(NSString *)errorStr
{
	if (nil != self.testObject)
	{
		[self.testObject doAssertTest:result errorString:errorStr];
		return;
	}
	
	if (_testPassed)
	{
		_testPassed = result;
	}
}



- (void)runTest
{
	int iResult = DoTesting(self);
	[self doAssertTest:(iResult == 0)  errorString:[NSString stringWithFormat:@"%@ test failed", _algName]];
	
	if (nil == _testObject)
	{
		printf("EncryptionTest: %s\n", (self.testPassed) ? "Passed" : "Failed");
	}
}

@end


static void appGetRandomBytes(void* dest, uint32 numBytes)
{
	NSAutoreleasePool *pool = [NSAutoreleasePool new];
	NSData* tempResult = [[CCRandomNumberService defaultRandomNumberService] generateRandomDataOfSize:numBytes];
	memcpy(dest, [tempResult bytes], numBytes);
	[pool drain];
}


static void printCCError(NSString* str, CCCryptorStatus crtn, id<TestToolProtocol> unitTest)
{
	NSString* errStr;
	
	switch(crtn) 
	{
		case kCCSuccess: errStr = @"kCCSuccess"; break;
		case kCCParamError: errStr = @"kCCParamError"; break;
		case kCCBufferTooSmall: errStr = @"kCCBufferTooSmall"; break;
		case kCCMemoryFailure: errStr = @"kCCMemoryFailure"; break;
		case kCCAlignmentError: errStr = @"kCCAlignmentError"; break;
		case kCCDecodeError: errStr = @"kCCDecodeError"; break;
		case kCCUnimplemented: errStr = @"kCCUnimplemented"; break;
		default:
			errStr = [NSString stringWithFormat:@"Unknown(%ld)", (long)crtn];
			break;
	}
	NSString* outputStr = nil;
	if (NULL != str)
	{
		outputStr = [NSString stringWithFormat:@"%@ %@", str, errStr];
	}
	else
	{
		outputStr = errStr;
	}
	
	[unitTest doAssertTest:NO errorString:outputStr];
}

/* max context size */
#define CC_MAX_CTX_SIZE	kCCContextSizeRC4

/* 
 * We write a marker at end of expected output and at end of caller-allocated 
 * CCCryptorRef, and check at the end to make sure they weren't written 
 */
#define MARKER_LENGTH	8
#define MARKER_BYTE		0x7e

/* 
 * Test harness for CCCryptor with lots of options. 
 */
CCCryptorStatus doCCCrypt(
	bool forEncrypt,
	CCAlgorithm encrAlg,			
	bool doCbc,
	bool doPadding,
	const void *keyBytes, size_t keyLen,
	const void *iv,
	bool randUpdates,
	bool inPlace,								/* !doPadding only */
	size_t ctxSize,								/* if nonzero, we allocate ctx */
	bool askOutSize,
	const uint8_t *inText, size_t inTextLen,
	uint8_t **outText, size_t *outTextLen, /* both returned, WE malloc */
	id<TestToolProtocol> unitTest)		
{
	CCCryptorRef	cryptor = NULL;
	CCCryptorStatus crtn;
	CCOperation		op = forEncrypt ? kCCEncrypt : kCCDecrypt;
	CCOptions		options = 0;
	uint8_t			*outBuf = NULL;			/* mallocd output buffer */
	uint8_t			*outp;					/* running ptr into outBuf */
	const uint8		*inp;					/* running ptr into inText */
	size_t			outLen;					/* bytes remaining in outBuf */
	size_t			toMove;					/* bytes remaining in inText */
	size_t			thisMoveOut;			/* output from CCCryptUpdate()/CCCryptFinal() */
	size_t			outBytes;				/* total bytes actually produced in outBuf */
	char			ctx[CC_MAX_CTX_SIZE];	/* for CCCryptorCreateFromData() */
	uint8_t			*textMarker = NULL;		/* 8 bytes of marker here after expected end of 
											 * output */
	char			*ctxMarker = NULL;		/* ditto for caller-provided context */
	unsigned		dex;
	size_t			askedOutSize;			/* from the lib */
	size_t			thisOutLen;				/* dataOutAvailable we use */
	
	
	if(!doCbc) 
	{
		options |= kCCOptionECBMode;
	}
	
	if(doPadding) 
	{
		options |= kCCOptionPKCS7Padding;
	}
	
	/* just hack this one */
	outLen = inTextLen;
	if(forEncrypt) 
	{
		outLen += MAX_BLOCK_SIZE;
	}
	
	outBuf = (uint8_t *)malloc(outLen + MARKER_LENGTH);
	
	/* library should not touch this memory */
	textMarker = outBuf + outLen;
	memset(textMarker, MARKER_BYTE, MARKER_LENGTH);
	
	/* subsequent errors to errOut: */

	if(inPlace) 
	{
		memmove(outBuf, inText, inTextLen);
		inp = outBuf;
	}
	else 
	{
		inp = inText;
	}

	if(!randUpdates) 
	{
		/* one shot */
		if(askOutSize) 
		{
			crtn = CCCrypt(op, encrAlg, options,
				keyBytes, keyLen, iv,
				inp, inTextLen,
				outBuf, 0, &askedOutSize);
			if(crtn != kCCBufferTooSmall) 
			{
				NSString* errStr = [NSString stringWithFormat:@"CCCrypt: ***Did not get kCCBufferTooSmall as expected\n  alg %d inTextLen %lu cbc %d padding %d keyLen %lu",
					(int)encrAlg, (unsigned long)inTextLen, (int)doCbc, (int)doPadding,
					(unsigned long)keyLen];
					
				printCCError(errStr, crtn, unitTest);
				crtn = -1;
				goto errOut;
			}
			outLen = askedOutSize;
		}
		crtn = CCCrypt(op, encrAlg, options,
			keyBytes, keyLen, iv,
			inp, inTextLen,
			outBuf, outLen, &outLen);
		if(crtn) 
		{
			printCCError(@"CCCrypt", crtn, unitTest);
			goto errOut;
		}
        
        [unitTest doAssertTest:(outLen != 0) errorString:@"output length should be non-zero for encryption operation"];
		*outText = outBuf;
		*outTextLen = outLen;
		goto errOut;
	}
	
	/* random multi updates */
	if(ctxSize) {
		size_t ctxSizeCreated;
		
		if(askOutSize) 
		{
			crtn = CCCryptorCreateFromData(op, encrAlg, options,
				keyBytes, keyLen, iv,
				ctx, 0 /* ctxSize */,
				&cryptor, &askedOutSize);
			if(crtn != kCCBufferTooSmall) 
			{
				printCCError(@"CCCryptorCreateFromData: ***Did not get kCCBufferTooSmall as expected", crtn, unitTest);
				crtn = -1;
				goto errOut;
			}
			ctxSize = askedOutSize;
		}
		crtn = CCCryptorCreateFromData(op, encrAlg, options,
			keyBytes, keyLen, iv,
			ctx, ctxSize, &cryptor, &ctxSizeCreated);
		if(crtn) 
		{
			printCCError(@"CCCryptorCreateFromData", crtn, unitTest);
			return crtn;
		}
		ctxMarker = ctx + ctxSizeCreated;
		memset(ctxMarker, MARKER_BYTE, MARKER_LENGTH);
	}
	else 
	{
		crtn = CCCryptorCreate(op, encrAlg, options,
			keyBytes, keyLen, iv,
			&cryptor);
		if(crtn) 
		{
			printCCError(@"CCCryptorCreate", crtn, unitTest);
			return crtn;
		}
	}
	
	toMove = inTextLen;		/* total to go */
	outp = outBuf;
	outBytes = 0;			/* bytes actually produced in outBuf */
	
	while(toMove) 
	{
		uint32 thisMoveIn;			/* input to CCryptUpdate() */
		
		thisMoveIn = [[CCRandomNumberService defaultRandomNumberService] 
			generateRandomNumberInRange:1 toMax:toMove];
		if(askOutSize) 
		{
			thisOutLen = CCCryptorGetOutputLength(cryptor, thisMoveIn, false);
		}
		else 
		{
			thisOutLen = outLen;
		}
		crtn = CCCryptorUpdate(cryptor, inp, thisMoveIn,
			outp, thisOutLen, &thisMoveOut);
		if(crtn) 
		{
			printCCError(@"CCCryptorUpdate", crtn, unitTest);
			goto errOut;
		}
		inp			+= thisMoveIn;
		toMove		-= thisMoveIn;
		outp		+= thisMoveOut;
		outLen   	-= thisMoveOut;
		outBytes	+= thisMoveOut;
	}
	
	if(doPadding) 
	{
		/* Final is not needed if padding is disabled */
		if(askOutSize) 
		{
			thisOutLen = CCCryptorGetOutputLength(cryptor, 0, true);
		}
		else 
		{
			thisOutLen = outLen;
		}
		crtn = CCCryptorFinal(cryptor, outp, thisOutLen, &thisMoveOut);
	}
	else 
	{
		thisMoveOut = 0;
		crtn = kCCSuccess;
	}
	
	if(crtn) 
	{
		printCCError(@"CCCryptorFinal", crtn, unitTest);
		goto errOut;
	}
	
	outBytes += thisMoveOut;
	*outText = outBuf;
	*outTextLen = outBytes;
	crtn = kCCSuccess;

	for(dex=0; dex<MARKER_LENGTH; dex++) 
	{
		if(textMarker[dex] != MARKER_BYTE) 
		{
			[unitTest doAssertTest:NO errorString:[NSString stringWithFormat:@"***lib scribbled on our textMarker memory (op=%s)!\n",
				forEncrypt ? "encrypt" : "decrypt"]];
			crtn = (CCCryptorStatus)-1;
		}
	}
	if(ctxSize) 
	{
		for(dex=0; dex<MARKER_LENGTH; dex++) 
		{
			if(ctxMarker[dex] != MARKER_BYTE) 
			{
				[unitTest doAssertTest:NO errorString:[NSString stringWithFormat:@"***lib scribbled on our ctxMarker memory (op=%s)!\n",
					forEncrypt ? "encrypt" : "decrypt"]];
				crtn = (CCCryptorStatus)-1;
			}
		}
	}
	
errOut:
	if(crtn) 
	{
		if(outBuf) 
		{
			free(outBuf);
		}
	}
	if(cryptor) 
	{
		CCCryptorRelease(cryptor);
	}
	return crtn;
}

static int doTest(const uint8_t *ptext,
	size_t ptextLen,
	CCAlgorithm encrAlg,			
	bool doCbc,
	bool doPadding,
	bool nullIV,			/* if CBC, use NULL IV */
	uint32 keySizeInBytes,
	bool stagedEncr,
	bool stagedDecr,
	bool inPlace,	
	size_t ctxSize,		
	bool askOutSize,
	bool quiet,
	id<TestToolProtocol> unitTest)
{
	uint8_t			keyBytes[MAX_KEY_SIZE];
	uint8_t			iv[MAX_BLOCK_SIZE];
	uint8_t			*ivPtrEncrypt;
	uint8_t			*ivPtrDecrypt;
	uint8_t			*ctext = NULL;		/* mallocd by doCCCrypt */
	size_t			ctextLen = 0;
	uint8_t			*rptext = NULL;		/* mallocd by doCCCrypt */
	size_t			rptextLen;
	CCCryptorStatus	crtn;
	int				rtn = 0;
	
	/* random key */
	appGetRandomBytes(keyBytes, keySizeInBytes);
	
	/* random IV if needed */
	if(doCbc) 
	{
		if(nullIV) 
		{
			memset(iv, 0, MAX_BLOCK_SIZE);
			
			/* flip a coin, give one side NULL, the other size zeroes */
			
			if ([[CCRandomNumberService defaultRandomNumberService] 
						generateRandomNumberInRange:1 toMax:2] == 1)
			{
				ivPtrEncrypt = NULL;
				ivPtrDecrypt = iv;
			}
			else 
			{
				ivPtrEncrypt = iv;
				ivPtrDecrypt = NULL;
			}
		}
		else 
		{
			appGetRandomBytes(iv, MAX_BLOCK_SIZE);
			ivPtrEncrypt = iv;
			ivPtrDecrypt = iv;
		}
	}	
	else 
	{
		ivPtrEncrypt = NULL;
		ivPtrDecrypt = NULL;
	}

	crtn = doCCCrypt(true, encrAlg, doCbc, doPadding,
		keyBytes, keySizeInBytes, ivPtrEncrypt,
		stagedEncr, inPlace, ctxSize, askOutSize,
		ptext, ptextLen,
		&ctext, &ctextLen, unitTest);
	if(crtn) 
	{
		rtn = 1;
		goto abort;
	}
		
	crtn = doCCCrypt(false, encrAlg, doCbc, doPadding,
		keyBytes, keySizeInBytes, ivPtrDecrypt,
		stagedDecr, inPlace, ctxSize, askOutSize,
		ctext, ctextLen,
		&rptext, &rptextLen, unitTest);
	if(crtn) 
	{
		rtn = 1;
		goto abort;
	}
	
	/* compare ptext, rptext */
	if(ptextLen != rptextLen) 
	{
		NSString* errStr = [NSString stringWithFormat:@"Ptext length mismatch: expect %lu, got %lu\n", ptextLen, rptextLen];
		[unitTest doAssertTest:NO errorString:errStr];
		rtn = 1;
		goto abort;
		
	}
	
	if(memcmp(ptext, rptext, ptextLen)) 
	{
		[unitTest doAssertTest:NO errorString:@"***data miscompare"];
		rtn = 1;
	}
	
abort:
	if(ctext) 
	{
		free(ctext);
	}
	if(rptext) 
	{
		free(rptext);
	}
	return rtn;
}

bool isBitSet(unsigned bit, unsigned word) 
{
	if(bit > 31) 
	{
		NSLog(@"We don't have that many bits");
		exit(1);
	}
	unsigned mask = 1 << bit;
	return (word & mask) ? true : false;
}

int DoTesting(CCEncryptionTest* unitTest)
{
	unsigned			loop;
	uint8				*ptext;
	size_t				ptextLen;
	bool				stagedEncr;
	bool				stagedDecr;
	bool				doPadding;
	bool				doCbc;
	bool				nullIV;
	const char			*algStr;
	CCAlgorithm			encrAlg;	
	uint32				minKeySizeInBytes;
	uint32				maxKeySizeInBytes;
	uint32				keySizeInBytes;
	int					rtn = 0;
	uint32				blockSize;		// for noPadding case
	size_t				ctxSize;		// always set per alg
	size_t				ctxSizeUsed;	// passed to doTest
	bool				askOutSize;		// inquire output size each op
	
	/*
	 * User-spec'd params
	 */
	bool		keySizeSpec = false;		// false: use rand key size
	unsigned	loops = LOOPS_DEF;
	size_t		minPtextSize = MIN_DATA_SIZE;
	size_t		maxPtextSize = MAX_DATA_SIZE;
	bool		quiet = false;
	bool		paddingSpec = false;		// true: user calls doPadding, const
	bool		cbcSpec = false;			// ditto for doCbc
	bool		stagedSpec = false;			// ditto for stagedEncr and stagedDecr
	bool		inPlace = false;			// en/decrypt in place for ECB
	bool		allocCtxSpec = false;		// use allocCtx
	bool		allocCtx = false;			// allocate context ourself
	

	ptext = (uint8 *)malloc(maxPtextSize);
	if(ptext == NULL) 
	{
		[unitTest doAssertTest:NO errorString:@"Insufficient heap space"];
		exit(1);
	}
	/* ptext length set in test loop */
	
	/* Set up the values for this test from the object */	
	encrAlg = unitTest.encrAlg;
	blockSize = unitTest.blockSize;
	minKeySizeInBytes = unitTest.minKeySizeInBytes;
	maxKeySizeInBytes = unitTest.maxKeySizeInBytes;
	ctxSize = unitTest.ctxSize;
	algStr = [unitTest.algName UTF8String];		
		
	for(loop=1; ; loop++) 
	{
		ptextLen = [[CCRandomNumberService defaultRandomNumberService] 
			generateRandomNumberInRange:minPtextSize toMax:maxPtextSize];
		appGetRandomBytes(ptext, ptextLen);
		
		/* per-loop settings */
		if(!keySizeSpec) 
		{
			if(minKeySizeInBytes == maxKeySizeInBytes) 
			{
				keySizeInBytes = minKeySizeInBytes;
			}
			else 
			{
				keySizeInBytes = [[CCRandomNumberService defaultRandomNumberService] 
					generateRandomNumberInRange:minKeySizeInBytes toMax:maxKeySizeInBytes];
			}
		}
		if(blockSize == 0) 
		{
			/* stream cipher */
			doCbc = false;
			doPadding = false;
		}
		else 
		{
			if(!cbcSpec) 
			{
				doCbc = isBitSet(0, loop);
			}
			if(!paddingSpec) 
			{
				doPadding = isBitSet(1, loop);
			}
		}
		if(!doPadding && (blockSize != 0)) 
		{
			/* align plaintext */
			ptextLen = (ptextLen / blockSize) * blockSize;
			if(ptextLen == 0) 
			{
				ptextLen = blockSize;
			}
		}
		if(!stagedSpec) 
		{
			stagedEncr = isBitSet(2, loop);
			stagedDecr = isBitSet(3, loop);
		}
		if(doCbc) 
		{
			nullIV = isBitSet(4, loop);
		}
		else 
		{
			nullIV = false;
		}
		inPlace = isBitSet(5, loop);
		if(allocCtxSpec) 
		{
			ctxSizeUsed = allocCtx ? ctxSize : 0;
		}
		else if(isBitSet(6, loop)) 
		{
			ctxSizeUsed = ctxSize;
		}
		else 
		{
			ctxSizeUsed = 0;
		}
		askOutSize = isBitSet(7, loop);
		
		
		if(doTest(ptext, ptextLen,
				encrAlg, doCbc, doPadding, nullIV,
				keySizeInBytes,
				stagedEncr,	stagedDecr, inPlace, ctxSizeUsed, askOutSize,
				quiet, unitTest)) 
		{
			rtn = 1;
			break;
		}
		
		if(loops && (loop == loops)) 
		{
			break;
		}
		
		if(rtn) 
		{
			break;
		}
		
	}	/* for algs */
	
	free(ptext);
	return rtn;
}