os/security/cryptoplugins/cryptospiplugins/source/softwarecrypto/cmacimpl.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/security/cryptoplugins/cryptospiplugins/source/softwarecrypto/cmacimpl.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,416 @@
     1.4 +/*
     1.5 +* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.6 +* All rights reserved.
     1.7 +* This component and the accompanying materials are made available
     1.8 +* under the terms of the License "Eclipse Public License v1.0"
     1.9 +* which accompanies this distribution, and is available
    1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.11 +*
    1.12 +* Initial Contributors:
    1.13 +* Nokia Corporation - initial contribution.
    1.14 +*
    1.15 +* Contributors:
    1.16 +*
    1.17 +* Description: 
    1.18 +* Software Mac Implementation
    1.19 +* plugin-dll headers
    1.20 +*
    1.21 +*/
    1.22 +
    1.23 +
    1.24 +/**
    1.25 + @file
    1.26 +*/
    1.27 +#include "cmacimpl.h"
    1.28 +#include "pluginconfig.h"
    1.29 +#include <cryptospi/cryptomacapi.h>
    1.30 +
    1.31 +
    1.32 +using namespace SoftwareCrypto;
    1.33 +using namespace CryptoSpi;
    1.34 +
    1.35 +/**
    1.36 + * Constants used to generate Key1, Key2 and Key3
    1.37 + */
    1.38 +const TUint8 K1Constant[] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
    1.39 +const TUint8 K2Constant[] = {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02};
    1.40 +const TUint8 K3Constant[] = {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03};
    1.41 +
    1.42 +const TInt KAesXcbcMac96Size = 12;
    1.43 +
    1.44 +
    1.45 +CCMacImpl* CCMacImpl::NewL(const CKey& aKey, CSymmetricCipher* aSymmetricCipher, TInt32 aAlgorithmUid)
    1.46 +	{
    1.47 +	CCMacImpl* self = CCMacImpl::NewLC(aKey, aSymmetricCipher, aAlgorithmUid);
    1.48 +	CleanupStack::Pop(self);
    1.49 +	return self;
    1.50 +	}
    1.51 +														
    1.52 +CCMacImpl* CCMacImpl::NewLC(const CKey& aKey, CSymmetricCipher* aSymmetricCipher, TInt32 aAlgorithmUid)
    1.53 +	{
    1.54 +	CCMacImpl* self = NULL;
    1.55 + 	TRAPD(err, self = new (ELeave) CCMacImpl(aSymmetricCipher));
    1.56 +  	if(err!=KErrNone)
    1.57 +  		{
    1.58 +  		delete aSymmetricCipher;
    1.59 +  		User::Leave(err);
    1.60 +  		}
    1.61 +	CleanupStack::PushL(self);
    1.62 +	self->ConstructL(aKey, aAlgorithmUid);
    1.63 +	return self;
    1.64 +	}
    1.65 +
    1.66 +CKey* CCMacImpl::Create128bitKeyL(const CKey& aKey)
    1.67 +	{
    1.68 +	TBuf8<KMacBlockSize> keybuffer;
    1.69 +	CryptoSpi::CKey* key = NULL;
    1.70 +	
    1.71 +	const TDesC8& keyContent=aKey.GetTDesC8L(CryptoSpi::KSymmetricKeyParameterUid);
    1.72 +
    1.73 +	if( (TUint32)keyContent.Size() > KMacBlockSize)
    1.74 +		{
    1.75 +		// Create key
    1.76 +		CryptoSpi::CCryptoParams* keyParams = CryptoSpi::CCryptoParams::NewLC();
    1.77 +		keybuffer.SetLength(KMacBlockSize);
    1.78 +		keybuffer.FillZ();
    1.79 +		// 'keybuffer' is the key with 128 zero bits.
    1.80 +		keyParams->AddL(keybuffer, CryptoSpi::KSymmetricKeyParameterUid);
    1.81 +		key=CryptoSpi::CKey::NewLC(aKey.KeyProperty(),*keyParams);
    1.82 +		// evaluate final key data.
    1.83 +		SetKeyL(*key);
    1.84 +		CleanupStack::PopAndDestroy(2, keyParams);
    1.85 +		keybuffer.Copy(FinalL(keyContent));
    1.86 +		// 'keybuffer' contains the final key data.
    1.87 +		}
    1.88 +	else 
    1.89 +		{
    1.90 +		keybuffer.Copy(keyContent);
    1.91 +		TUint i;
    1.92 +		for (i=keybuffer.Size();i<KMacBlockSize;++i)
    1.93 +			{
    1.94 +			keybuffer.Append(0);
    1.95 +			}
    1.96 +		// 'keybuffer' contains the final key data.
    1.97 +		}
    1.98 +	
    1.99 +	// create a new CKey instance and assign it to iKey using 'keybuffer'.
   1.100 +	CryptoSpi::CCryptoParams* keyParams = CryptoSpi::CCryptoParams::NewLC();
   1.101 +	keyParams->AddL(keybuffer, CryptoSpi::KSymmetricKeyParameterUid);
   1.102 +	key=CryptoSpi::CKey::NewL(aKey.KeyProperty(),*keyParams);
   1.103 +	CleanupStack::PopAndDestroy(keyParams);	
   1.104 +
   1.105 +	// 'key' will contain the final CKey instance.
   1.106 +	return key;
   1.107 +	}
   1.108 +
   1.109 +void CCMacImpl::SetKeyL(const CKey& aKey)
   1.110 +	{
   1.111 +	const TPtrC8 KeyConstant1(K1Constant, KMacBlockSize);
   1.112 +	const TPtrC8 KeyConstant2(K2Constant, KMacBlockSize);
   1.113 +	const TPtrC8 KeyConstant3(K3Constant, KMacBlockSize);
   1.114 +
   1.115 +	// Initialize the cipher class to encrypt Keyconstants to generate additional keys.
   1.116 +	if (iImplementationUid == CryptoSpi::KAlgorithmCipherAesXcbcPrf128)
   1.117 +		{
   1.118 +		// RFC 4434: keys that were not equal in length to 128 bits will no longer be
   1.119 +		// rejected but instead will be made 128 bits for AES-XCBC-PRF-128 Algorithm only.
   1.120 +		CryptoSpi::CKey* key = Create128bitKeyL(aKey);
   1.121 +		CleanupStack::PushL(key);
   1.122 +		iCipherImpl->SetKeyL(*key);
   1.123 +		CleanupStack::PopAndDestroy(key);	
   1.124 +		}
   1.125 +	else
   1.126 +		{
   1.127 +		iCipherImpl->SetKeyL(aKey);
   1.128 +		}
   1.129 +	iCipherImpl->SetCryptoModeL(CryptoSpi::KCryptoModeEncryptUid);
   1.130 +	iCipherImpl->SetOperationModeL(CryptoSpi::KOperationModeNoneUid);
   1.131 +
   1.132 +	// cipher class expects the output buffer to be empty.
   1.133 +	iKey1.Zero();
   1.134 +	iKey2.Zero();
   1.135 +	iKey3.Zero();
   1.136 +
   1.137 +	// aKey is used to generate Key1, Key2 and Key3.
   1.138 +	// Where Key1 = encrypt KeyConstant1 with aKey
   1.139 +	// Where Key2 = encrypt KeyConstant2 with aKey
   1.140 +	// Where Key3 = encrypt KeyConstant3 with aKey
   1.141 +	
   1.142 +	// Key1 is used to encrypt the data whereas
   1.143 +	// Key2 and Key3 is used to XOR with the last 
   1.144 +	// block.
   1.145 +    iCipherImpl->ProcessFinalL(KeyConstant1, iKey1);
   1.146 +	iCipherImpl->ProcessFinalL(KeyConstant2, iKey2);
   1.147 +	iCipherImpl->ProcessFinalL(KeyConstant3, iKey3);
   1.148 +	
   1.149 +	// Create CKey instance with key1
   1.150 +	CCryptoParams* keyParam =CCryptoParams::NewLC();
   1.151 + 	keyParam->AddL(iKey1, CryptoSpi::KSymmetricKeyParameterUid);
   1.152 +
   1.153 + 	delete iKey;
   1.154 + 	iKey = NULL;
   1.155 + 	iKey=CKey::NewL(aKey.KeyProperty(), *keyParam);
   1.156 + 	// Initialize the cipher class for MAC calculation.
   1.157 +	iCipherImpl->SetKeyL(*iKey);
   1.158 + 	iCipherImpl->SetOperationModeL(CryptoSpi::KOperationModeCBCUid);
   1.159 + 	Mem::FillZ(iE, sizeof(iE));
   1.160 + 	iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
   1.161 +
   1.162 + 	CleanupStack::PopAndDestroy(keyParam);
   1.163 +	}
   1.164 +
   1.165 +CCMacImpl::~CCMacImpl()
   1.166 +	{
   1.167 +	delete iKey;
   1.168 +	delete iCipherImpl;
   1.169 +	}
   1.170 +
   1.171 +CCMacImpl::CCMacImpl(const CCMacImpl& aCCMacImpl)
   1.172 +	{
   1.173 +	iImplementationUid = aCCMacImpl.iImplementationUid;
   1.174 +	iKey1.Copy(aCCMacImpl.iKey1);
   1.175 +	iKey2.Copy(aCCMacImpl.iKey2);
   1.176 +	iKey3.Copy(aCCMacImpl.iKey3);
   1.177 +	
   1.178 +	(void)Mem::Copy(iE, aCCMacImpl.iE, sizeof(iE));
   1.179 +	(void)Mem::Copy(iData, aCCMacImpl.iData, sizeof(iData));
   1.180 +	
   1.181 +	iCurrentTotalLength = aCCMacImpl.iCurrentTotalLength;
   1.182 +	}
   1.183 +
   1.184 +const CExtendedCharacteristics* CCMacImpl::GetExtendedCharacteristicsL()
   1.185 +	{
   1.186 +	return iCipherImpl->GetExtendedCharacteristicsL();
   1.187 +	}
   1.188 +
   1.189 +CCMacImpl::CCMacImpl(CryptoSpi::CSymmetricCipher* aSymmetricCipher)
   1.190 +	{
   1.191 +	iCipherImpl = aSymmetricCipher;
   1.192 +	aSymmetricCipher = NULL;
   1.193 +	iMacValue.SetLength(KMacBlockSize);
   1.194 +	}
   1.195 +
   1.196 +void CCMacImpl::ConstructL(const CKey& aKey, TInt32 aAlgorithmUid) 
   1.197 +	{
   1.198 +	iImplementationUid = aAlgorithmUid;
   1.199 +	
   1.200 +    switch(aAlgorithmUid)
   1.201 +    	{
   1.202 +    	case CryptoSpi::KAlgorithmCipherAesXcbcMac96:
   1.203 +    	case CryptoSpi::KAlgorithmCipherAesXcbcPrf128:
   1.204 +    		{
   1.205 +    		SetKeyL(aKey);
   1.206 +     		break;
   1.207 +    		}
   1.208 +    	default:
   1.209 +    		{
   1.210 +    		User::Leave(KErrNotSupported);
   1.211 +    		}
   1.212 +    	}
   1.213 +	}
   1.214 +
   1.215 +/**
   1.216 + * Takes the message and XOR it with iData.
   1.217 + * 
   1.218 + * @param aKey 128bit key. This key will be XORed with iData.
   1.219 + * @param aOutput  The result of the XOR operation will be copied to this.
   1.220 + * 				   Its length should be 128bit (16bytes).
   1.221 + */
   1.222 +
   1.223 +void CCMacImpl::XORKeyWithData(const TDesC8& aKey, TDes8& aOutput)
   1.224 +	{
   1.225 +	for (TInt i = 0; i < KMacBlockSize; ++i)
   1.226 +		{
   1.227 +		aOutput[i] = iData[i] ^ aKey[i];
   1.228 +		}
   1.229 +	}
   1.230 +
   1.231 +/**
   1.232 + * This function is used to pad message M to make the total message
   1.233 + * length multiple of block size (128bit). The last block M[n] will be 
   1.234 + * padded with a single "1" bit followed by the number of "0" bits required
   1.235 + * to increase M[n]'s size to 128 bits (Block Size).
   1.236 + * 
   1.237 + * Used in AES-XCBC-MAC-96 and AES-XCBC-PRF-128 Mac algorithms.
   1.238 + */
   1.239 +void CCMacImpl::PadMessage()
   1.240 +	{
   1.241 +	if(iCurrentTotalLength < KMacBlockSize)
   1.242 +		{
   1.243 +		iData[iCurrentTotalLength] = 0x80;
   1.244 +		Mem::FillZ(iData + iCurrentTotalLength+1, KMacBlockSize - iCurrentTotalLength - 1);
   1.245 +		}
   1.246 +	}
   1.247 +
   1.248 +void CCMacImpl::Reset()
   1.249 +	{
   1.250 +	Mem::FillZ(iE,sizeof(iE));
   1.251 +	iCurrentTotalLength =0;
   1.252 +	// record for Reset, for the next time MacL, UpdateL or FinalL is called as we
   1.253 +	// cannot leave in Reset.
   1.254 +	TRAP(iDelayedReset, iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize)));
   1.255 +	}
   1.256 +
   1.257 +TPtrC8 CCMacImpl::MacL(const TDesC8& aMessage)
   1.258 +	{
   1.259 +	// Reset the cipher with iE as 128 zero bits as it leaved in previous call to Reset. 
   1.260 +	if (iDelayedReset != KErrNone)
   1.261 +		{
   1.262 +		// iE was reset to 128 zero bits in previous call to Reset which leaved.
   1.263 +		iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
   1.264 +		iDelayedReset = KErrNone; 
   1.265 +		}
   1.266 +	
   1.267 +	if (aMessage!=KNullDesC8())
   1.268 +		{
   1.269 +		DoUpdateL(aMessage);			
   1.270 +		}
   1.271 +	
   1.272 +	// Calculate MAC
   1.273 +	TPtrC8 macPtr(KNullDesC8());
   1.274 +	macPtr.Set(DoFinalL());
   1.275 +
   1.276 +	// Restore the internal state.
   1.277 +	// We don't want to save any state change happened in 
   1.278 +	// DoFinalL.
   1.279 +	// iE is not updated in DoFinalL function and hence
   1.280 +	// can be used to reset iCipherImpl to previous state.
   1.281 +	iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
   1.282 +	
   1.283 +	return macPtr;		
   1.284 +	}
   1.285 +
   1.286 +TPtrC8 CCMacImpl::FinalL(const TDesC8& aMessage)
   1.287 +	{
   1.288 +	// Reset the cipher with iE as 128 zero bits as it leaved in previous call to Reset. 
   1.289 +	if (iDelayedReset == KErrNone)
   1.290 +		{
   1.291 +		// iE was reset to 128 zero bits in previous call to Reset which leaved.
   1.292 +		iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
   1.293 +		iDelayedReset = KErrNone;
   1.294 +		}
   1.295 +
   1.296 +	if (aMessage!=KNullDesC8())
   1.297 +		{
   1.298 +		DoUpdateL(aMessage);			
   1.299 +		}
   1.300 +	TPtrC8 macPtr(KNullDesC8());
   1.301 +	macPtr.Set(DoFinalL());
   1.302 +	Reset();
   1.303 +	return macPtr;
   1.304 +	}
   1.305 +
   1.306 +void CCMacImpl::UpdateL(const TDesC8& aMessage)
   1.307 +	{
   1.308 +	// Reset the cipher with iE as 128 zero bits as it leaved in previous call to Reset. 
   1.309 +	if (iDelayedReset == KErrNone)
   1.310 +		{
   1.311 +		// iE was reset to 128 zero bits in previous call to Reset which leaved.
   1.312 +		iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
   1.313 +		iDelayedReset = KErrNone;
   1.314 +		}
   1.315 +
   1.316 +	if (aMessage!=KNullDesC8())
   1.317 +		{
   1.318 +		DoUpdateL(aMessage);			
   1.319 +		}
   1.320 +	}
   1.321 +
   1.322 +void CCMacImpl::ProcessBlockL()
   1.323 +	{
   1.324 +	TPtrC8 dataPtr(iData, KMacBlockSize);
   1.325 +	TPtr8 intermediateCipherPtr(iE,0,KMacBlockSize);
   1.326 +	// iData (Block) should be XORed with iE calculated
   1.327 +	// from previoue processing. If it's the first processing
   1.328 +	// then iE will be zero.
   1.329 +	// Here we are not doing explicit XORing because iCpherImpl 
   1.330 +	// is set in CBC mode. Therefore this operation will be
   1.331 +	// done by iCipherImpl
   1.332 +	iCipherImpl->ProcessL(dataPtr, intermediateCipherPtr);
   1.333 +	// After processing discard the block.
   1.334 +	iCurrentTotalLength = 0;
   1.335 +	}
   1.336 +
   1.337 +void CCMacImpl::DoUpdateL(const TDesC8& aMessage)
   1.338 +	{
   1.339 +	TInt curLength = aMessage.Length();
   1.340 +	const TUint8* msgPtr = aMessage.Ptr();
   1.341 +	
   1.342 +	while(curLength > 0)
   1.343 +		{
   1.344 +		// If block is formed then process it.
   1.345 +		if(iCurrentTotalLength == KMacBlockSize)
   1.346 +			ProcessBlockL();
   1.347 +		
   1.348 +		// Check the space left in the block.
   1.349 +		TUint remainingLength = KMacBlockSize - iCurrentTotalLength;
   1.350 +		// If unprocesed message length is less then remainingLength
   1.351 +		// then copy the entire data to iData else copy till iData
   1.352 +		// if full.
   1.353 +		TUint length = Min(curLength, remainingLength);
   1.354 +
   1.355 +		
   1.356 +		// Discard the return value obtained from Mem::Copy( ) function.		
   1.357 +		(void)Mem::Copy(iData+iCurrentTotalLength, msgPtr, length);
   1.358 +		// Update data offset
   1.359 +		iCurrentTotalLength += length;
   1.360 +		curLength -= length;
   1.361 +		msgPtr += length;
   1.362 +		}
   1.363 + 	}
   1.364 +
   1.365 +TPtrC8 CCMacImpl::DoFinalL()
   1.366 +	{
   1.367 +	TBuf8<KMacBlockSize> finalBlock;
   1.368 +	finalBlock.SetLength(KMacBlockSize);
   1.369 +	
   1.370 +	// If padding is required then use Key3
   1.371 +	// else use Key2.
   1.372 +	if(iCurrentTotalLength < KMacBlockSize)
   1.373 +		{
   1.374 +		PadMessage();
   1.375 +		XORKeyWithData(iKey3, finalBlock);
   1.376 +		}
   1.377 +	else
   1.378 +		{
   1.379 +		XORKeyWithData(iKey2, finalBlock);
   1.380 +		}
   1.381 +
   1.382 +	// cipher class expects the output buffer to be empty.
   1.383 +	iMacValue.Zero();
   1.384 +
   1.385 +	iCipherImpl->ProcessFinalL(finalBlock, iMacValue);
   1.386 +	
   1.387 +    return (iImplementationUid == CryptoSpi::KAlgorithmCipherAesXcbcMac96)? iMacValue.Left(KAesXcbcMac96Size): TPtrC8(iMacValue);
   1.388 +	}
   1.389 +
   1.390 +void CCMacImpl::ReInitialiseAndSetKeyL(const CKey& aKey)
   1.391 +	{
   1.392 +	Reset();
   1.393 +	SetKeyL(aKey);
   1.394 +	}
   1.395 +
   1.396 +
   1.397 +CCMacImpl* CCMacImpl::CopyL()
   1.398 +	{
   1.399 +	CCMacImpl* clone = new(ELeave) CCMacImpl(*this);
   1.400 +	CleanupStack::PushL(clone);
   1.401 +	clone->iKey = CKey::NewL(*iKey);
   1.402 +	CryptoSpi::CSymmetricCipherFactory::CreateSymmetricCipherL(clone->iCipherImpl,
   1.403 +												CryptoSpi::KAesUid,
   1.404 +												*iKey,
   1.405 +												CryptoSpi::KCryptoModeEncryptUid,
   1.406 +												CryptoSpi::KOperationModeCBCUid,
   1.407 +												CryptoSpi::KPaddingModeNoneUid,
   1.408 +												NULL);
   1.409 +	clone->iCipherImpl->SetIvL(TPtrC8(clone->iE, KMacBlockSize));
   1.410 +	CleanupStack::Pop();
   1.411 +	return clone;	
   1.412 +	}
   1.413 +	
   1.414 +CCMacImpl* CCMacImpl::ReplicateL()
   1.415 +	{
   1.416 +	CCMacImpl* replica = CopyL();
   1.417 +	replica->Reset();
   1.418 +	return replica;
   1.419 +	}