os/security/cryptoplugins/cryptospiplugins/test/h4drv/crypto_h4_plugin/h4cipherimpl.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     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 /**
    20  @file
    21  @internalComponent
    22  @released
    23 */
    24 #include "h4cipherimpl.h"
    25 
    26 #include <e32def.h>
    27 #include <cryptostrength.h>
    28 #include <cryptospi/cryptospidef.h>
    29 #include "keys.h"
    30 #include <cryptospi/plugincharacteristics.h>
    31 #include "pluginconfig.h"
    32 #include <cryptopanic.h>
    33 #include <securityerr.h>
    34 #include "keyhandle.h"
    35 
    36 using namespace HwCrypto;
    37 
    38 #define BytesToBits(byteCount) (byteCount*8)
    39 
    40 //
    41 // Implementation of Symmetric Cipher class
    42 //
    43 CH4CipherImpl::CH4CipherImpl(TUint8 aBlockBytes,
    44 							 TUid aCryptoMode,
    45 							 TUid aOperationMode,
    46 							 TUid aPaddingMode) 
    47 	: iBlockBytes(aBlockBytes),
    48 	  iCryptoMode(aCryptoMode),
    49 	  iOperationMode(aOperationMode),
    50 	  iPaddingMode(aPaddingMode)
    51 	{
    52 	}
    53 
    54 void CH4CipherImpl::ConstructL(const CKey& aKey) 
    55 	{
    56 	SetKeyL(aKey);		
    57 	SetOperationModeL(iOperationMode);
    58 	SetCryptoModeL(iCryptoMode);	
    59 	SetPaddingModeL(iPaddingMode);
    60 	
    61 	iPartialBlock.ReAllocL(iBlockBytes);
    62 	iPaddingBlock.ReAllocL(iBlockBytes);
    63 	
    64 	iIv.ReAllocL(iBlockBytes);
    65 	//	iIv.SetLength(iBlockBytes);
    66 	//	TRandom::RandomL(iIv);
    67 	}
    68 	
    69 CExtendedCharacteristics* CH4CipherImpl::CreateExtendedCharacteristicsL()
    70 	{
    71 	// All Symbian software plug-ins have unlimited concurrency, cannot be reserved
    72 	// for exclusive use and are not CERTIFIED to be standards compliant.		
    73 
    74 	//	return CExtendedCharacteristics::NewL(KMaxTInt, iStandardsConformance, EFalse);	
    75 	return 0;	
    76 	}
    77 
    78 CH4CipherImpl::~CH4CipherImpl()
    79 	{			
    80 	delete iPadding;
    81 	iIv.Close();
    82 	iPartialBlock.Close();
    83 	iPaddingBlock.Close();	
    84 
    85 	delete iKey;	
    86 	iStandardsConformance.Close();	
    87 	}
    88 		
    89 void CH4CipherImpl::Close()
    90 	{
    91 	delete this;
    92 	}
    93 	
    94 TAny* CH4CipherImpl::GetExtension(TUid /*aExtensionId*/) 
    95 	{
    96 	return 0;
    97 	}
    98 	
    99 void CH4CipherImpl::GetCharacteristicsL(const TAny*& aPluginCharacteristics)
   100 	{
   101 	TInt numCiphers = sizeof(KSymmetricCipherCharacteristics)/sizeof(TSymmetricCipherCharacteristics*);
   102 	TInt32 implUid = ImplementationUid().iUid;
   103 	for (TInt i = 0; i < numCiphers; ++i)
   104 		{
   105 		if (KSymmetricCipherCharacteristics[i]->cmn.iImplementationUID == implUid)
   106 			{
   107 			aPluginCharacteristics = KSymmetricCipherCharacteristics[i];
   108 			break;
   109 			}
   110 		}	
   111 	}
   112 
   113 
   114 void CH4CipherImpl::Reset()
   115 	{
   116 	iPartialBlock.Zero();
   117 	iPaddingBlock.Zero();
   118 	
   119 	// Reconfigure h/w based on iCryptoMode/iOperationMode/iKey/iIv
   120 	TRAP_IGNORE(DoSetupL());
   121 	iNeedToSetupHw = EFalse;
   122 	}	
   123 
   124 
   125 TInt CH4CipherImpl::GetKeyStrength() const
   126 	{
   127 	return BytesToBits(iKey->Length());
   128 	}
   129 	
   130 HBufC8* CH4CipherImpl::ExtractKeyDataLC(const CKey& aKey) const
   131 	{
   132 	const TDesC8& keyContent = aKey.GetTDesC8L(KSymmetricKeyParameterUid);
   133 	return keyContent.AllocLC();
   134 	}
   135 
   136 TInt CH4CipherImpl::KeySize() const
   137 	{
   138 	// return key size in BITS
   139 	return BytesToBits(iKeyBytes);
   140 	}
   141 
   142 void CH4CipherImpl::SetKeyL(const CKey& aKey)
   143 	{
   144 	HBufC8* key = ExtractKeyDataLC(aKey);
   145 	TInt keyLength(key->Length());
   146 	
   147 	const TKeyProperty &keyProps = aKey.KeyProperty();
   148 
   149 	if(keyProps.iKeyType != KSymmetricKeyUid)
   150 		{
   151 		User::Leave(KErrArgument);
   152 		}
   153 
   154 	if(keyProps.iKeyAttribute == KNonEmbeddedKeyUid)
   155 		{
   156 		// Not an embedded key, so key is the actual key data and we
   157 		// can therefore check its strength...
   158 		TCrypto::IsSymmetricWeakEnoughL(BytesToBits(keyLength));
   159 		if (! IsValidKeyLength(keyLength))
   160 			{
   161 			User::Leave(KErrNotSupported);
   162 			}
   163 		}
   164 		
   165 	delete iKey;	
   166 	CleanupStack::Pop(key);
   167 	iKey = key;
   168 	iKeyBytes = keyLength;
   169 
   170 	// H/W needs reconfiguring
   171 	iNeedToSetupHw = ETrue;
   172 	}	
   173 
   174 TInt CH4CipherImpl::BlockSize() const
   175 	{
   176 	// return block size in BITS
   177 	return BytesToBits(iBlockBytes);
   178 	}
   179 
   180 void CH4CipherImpl::SetCryptoModeL(TUid aCryptoMode)
   181 	{
   182 	switch (aCryptoMode.iUid)
   183 		{
   184 		case KCryptoModeEncrypt:
   185 		case KCryptoModeDecrypt:
   186 			break;
   187 		default:
   188 			User::Leave(KErrNotSupported);
   189 		}
   190 	iCryptoMode = aCryptoMode;		
   191 	// H/W needs reconfiguring
   192 	iNeedToSetupHw = ETrue;
   193 	}
   194 
   195 void CH4CipherImpl::SetOperationModeL(TUid aOperationMode)
   196 	{
   197 	switch (aOperationMode.iUid)
   198 		{
   199 		case KOperationModeNone:
   200 		case KOperationModeECB:
   201 		case KOperationModeCBC:
   202 			break;
   203 		default:
   204 			User::Leave(KErrNotSupported);
   205 		}
   206 	iOperationMode = aOperationMode;		
   207 	// H/W needs reconfiguring
   208 	iNeedToSetupHw = ETrue;
   209 	}
   210 
   211 void CH4CipherImpl::SetPaddingModeL(TUid aPaddingMode)
   212 	{
   213 	if(!iPadding || (aPaddingMode != iPaddingMode))
   214 		{
   215 		CPadding* padding(0);
   216 		switch (aPaddingMode.iUid)
   217 			{
   218 			case KPaddingModeNone:
   219 				padding = CPaddingNone::NewL(iBlockBytes);
   220 				break;
   221 			case KPaddingModeSSLv3:
   222 			padding = CPaddingSSLv3::NewL(iBlockBytes);
   223 			break;
   224 			case KPaddingModePKCS7:
   225 				padding = CPaddingPKCS7::NewL(iBlockBytes);
   226 				break;
   227 			default:
   228 				User::Leave(KErrNotSupported);
   229 			}
   230 		delete iPadding;
   231 		iPadding = padding;
   232 		iPaddingMode = aPaddingMode;
   233 		}
   234 	
   235 	// H/W needs reconfiguring
   236 	iNeedToSetupHw = ETrue;
   237 	}
   238 	
   239 void CH4CipherImpl::SetIvL(const TDesC8& aIv)
   240 	{
   241 	if (iOperationMode.iUid != KOperationModeCBC)
   242 		{
   243 		User::Leave(KErrNotSupported);
   244 		}
   245 
   246 	if (aIv.Length() != iBlockBytes) 
   247 		{
   248 		User::Leave(KErrArgument);
   249 		}
   250 	iIv = aIv;	
   251 
   252 	// H/W needs reconfiguring
   253 	iNeedToSetupHw = ETrue;
   254 	}
   255 
   256 
   257 
   258 	
   259 	
   260 
   261 
   262 
   263 
   264 TInt CH4CipherImpl::MaxOutputLength(TInt aInputLength) const
   265 	{	
   266 	// The maximum output length required for Process is equal to the
   267 	// size of the number of whole input blocks available.
   268 	//
   269 	// The block bytes is a power of two so we can use this to avoid
   270 	// doing a real mod operation
   271 	TUint partialBlockLength(iPartialBlock.Length());
   272 	return (partialBlockLength + aInputLength) & ~TUint32(iBlockBytes - 1);
   273 	}	
   274 
   275 TInt CH4CipherImpl::MaxFinalOutputLength(TInt aInputLength) const
   276 	{
   277 	if (iCryptoMode.iUid == KCryptoModeEncrypt)
   278 		{
   279 		return iPadding->MaxPaddedLength(iPartialBlock.Length() + aInputLength);
   280 		}
   281 	else
   282 		{
   283 		return iPadding->MaxUnPaddedLength(aInputLength + iPartialBlock.Length());
   284 		}
   285 	}
   286 
   287 
   288 
   289 void CH4CipherImpl::ProcessL(const TDesC8& aInput, TDes8& aOutput)
   290 	{
   291 	if(iNeedToSetupHw)
   292 		{
   293 		// Reconfigure h/w based on iCryptoMode/iOperationMode/iKey/iIv
   294 		DoSetupL();
   295 		iNeedToSetupHw = EFalse;
   296 		}
   297 
   298 	TInt inputLength(aInput.Length());	
   299 	if (MaxOutputLength(inputLength) > aOutput.MaxLength())
   300 		{
   301 		User::Leave(KErrOverflow);
   302 		}	
   303 
   304 	TInt partialBlockLength(iPartialBlock.Length()); // partial data written to h/w last time
   305 	TUint32 totalInput = partialBlockLength + inputLength;
   306 	
   307 	// Pass new data to h/w driver
   308 	DoWriteL(aInput.Ptr(), inputLength);
   309 
   310 	if(totalInput < iBlockBytes)
   311 		{
   312 		// Keep a copy of the partial block which is inside the h/w
   313 		// driver in case we need to calculate pad for it later...
   314 		if(inputLength) iPartialBlock.Append(aInput);
   315 		// Not enough written yet for more data to be available yet.
   316 		return;
   317 		}
   318 	else
   319 		{
   320 		// We have completed the previous partial block so we no
   321 		// longer need to keep a copy of it
   322 		iPartialBlock.Zero();
   323 		// Work out length of partial block at end of current data
   324 		TUint32 trailing = TUint32(partialBlockLength + inputLength) & TUint32(iBlockBytes - 1);
   325 		// Keep a copy of the partial block data
   326 		if(trailing) iPartialBlock.Append(aInput.Right(trailing));
   327 		}
   328 
   329 	//
   330 	// Work out how much data is available for reading.
   331 	//
   332 	// The h/w processes data a block at a time, and we only ever read
   333 	// a multiple of the block size so the available data will always
   334 	// be a multiple of the blocksize.
   335 
   336 	TUint32 availableData = totalInput & ~TUint32(iBlockBytes - 1);
   337 	if (availableData)
   338 		{
   339 		// Read available data
   340 		DoReadL(aOutput, availableData);
   341 		}
   342 	}
   343 
   344 void CH4CipherImpl::ProcessFinalL(const TDesC8& aInput, TDes8& aOutput)
   345 	{
   346 	if(iNeedToSetupHw)
   347 		{
   348 		// Reconfigure h/w based on iCryptoMode/iOperationMode/iKey/iIv
   349 		DoSetupL();
   350 		iNeedToSetupHw = EFalse;
   351 		}
   352 
   353 	if(MaxFinalOutputLength(aInput.Length()) > aOutput.MaxLength() - aOutput.Length())
   354 		{
   355 		User::Leave(KErrOverflow);
   356 		}
   357 
   358 
   359 	if(iCryptoMode.iUid == KCryptoModeEncrypt)
   360 		{
   361 		// process everything up to the last (possibly empty block)
   362 		ProcessL(aInput, aOutput);
   363 
   364 		// pad the plaintext
   365 		iPaddingBlock.Zero();
   366 		iPadding->PadL(iPartialBlock, iPaddingBlock);
   367 
   368 		TUint32 padLength = iPaddingBlock.Length();
   369 		// Make sure pad worked
   370 		if(padLength & TUint32(iBlockBytes-1))
   371 			{
   372 			User::Leave(KErrInvalidPadding);
   373 			}
   374 	
   375 		if(padLength > 0)
   376 			{
   377 			// Padding created
   378 
   379 			// We have already written iPartialBlock data to the h/w
   380 			// so skip those bytes which are in the pad.
   381 			TUint32 partialLength = iPartialBlock.Length();
   382 			if(partialLength)
   383 				{
   384 				// Make sure the pad algorithm did not change the bytes at
   385 				// the start of the block....
   386 				if(iPaddingBlock.Left(partialLength) != iPartialBlock)
   387 					{
   388 					User::Leave(KErrInvalidPadding);
   389 					}
   390 				}
   391 			// Pass new data to h/w driver
   392 			DoWriteL(iPaddingBlock.Ptr() + partialLength, padLength - partialLength);
   393 
   394 			// Have now written an exact multiple of blocks to h/w so clear partial
   395 			iPartialBlock.Zero();
   396 
   397 			// Read data
   398 			DoReadL(aOutput, padLength);
   399 			}
   400 		}
   401 	else
   402 		{
   403 		// Decrypt
   404 
   405 		// Input length (including inputstore) must be a multiple of the 
   406 		// block size in length
   407 		if ((aInput.Length() + iPartialBlock.Length()) & (iBlockBytes - 1)) 
   408 			{
   409 			User::Leave(KErrArgument);
   410 			}
   411 		
   412 		// process everything up to the last (possibly empty block)
   413 		ProcessL(aInput, aOutput);
   414 		ASSERT(iPartialBlock.Length()==0); // all the blocks should have been decrypted
   415 
   416 		// Retrieve last decrypted block.
   417 		iPaddingBlock = aOutput.Right(iBlockBytes);
   418 		aOutput.SetLength(aOutput.Length() - iBlockBytes);
   419 
   420 		// Unpad the last block and (re)append to output
   421 		iPadding->UnPadL(iPaddingBlock, aOutput);
   422 	
   423 		iPaddingBlock.Zero();
   424 		iPartialBlock.Zero();
   425 		}
   426 	
   427 	}
   428 
   429 
   430 
   431 // End of file
   432 
   433