cryptoplugins/cryptospiplugins/source/softwarecrypto/symmetriccipherimpl.cpp
changeset 17 cd501b96611d
equal deleted inserted replaced
15:da2ae96f639b 17:cd501b96611d
       
     1 /*
       
     2 * Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include "symmetriccipherimpl.h"
       
    20 
       
    21 #include <e32def.h>
       
    22 #include <cryptostrength.h>
       
    23 #include <cryptospi/cryptospidef.h>
       
    24 #include "keys.h"
       
    25 #include <cryptopanic.h>
       
    26 #include <cryptospi/plugincharacteristics.h>
       
    27 #include "pluginconfig.h"
       
    28 #include <securityerr.h>
       
    29 #include "common/inlines.h"
       
    30 
       
    31 using namespace SoftwareCrypto;
       
    32 
       
    33 //
       
    34 // Implementation of Symmetric Cipher class
       
    35 //
       
    36 CSymmetricCipherImpl::CSymmetricCipherImpl() 
       
    37 	{
       
    38 	}
       
    39 
       
    40 void CSymmetricCipherImpl::ConstructL(const CKey& aKey) 
       
    41 	{
       
    42 	DoSetKeyL(aKey);		
       
    43 	}
       
    44 	
       
    45 void CSymmetricCipherImpl::SecureDelete(HBufC8*& aBuffer)
       
    46 	{
       
    47 	if (aBuffer)
       
    48 		{
       
    49 		aBuffer->Des().FillZ();
       
    50 		}
       
    51 	delete aBuffer;
       
    52 	aBuffer = 0;	
       
    53 	}
       
    54 
       
    55 CSymmetricCipherImpl::~CSymmetricCipherImpl()
       
    56 	{			
       
    57 	SecureDelete(iKey);	
       
    58 	}
       
    59 		
       
    60 void CSymmetricCipherImpl::Close()
       
    61 	{
       
    62 	delete this;
       
    63 	}
       
    64 	
       
    65 TAny* CSymmetricCipherImpl::GetExtension(TUid /*aExtensionId*/) 
       
    66 	{
       
    67 	return 0;
       
    68 	}
       
    69 	
       
    70 void CSymmetricCipherImpl::GetCharacteristicsL(const TAny*& aPluginCharacteristics)
       
    71 	{
       
    72 	TInt numCiphers = sizeof(KSymmetricCipherCharacteristics)/sizeof(TSymmetricCipherCharacteristics*);
       
    73 	TInt32 implUid = ImplementationUid().iUid;
       
    74 	for (TInt i = 0; i < numCiphers; ++i)
       
    75 		{
       
    76 		if (KSymmetricCipherCharacteristics[i]->cmn.iImplementationUID == implUid)
       
    77 			{
       
    78 			aPluginCharacteristics = KSymmetricCipherCharacteristics[i];
       
    79 			break;
       
    80 			}
       
    81 		}	
       
    82 	}
       
    83 
       
    84 TInt CSymmetricCipherImpl::GetKeyStrength() const
       
    85 	{
       
    86 	return BytesToBits(iKey->Length());
       
    87 	}
       
    88 	
       
    89 HBufC8* CSymmetricCipherImpl::ExtractKeyDataLC(const CKey& aKey) const
       
    90 	{
       
    91 	const TDesC8& keyContent = aKey.GetTDesC8L(KSymmetricKeyParameterUid);
       
    92 	return keyContent.AllocLC();
       
    93 	}
       
    94 
       
    95 TInt CSymmetricCipherImpl::KeySize() const
       
    96 	{
       
    97 	// return key size in BITS
       
    98 	return BytesToBits(iKeyBytes);
       
    99 	}
       
   100 
       
   101 void CSymmetricCipherImpl::DoSetKeyL(const CKey& aKey)
       
   102 	{
       
   103 	HBufC8* key = ExtractKeyDataLC(aKey);
       
   104 	TInt keyLength(key->Length());
       
   105 	
       
   106 	TCrypto::IsSymmetricWeakEnoughL(BytesToBits(keyLength));
       
   107 	if (! IsValidKeyLength(keyLength))
       
   108 		{
       
   109 		CleanupStack::PopAndDestroy(key);
       
   110 		User::Leave(KErrNotSupported);
       
   111 		}
       
   112 	
       
   113 	SecureDelete(iKey);	
       
   114 	CleanupStack::Pop(key);
       
   115 	iKey = key;
       
   116 	iKeyBytes = keyLength;
       
   117 	}	
       
   118 
       
   119 //
       
   120 // Implementation of Symmetric Stream Cipher
       
   121 //
       
   122 CSymmetricStreamCipherImpl::CSymmetricStreamCipherImpl()
       
   123 	{
       
   124 	}
       
   125 
       
   126 CSymmetricStreamCipherImpl::~CSymmetricStreamCipherImpl()
       
   127 	{
       
   128 	}
       
   129 
       
   130 void CSymmetricStreamCipherImpl::SetKeyL(const CKey& aKey)
       
   131 	{
       
   132 	DoSetKeyL(aKey);
       
   133 	TCrypto::IsSymmetricWeakEnoughL(GetKeyStrength());
       
   134 	Reset();
       
   135 	}	
       
   136 
       
   137 void CSymmetricStreamCipherImpl::ConstructL(const CKey& aKey) 
       
   138 	{
       
   139 	CSymmetricCipherImpl::ConstructL(aKey);
       
   140 	}
       
   141 
       
   142 TInt CSymmetricStreamCipherImpl::BlockSize() const
       
   143 	{
       
   144 	// return block size in BITS
       
   145 	return BYTE_BITS;
       
   146 	}
       
   147 
       
   148 void CSymmetricStreamCipherImpl::SetCryptoModeL(TUid /*aCryptoMode*/)
       
   149 	{
       
   150 	// Call the reset method.
       
   151 	Reset();
       
   152 	}
       
   153 	
       
   154 TInt CSymmetricStreamCipherImpl::MaxOutputLength(TInt aInputLength) const
       
   155 	{
       
   156 	return aInputLength;	
       
   157 	}
       
   158 	
       
   159 TInt CSymmetricStreamCipherImpl::MaxFinalOutputLength(TInt aInputLength) const
       
   160 	{
       
   161 	return aInputLength;	
       
   162 	}
       
   163 	
       
   164 void CSymmetricStreamCipherImpl::ProcessL(const TDesC8& aInput, TDes8& aOutput)
       
   165 	{
       
   166 	TInt outputIndex = aOutput.Size();
       
   167 
       
   168 	// aOutput may already have outputIndex bytes of data in it
       
   169 	// check there will still be enough space to process the result
       
   170 	__ASSERT_DEBUG(aOutput.MaxLength() - outputIndex >= MaxOutputLength(aInput.Length()), User::Panic(KCryptoPanic, ECryptoPanicOutputDescriptorOverflow));
       
   171 
       
   172 	aOutput.Append(aInput);
       
   173 
       
   174 	TPtr8 transformBuf((TUint8*)(aOutput.Ptr()) + outputIndex, aInput.Size(),
       
   175 		aInput.Size());
       
   176 	DoProcess(transformBuf);
       
   177 	}
       
   178 
       
   179 void CSymmetricStreamCipherImpl::ProcessFinalL(const TDesC8& aInput, TDes8& aOutput)
       
   180 	{
       
   181 	ProcessL(aInput, aOutput);	
       
   182 	}
       
   183 
       
   184 //
       
   185 // Implementation of Symmetric Block Cipher
       
   186 //
       
   187 CSymmetricBlockCipherImpl::CSymmetricBlockCipherImpl(
       
   188 	TUint8 aBlockBytes,
       
   189 	TUid aCryptoMode,
       
   190 	TUid aOperationMode,
       
   191 	TUid aPaddingMode) :
       
   192 	iBlockBytes(aBlockBytes),
       
   193 	iCryptoMode(aCryptoMode),
       
   194 	iOperationMode(aOperationMode),
       
   195 	iPaddingMode(aPaddingMode),
       
   196 	iBufferedPlaintextPtr(0,0,0),
       
   197 	iCtrUnusedKeystreamPtr(0,0,0)
       
   198 	{
       
   199 	}
       
   200 
       
   201 CSymmetricBlockCipherImpl::~CSymmetricBlockCipherImpl()
       
   202 	{			
       
   203 	delete iPadding;
       
   204 	delete [] iRegister;
       
   205 	delete [] iCurrentCipherText;
       
   206 	delete iBufferedPlaintext;
       
   207 	delete iCtrUnusedKeystream;
       
   208 	iIv.Close();
       
   209 	iInputStore.Close();
       
   210 	iPaddingBlock.Close();	
       
   211 	}
       
   212 
       
   213 
       
   214 void CSymmetricBlockCipherImpl::ConstructL(const CKey& aKey) 
       
   215 	{
       
   216 	CSymmetricCipherImpl::ConstructL(aKey);
       
   217 	DoSetOperationModeL(iOperationMode);
       
   218 	DoSetCryptoModeL(iCryptoMode);	
       
   219 	DoSetPaddingModeL(iPaddingMode);
       
   220 	
       
   221 	iInputStore.ReAllocL(iBlockBytes);
       
   222 	iPaddingBlock.ReAllocL(iBlockBytes);
       
   223 
       
   224 	iRegister = new(ELeave) TUint32[iBlockBytes/4];	
       
   225 	iRegisterPtr = reinterpret_cast<TUint8*>(iRegister);
       
   226 
       
   227 	iCurrentCipherText = new(ELeave) TUint32[iBlockBytes/4];	
       
   228 	iCurrentCipherTextPtr = reinterpret_cast<TUint8*>(iCurrentCipherText);
       
   229 	
       
   230 	iBufferedPlaintext = HBufC8::NewL(iBlockBytes);
       
   231 	iBufferedPlaintextPtr.Set(iBufferedPlaintext->Des());
       
   232 	
       
   233 	iCtrUnusedKeystream = HBufC8::NewL(iBlockBytes);
       
   234 	iCtrUnusedKeystreamPtr.Set(iCtrUnusedKeystream->Des());
       
   235 	}
       
   236 
       
   237 void CSymmetricBlockCipherImpl::Reset()
       
   238 	{
       
   239 	iInputStore.Zero();
       
   240 	iPaddingBlock.Zero();
       
   241 	iCtrUnusedKeystreamPtr.Zero();
       
   242 	
       
   243 	if (iOperationMode.iUid == KOperationModeCBC)
       
   244 		{
       
   245 		// only copy the IV if it is already set
       
   246 		if (iIv.MaxLength() > 0)
       
   247 			{
       
   248 			Mem::Copy(iRegisterPtr, &iIv[0], iBlockBytes);
       
   249 			}
       
   250 		}
       
   251 	}	
       
   252 
       
   253 void CSymmetricBlockCipherImpl::SetKeyL(const CKey& aKey)
       
   254 	{
       
   255 	DoSetKeyL(aKey);
       
   256 	TCrypto::IsSymmetricWeakEnoughL(GetKeyStrength());
       
   257 	SetKeySchedule();
       
   258 	Reset();
       
   259 	}
       
   260 
       
   261 void CSymmetricBlockCipherImpl::SetOperationModeL(TUid aOperationMode)
       
   262 	{
       
   263 	DoSetOperationModeL(aOperationMode);
       
   264 	Reset();
       
   265 	}
       
   266 	
       
   267 void CSymmetricBlockCipherImpl::SetCryptoModeL(TUid aCryptoMode)
       
   268 	{
       
   269 	DoSetCryptoModeL(aCryptoMode);
       
   270 	SetKeySchedule();
       
   271 	Reset();
       
   272 	}
       
   273 	
       
   274 void CSymmetricBlockCipherImpl::SetPaddingModeL(TUid aPaddingMode)
       
   275 	{
       
   276 	DoSetPaddingModeL(aPaddingMode);
       
   277 	Reset();
       
   278 	}
       
   279 	
       
   280 void CSymmetricBlockCipherImpl::SetIvL(const TDesC8& aIv)
       
   281 	{
       
   282 	if ((iOperationMode.iUid != KOperationModeCBC) && (iOperationMode.iUid != KOperationModeCTR))
       
   283 		{
       
   284 		User::Leave(KErrNotSupported);
       
   285 		}
       
   286 	DoSetIvL(aIv);
       
   287 	Reset();
       
   288 	}
       
   289 
       
   290 void CSymmetricBlockCipherImpl::DoSetOperationModeL(TUid aOperationMode)
       
   291 	{
       
   292 	switch (aOperationMode.iUid)
       
   293 		{
       
   294 		case KOperationModeNone:
       
   295 		case KOperationModeECB:
       
   296 		case KOperationModeCBC:
       
   297 			break;
       
   298 		case KOperationModeCTR:
       
   299 			SetCryptoModeL(KCryptoModeEncryptUid);
       
   300 			break;
       
   301 		default:
       
   302 			User::Leave(KErrNotSupported);
       
   303 		}
       
   304 	iOperationMode = aOperationMode;		
       
   305 	}
       
   306 
       
   307 void CSymmetricBlockCipherImpl::DoSetCryptoModeL(TUid aCryptoMode)
       
   308 	{
       
   309 	switch (aCryptoMode.iUid)
       
   310 		{
       
   311 		case KCryptoModeEncrypt:
       
   312 			break;
       
   313 		case KCryptoModeDecrypt:
       
   314 			if (iOperationMode.iUid == KOperationModeCTR)
       
   315 				{
       
   316 				return;
       
   317 				}
       
   318 			break;
       
   319 		default:
       
   320 			User::Leave(KErrNotSupported);
       
   321 		}
       
   322 	iCryptoMode = aCryptoMode;		
       
   323 	}
       
   324 
       
   325 void CSymmetricBlockCipherImpl::DoSetPaddingModeL(TUid aPaddingMode)
       
   326 	{
       
   327 	CPadding* padding(0);
       
   328 	switch (aPaddingMode.iUid)
       
   329 		{
       
   330 		case KPaddingModeNone:
       
   331 			padding = CPaddingNone::NewL(iBlockBytes);
       
   332 		break;
       
   333 		case KPaddingModeSSLv3:
       
   334 			padding = CPaddingSSLv3::NewL(iBlockBytes);
       
   335 		break;
       
   336 		case KPaddingModePKCS7:
       
   337 			padding = CPaddingPKCS7::NewL(iBlockBytes);
       
   338 		break;
       
   339 		default:
       
   340 			User::Leave(KErrNotSupported);
       
   341 		}
       
   342 	delete iPadding;
       
   343 	iPadding = padding;
       
   344 	iPaddingMode = aPaddingMode;
       
   345 	}	
       
   346 
       
   347 void CSymmetricBlockCipherImpl::DoSetIvL(const TDesC8& aIv)
       
   348 	{
       
   349 	iIv.ReAllocL(iBlockBytes);
       
   350 	iIv.SetLength(iBlockBytes);
       
   351 
       
   352 	iIv.Zero();
       
   353 	if (aIv.Length() != iBlockBytes) 
       
   354 		{
       
   355 		User::Leave(KErrArgument);
       
   356 		}
       
   357 	iIv = aIv;
       
   358 	Mem::Copy(iRegisterPtr, &iIv[0], iBlockBytes);	//for CTR mode
       
   359 
       
   360 	}	
       
   361 
       
   362 TInt CSymmetricBlockCipherImpl::BlockSize() const
       
   363 	{
       
   364 	// return block size in BITS
       
   365 	if (iOperationMode.iUid == KOperationModeCTR)
       
   366 		{
       
   367 		return 8;
       
   368 		}
       
   369 	else
       
   370 		{
       
   371 		return BytesToBits(iBlockBytes);
       
   372 		}
       
   373 	}
       
   374 
       
   375 TInt CSymmetricBlockCipherImpl::MaxOutputLength(TInt aInputLength) const
       
   376 	{	
       
   377 	if (iOperationMode.iUid == KOperationModeCTR)
       
   378 		{
       
   379 		return aInputLength;
       
   380 		}
       
   381 	else
       
   382 		{
       
   383 		// The maximum output length required for Process is equal to the
       
   384 		// size of the number of whole input blocks available.
       
   385 		//
       
   386 		// The block bytes is a power of two so we can use this to avoid
       
   387 		// doing a real mod operation
       
   388 		TUint inputStoreLength(iInputStore.Length());
       
   389 		TInt rem = (aInputLength + inputStoreLength) & (iBlockBytes - 1);
       
   390 		return (aInputLength + inputStoreLength - rem);
       
   391 		}
       
   392 	}	
       
   393 
       
   394 TInt CSymmetricBlockCipherImpl::MaxFinalOutputLength(TInt aInputLength) const
       
   395 	{
       
   396 	if (iOperationMode.iUid == KOperationModeCTR)
       
   397 		{
       
   398 		return aInputLength;
       
   399 		}
       
   400 	else if (iCryptoMode.iUid == KCryptoModeEncrypt)
       
   401 		{
       
   402 		return iPadding->MaxPaddedLength(iInputStore.Length() + aInputLength);
       
   403 		}
       
   404 	else
       
   405 		{
       
   406 		return iPadding->MaxUnPaddedLength(aInputLength + iInputStore.Size());
       
   407 		}
       
   408 	}
       
   409 
       
   410 void CSymmetricBlockCipherImpl::ProcessL(const TDesC8& aInput, TDes8& aOutput)
       
   411 	{
       
   412 	// if we're running in CBC or CTR mode then we must have an IV set before we can 
       
   413 	// do any processing ie call SetIvL() before this method
       
   414 	if ((iOperationMode.iUid == KOperationModeCBC) || (iOperationMode.iUid == KOperationModeCTR))
       
   415 		{
       
   416 		if (iIv.MaxLength() == 0)
       
   417 			{
       
   418 			User::Leave(KErrNotSupported);
       
   419 			}
       
   420 		}
       
   421 
       
   422 	TInt inputLength(aInput.Length());	
       
   423 	TInt inputStoreLength(iInputStore.Length());
       
   424 	
       
   425 	if (MaxOutputLength(inputLength) > aOutput.MaxLength())
       
   426 		{
       
   427 		User::Leave(KErrOverflow);
       
   428 		}	
       
   429 
       
   430 	if (iOperationMode.iUid == KOperationModeCTR)
       
   431 		{
       
   432 		ProcessCtrL(aInput, aOutput);
       
   433 		}	
       
   434 	else
       
   435 		{
       
   436 		TUint8 blockSizeLog = CryptoLog2(iBlockBytes);
       
   437 		TInt wholeBlocks = (inputLength + inputStoreLength) >> blockSizeLog; 
       
   438 		TInt wholeBlocksSize = wholeBlocks << blockSizeLog;
       
   439 	
       
   440 		if (wholeBlocks)
       
   441 			{
       
   442 			TInt outputLength(aOutput.Length());
       
   443 
       
   444 			if (inputStoreLength > 0)
       
   445 				{
       
   446 				aOutput.Append(iInputStore);
       
   447 				iInputStore.Zero();
       
   448 				}
       
   449 			aOutput.Append(aInput.Left(wholeBlocksSize - inputStoreLength));
       
   450 			Transform(const_cast<TUint8*>(aOutput.Ptr()) + outputLength, wholeBlocks);
       
   451 			}
       
   452 		
       
   453 		TInt remainingBytes = inputLength + inputStoreLength - wholeBlocksSize;
       
   454 		if (remainingBytes > 0)
       
   455 			{		
       
   456 			iInputStore.Append(aInput.Right(remainingBytes));
       
   457 			}
       
   458 		}
       
   459 	}
       
   460 		
       
   461 void CSymmetricBlockCipherImpl::ProcessFinalL(const TDesC8& aInput, TDes8& aOutput)
       
   462 	{
       
   463 	if (iOperationMode.iUid == KOperationModeCTR)
       
   464 		{
       
   465 		ProcessL(aInput, aOutput);
       
   466 		}
       
   467 	else
       
   468 		{
       
   469 		// if we're running in CBC mode then we must have an IV set before we can 
       
   470 		// do any processing ie call SetIvL() before this method
       
   471 		if (iOperationMode.iUid == KOperationModeCBC)
       
   472 			{
       
   473 			if (iIv.MaxLength() == 0)
       
   474 				{
       
   475 				User::Leave(KErrNotSupported);
       
   476 				}
       
   477 			}
       
   478 
       
   479 		if (iCryptoMode.iUid == KCryptoModeEncrypt)
       
   480 			{
       
   481 			return DoProcessFinalEncryptL(aInput, aOutput);
       
   482 			}
       
   483 		else
       
   484 			{
       
   485 			return DoProcessFinalDecryptL(aInput, aOutput);
       
   486 			}
       
   487 		}
       
   488 	}
       
   489 
       
   490 void CSymmetricBlockCipherImpl::DoProcessFinalEncryptL(const TDesC8& aInput, TDes8& aOutput)
       
   491 	{	
       
   492 	if (MaxFinalOutputLength(aInput.Length()) > aOutput.MaxLength() - aOutput.Length())
       
   493 		{
       
   494 		User::Leave(KErrOverflow);
       
   495 		}
       
   496 		
       
   497 	// process everything up to the last (possibly empty block)
       
   498 	TInt outputStartIndex = aOutput.Length();
       
   499 	ProcessL(aInput, aOutput);
       
   500 
       
   501 	// pad the plaintext
       
   502 	iPadding->PadL(iInputStore, iPaddingBlock);
       
   503 	
       
   504 	// if padding required
       
   505 	if (iPaddingBlock.Length() > 0)
       
   506 		{
       
   507 		iInputStore.Zero();
       
   508 
       
   509 		// make sure the output is a multiple of the block size
       
   510 		User::LeaveIfError(((aOutput.Length() - outputStartIndex + iPaddingBlock.Length()) % iBlockBytes) == 0 ? KErrNone : KErrInvalidPadding);
       
   511 
       
   512 		outputStartIndex = aOutput.Length();
       
   513 		aOutput.Append(iPaddingBlock);
       
   514 		iPaddingBlock.Zero();
       
   515 		TransformEncrypt(const_cast<TUint8*>(aOutput.Ptr()) + outputStartIndex, 1);		
       
   516 		}
       
   517 	}
       
   518 
       
   519 void CSymmetricBlockCipherImpl::DoProcessFinalDecryptL(const TDesC8& aInput, TDes8& aOutput)
       
   520 	{
       
   521 	if (MaxFinalOutputLength(aInput.Length()) > aOutput.MaxLength() - aOutput.Length())
       
   522 		{
       
   523 		User::Leave(KErrOverflow);
       
   524 		}
       
   525 
       
   526 	// Input length (including inputstore) must be a multiple of the 
       
   527 	// block size in length
       
   528 	if ((aInput.Length() + iInputStore.Length()) & (iBlockBytes - 1)) 
       
   529 		{
       
   530 		User::Leave(KErrArgument);
       
   531 		}
       
   532 
       
   533 	if(aInput.Length() > iBlockBytes)
       
   534 		{
       
   535 		HBufC8* processBuf = HBufC8::NewLC(MaxFinalOutputLength(aInput.Length()));
       
   536 		TPtr8 processPtr = processBuf->Des(); 
       
   537 	
       
   538 		ProcessL(aInput, processPtr);
       
   539 
       
   540 		ASSERT(iInputStore.Length()==0); // all the blocks should have been decrypted
       
   541 		
       
   542 		// Unpad processPtr into aOutput
       
   543 		iPadding->UnPadL(processPtr, aOutput);
       
   544 
       
   545 		CleanupStack::PopAndDestroy(processBuf);
       
   546 		}
       
   547 	else 
       
   548 		{
       
   549 		// now contains the final ciphertext block
       
   550 		iInputStore.Append(aInput);
       
   551 
       
   552 		// Decrypt the last _padding_ blocksize into a new buffer
       
   553 		TransformDecrypt(const_cast<TUint8*>(iInputStore.Ptr()), 1);
       
   554 		
       
   555 		// Unpad the last block and append to output
       
   556 		iPadding->UnPadL(iInputStore, aOutput);
       
   557 		}
       
   558 			
       
   559 	iPaddingBlock.Zero();
       
   560 	iInputStore.Zero();
       
   561 	}
       
   562 
       
   563 	
       
   564 /**
       
   565 CTR mode behaves like a stream cipher, accepting input of any arbitrary length. This results 
       
   566 in a significant body of code that behaves fundamentally differently to the ECB and CBC modes. 
       
   567 ProcessCtrL() is called by ProcessL() when operating in CTR mode, wrapping up all this 
       
   568 functionality into a separate method for clarity.
       
   569 
       
   570 Encrypting zero-filled bytes will return the keystream since the output of Transformation is simply 
       
   571 the input XORed with the keystream.
       
   572 	
       
   573 See: http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
       
   574 */
       
   575 void CSymmetricBlockCipherImpl::ProcessCtrL(const TDesC8& aInput, TDes8& aOutput)
       
   576 	{
       
   577 	TInt inputLength(aInput.Length());	
       
   578 
       
   579 	TInt outputLength(aOutput.Length());
       
   580 	TInt amountToXor = Min(iCtrUnusedKeystreamPtr.Length(), inputLength);
       
   581 
       
   582 	// Try applying previously unused key stream bytes.
       
   583 	if (amountToXor > 0)
       
   584 		{
       
   585 		aOutput.Append(aInput.Left(amountToXor));
       
   586 		for (TInt i = 0; i < amountToXor; ++i)
       
   587 			{
       
   588 			aOutput[outputLength + i] ^= iCtrUnusedKeystreamPtr[i];
       
   589 			}
       
   590 		iCtrUnusedKeystreamPtr = iCtrUnusedKeystreamPtr.RightTPtr((iCtrUnusedKeystreamPtr.Length() - amountToXor));	
       
   591 		}
       
   592 		
       
   593 	TInt amountToEncode = inputLength - amountToXor;
       
   594 	
       
   595 	if ((iCtrUnusedKeystreamPtr.Length() == 0) && (amountToEncode > 0))
       
   596 		{
       
   597 		// For each whole block's worth of input, transform it.
       
   598 		TInt wholeBlocks = (amountToEncode) / iBlockBytes; 
       
   599 		TInt wholeBlocksSize = wholeBlocks * iBlockBytes;		
       
   600 		outputLength = aOutput.Length();
       
   601 		
       
   602 		if (wholeBlocks)
       
   603 			{
       
   604 			aOutput.Append(aInput.Mid(amountToXor, wholeBlocksSize));
       
   605 			Transform(const_cast<TUint8*>(aOutput.Ptr()) + outputLength, wholeBlocks);
       
   606 			}
       
   607 			
       
   608 		// CTR mode can handle arbitrary sized inputs. Here any remaining input data of less than the block size
       
   609 		// is padded with zeros and then transformed. On return this padded section of the block will contain the next
       
   610 		// sequence of keystream, which is copied to iCtrUnusedKeystream for use next time ProcessCtrL() is called.
       
   611 		TInt remainingBytes = amountToEncode - wholeBlocksSize;
       
   612 		iCtrUnusedKeystreamPtr = iCtrUnusedKeystream->Des();
       
   613 		iCtrUnusedKeystreamPtr.SetMax();
       
   614 		iCtrUnusedKeystreamPtr.FillZ();
       
   615 		iCtrUnusedKeystreamPtr.Copy(aInput.Right(remainingBytes));
       
   616 		iCtrUnusedKeystreamPtr.SetLength(iBlockBytes);	
       
   617 	
       
   618 		Transform(const_cast<TUint8*>(iCtrUnusedKeystreamPtr.Ptr()), 1);
       
   619 	
       
   620 		aOutput.Append(iCtrUnusedKeystreamPtr.Left(remainingBytes));
       
   621 			
       
   622 		iCtrUnusedKeystreamPtr = iCtrUnusedKeystreamPtr.RightTPtr((iCtrUnusedKeystreamPtr.Length() - remainingBytes));	
       
   623 		}
       
   624 	}
       
   625 
       
   626 
       
   627 
       
   628 // Methods implemented in subclass. No coverage here.
       
   629 #ifdef _BullseyeCoverage
       
   630 #pragma suppress_warnings on
       
   631 #pragma BullseyeCoverage off
       
   632 #pragma suppress_warnings off
       
   633 #endif
       
   634 void CSymmetricStreamCipherImpl::SetOperationModeL(TUid /*aOperationMode*/)
       
   635 	{
       
   636 	// Override in subclass
       
   637 	User::Leave(KErrNotSupported);
       
   638 	}
       
   639 	
       
   640 void CSymmetricStreamCipherImpl::SetPaddingModeL(TUid /*aPaddingMode*/)
       
   641 	{
       
   642 	// Override in subclass
       
   643 	User::Leave(KErrNotSupported);
       
   644 	}
       
   645 	
       
   646 void CSymmetricStreamCipherImpl::SetIvL(const TDesC8& /*aIv*/)
       
   647 	{
       
   648 	// Override in subclass
       
   649 	User::Leave(KErrNotSupported);
       
   650 	}