cryptoplugins/cryptospiplugins/source/softwarecrypto/cmacimpl.cpp
changeset 19 cd501b96611d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cryptoplugins/cryptospiplugins/source/softwarecrypto/cmacimpl.cpp	Fri Nov 06 13:21:00 2009 +0200
@@ -0,0 +1,416 @@
+/*
+* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+* Software Mac Implementation
+* plugin-dll headers
+*
+*/
+
+
+/**
+ @file
+*/
+#include "cmacimpl.h"
+#include "pluginconfig.h"
+#include <cryptospi/cryptomacapi.h>
+
+
+using namespace SoftwareCrypto;
+using namespace CryptoSpi;
+
+/**
+ * Constants used to generate Key1, Key2 and Key3
+ */
+const TUint8 K1Constant[] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
+const TUint8 K2Constant[] = {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02};
+const TUint8 K3Constant[] = {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03};
+
+const TInt KAesXcbcMac96Size = 12;
+
+
+CCMacImpl* CCMacImpl::NewL(const CKey& aKey, CSymmetricCipher* aSymmetricCipher, TInt32 aAlgorithmUid)
+	{
+	CCMacImpl* self = CCMacImpl::NewLC(aKey, aSymmetricCipher, aAlgorithmUid);
+	CleanupStack::Pop(self);
+	return self;
+	}
+														
+CCMacImpl* CCMacImpl::NewLC(const CKey& aKey, CSymmetricCipher* aSymmetricCipher, TInt32 aAlgorithmUid)
+	{
+	CCMacImpl* self = NULL;
+ 	TRAPD(err, self = new (ELeave) CCMacImpl(aSymmetricCipher));
+  	if(err!=KErrNone)
+  		{
+  		delete aSymmetricCipher;
+  		User::Leave(err);
+  		}
+	CleanupStack::PushL(self);
+	self->ConstructL(aKey, aAlgorithmUid);
+	return self;
+	}
+
+CKey* CCMacImpl::Create128bitKeyL(const CKey& aKey)
+	{
+	TBuf8<KMacBlockSize> keybuffer;
+	CryptoSpi::CKey* key = NULL;
+	
+	const TDesC8& keyContent=aKey.GetTDesC8L(CryptoSpi::KSymmetricKeyParameterUid);
+
+	if( (TUint32)keyContent.Size() > KMacBlockSize)
+		{
+		// Create key
+		CryptoSpi::CCryptoParams* keyParams = CryptoSpi::CCryptoParams::NewLC();
+		keybuffer.SetLength(KMacBlockSize);
+		keybuffer.FillZ();
+		// 'keybuffer' is the key with 128 zero bits.
+		keyParams->AddL(keybuffer, CryptoSpi::KSymmetricKeyParameterUid);
+		key=CryptoSpi::CKey::NewLC(aKey.KeyProperty(),*keyParams);
+		// evaluate final key data.
+		SetKeyL(*key);
+		CleanupStack::PopAndDestroy(2, keyParams);
+		keybuffer.Copy(FinalL(keyContent));
+		// 'keybuffer' contains the final key data.
+		}
+	else 
+		{
+		keybuffer.Copy(keyContent);
+		TUint i;
+		for (i=keybuffer.Size();i<KMacBlockSize;++i)
+			{
+			keybuffer.Append(0);
+			}
+		// 'keybuffer' contains the final key data.
+		}
+	
+	// create a new CKey instance and assign it to iKey using 'keybuffer'.
+	CryptoSpi::CCryptoParams* keyParams = CryptoSpi::CCryptoParams::NewLC();
+	keyParams->AddL(keybuffer, CryptoSpi::KSymmetricKeyParameterUid);
+	key=CryptoSpi::CKey::NewL(aKey.KeyProperty(),*keyParams);
+	CleanupStack::PopAndDestroy(keyParams);	
+
+	// 'key' will contain the final CKey instance.
+	return key;
+	}
+
+void CCMacImpl::SetKeyL(const CKey& aKey)
+	{
+	const TPtrC8 KeyConstant1(K1Constant, KMacBlockSize);
+	const TPtrC8 KeyConstant2(K2Constant, KMacBlockSize);
+	const TPtrC8 KeyConstant3(K3Constant, KMacBlockSize);
+
+	// Initialize the cipher class to encrypt Keyconstants to generate additional keys.
+	if (iImplementationUid == CryptoSpi::KAlgorithmCipherAesXcbcPrf128)
+		{
+		// RFC 4434: keys that were not equal in length to 128 bits will no longer be
+		// rejected but instead will be made 128 bits for AES-XCBC-PRF-128 Algorithm only.
+		CryptoSpi::CKey* key = Create128bitKeyL(aKey);
+		CleanupStack::PushL(key);
+		iCipherImpl->SetKeyL(*key);
+		CleanupStack::PopAndDestroy(key);	
+		}
+	else
+		{
+		iCipherImpl->SetKeyL(aKey);
+		}
+	iCipherImpl->SetCryptoModeL(CryptoSpi::KCryptoModeEncryptUid);
+	iCipherImpl->SetOperationModeL(CryptoSpi::KOperationModeNoneUid);
+
+	// cipher class expects the output buffer to be empty.
+	iKey1.Zero();
+	iKey2.Zero();
+	iKey3.Zero();
+
+	// aKey is used to generate Key1, Key2 and Key3.
+	// Where Key1 = encrypt KeyConstant1 with aKey
+	// Where Key2 = encrypt KeyConstant2 with aKey
+	// Where Key3 = encrypt KeyConstant3 with aKey
+	
+	// Key1 is used to encrypt the data whereas
+	// Key2 and Key3 is used to XOR with the last 
+	// block.
+    iCipherImpl->ProcessFinalL(KeyConstant1, iKey1);
+	iCipherImpl->ProcessFinalL(KeyConstant2, iKey2);
+	iCipherImpl->ProcessFinalL(KeyConstant3, iKey3);
+	
+	// Create CKey instance with key1
+	CCryptoParams* keyParam =CCryptoParams::NewLC();
+ 	keyParam->AddL(iKey1, CryptoSpi::KSymmetricKeyParameterUid);
+
+ 	delete iKey;
+ 	iKey = NULL;
+ 	iKey=CKey::NewL(aKey.KeyProperty(), *keyParam);
+ 	// Initialize the cipher class for MAC calculation.
+	iCipherImpl->SetKeyL(*iKey);
+ 	iCipherImpl->SetOperationModeL(CryptoSpi::KOperationModeCBCUid);
+ 	Mem::FillZ(iE, sizeof(iE));
+ 	iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
+
+ 	CleanupStack::PopAndDestroy(keyParam);
+	}
+
+CCMacImpl::~CCMacImpl()
+	{
+	delete iKey;
+	delete iCipherImpl;
+	}
+
+CCMacImpl::CCMacImpl(const CCMacImpl& aCCMacImpl)
+	{
+	iImplementationUid = aCCMacImpl.iImplementationUid;
+	iKey1.Copy(aCCMacImpl.iKey1);
+	iKey2.Copy(aCCMacImpl.iKey2);
+	iKey3.Copy(aCCMacImpl.iKey3);
+	
+	(void)Mem::Copy(iE, aCCMacImpl.iE, sizeof(iE));
+	(void)Mem::Copy(iData, aCCMacImpl.iData, sizeof(iData));
+	
+	iCurrentTotalLength = aCCMacImpl.iCurrentTotalLength;
+	}
+
+const CExtendedCharacteristics* CCMacImpl::GetExtendedCharacteristicsL()
+	{
+	return iCipherImpl->GetExtendedCharacteristicsL();
+	}
+
+CCMacImpl::CCMacImpl(CryptoSpi::CSymmetricCipher* aSymmetricCipher)
+	{
+	iCipherImpl = aSymmetricCipher;
+	aSymmetricCipher = NULL;
+	iMacValue.SetLength(KMacBlockSize);
+	}
+
+void CCMacImpl::ConstructL(const CKey& aKey, TInt32 aAlgorithmUid) 
+	{
+	iImplementationUid = aAlgorithmUid;
+	
+    switch(aAlgorithmUid)
+    	{
+    	case CryptoSpi::KAlgorithmCipherAesXcbcMac96:
+    	case CryptoSpi::KAlgorithmCipherAesXcbcPrf128:
+    		{
+    		SetKeyL(aKey);
+     		break;
+    		}
+    	default:
+    		{
+    		User::Leave(KErrNotSupported);
+    		}
+    	}
+	}
+
+/**
+ * Takes the message and XOR it with iData.
+ * 
+ * @param aKey 128bit key. This key will be XORed with iData.
+ * @param aOutput  The result of the XOR operation will be copied to this.
+ * 				   Its length should be 128bit (16bytes).
+ */
+
+void CCMacImpl::XORKeyWithData(const TDesC8& aKey, TDes8& aOutput)
+	{
+	for (TInt i = 0; i < KMacBlockSize; ++i)
+		{
+		aOutput[i] = iData[i] ^ aKey[i];
+		}
+	}
+
+/**
+ * This function is used to pad message M to make the total message
+ * length multiple of block size (128bit). The last block M[n] will be 
+ * padded with a single "1" bit followed by the number of "0" bits required
+ * to increase M[n]'s size to 128 bits (Block Size).
+ * 
+ * Used in AES-XCBC-MAC-96 and AES-XCBC-PRF-128 Mac algorithms.
+ */
+void CCMacImpl::PadMessage()
+	{
+	if(iCurrentTotalLength < KMacBlockSize)
+		{
+		iData[iCurrentTotalLength] = 0x80;
+		Mem::FillZ(iData + iCurrentTotalLength+1, KMacBlockSize - iCurrentTotalLength - 1);
+		}
+	}
+
+void CCMacImpl::Reset()
+	{
+	Mem::FillZ(iE,sizeof(iE));
+	iCurrentTotalLength =0;
+	// record for Reset, for the next time MacL, UpdateL or FinalL is called as we
+	// cannot leave in Reset.
+	TRAP(iDelayedReset, iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize)));
+	}
+
+TPtrC8 CCMacImpl::MacL(const TDesC8& aMessage)
+	{
+	// Reset the cipher with iE as 128 zero bits as it leaved in previous call to Reset. 
+	if (iDelayedReset != KErrNone)
+		{
+		// iE was reset to 128 zero bits in previous call to Reset which leaved.
+		iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
+		iDelayedReset = KErrNone; 
+		}
+	
+	if (aMessage!=KNullDesC8())
+		{
+		DoUpdateL(aMessage);			
+		}
+	
+	// Calculate MAC
+	TPtrC8 macPtr(KNullDesC8());
+	macPtr.Set(DoFinalL());
+
+	// Restore the internal state.
+	// We don't want to save any state change happened in 
+	// DoFinalL.
+	// iE is not updated in DoFinalL function and hence
+	// can be used to reset iCipherImpl to previous state.
+	iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
+	
+	return macPtr;		
+	}
+
+TPtrC8 CCMacImpl::FinalL(const TDesC8& aMessage)
+	{
+	// Reset the cipher with iE as 128 zero bits as it leaved in previous call to Reset. 
+	if (iDelayedReset == KErrNone)
+		{
+		// iE was reset to 128 zero bits in previous call to Reset which leaved.
+		iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
+		iDelayedReset = KErrNone;
+		}
+
+	if (aMessage!=KNullDesC8())
+		{
+		DoUpdateL(aMessage);			
+		}
+	TPtrC8 macPtr(KNullDesC8());
+	macPtr.Set(DoFinalL());
+	Reset();
+	return macPtr;
+	}
+
+void CCMacImpl::UpdateL(const TDesC8& aMessage)
+	{
+	// Reset the cipher with iE as 128 zero bits as it leaved in previous call to Reset. 
+	if (iDelayedReset == KErrNone)
+		{
+		// iE was reset to 128 zero bits in previous call to Reset which leaved.
+		iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
+		iDelayedReset = KErrNone;
+		}
+
+	if (aMessage!=KNullDesC8())
+		{
+		DoUpdateL(aMessage);			
+		}
+	}
+
+void CCMacImpl::ProcessBlockL()
+	{
+	TPtrC8 dataPtr(iData, KMacBlockSize);
+	TPtr8 intermediateCipherPtr(iE,0,KMacBlockSize);
+	// iData (Block) should be XORed with iE calculated
+	// from previoue processing. If it's the first processing
+	// then iE will be zero.
+	// Here we are not doing explicit XORing because iCpherImpl 
+	// is set in CBC mode. Therefore this operation will be
+	// done by iCipherImpl
+	iCipherImpl->ProcessL(dataPtr, intermediateCipherPtr);
+	// After processing discard the block.
+	iCurrentTotalLength = 0;
+	}
+
+void CCMacImpl::DoUpdateL(const TDesC8& aMessage)
+	{
+	TInt curLength = aMessage.Length();
+	const TUint8* msgPtr = aMessage.Ptr();
+	
+	while(curLength > 0)
+		{
+		// If block is formed then process it.
+		if(iCurrentTotalLength == KMacBlockSize)
+			ProcessBlockL();
+		
+		// Check the space left in the block.
+		TUint remainingLength = KMacBlockSize - iCurrentTotalLength;
+		// If unprocesed message length is less then remainingLength
+		// then copy the entire data to iData else copy till iData
+		// if full.
+		TUint length = Min(curLength, remainingLength);
+
+		
+		// Discard the return value obtained from Mem::Copy( ) function.		
+		(void)Mem::Copy(iData+iCurrentTotalLength, msgPtr, length);
+		// Update data offset
+		iCurrentTotalLength += length;
+		curLength -= length;
+		msgPtr += length;
+		}
+ 	}
+
+TPtrC8 CCMacImpl::DoFinalL()
+	{
+	TBuf8<KMacBlockSize> finalBlock;
+	finalBlock.SetLength(KMacBlockSize);
+	
+	// If padding is required then use Key3
+	// else use Key2.
+	if(iCurrentTotalLength < KMacBlockSize)
+		{
+		PadMessage();
+		XORKeyWithData(iKey3, finalBlock);
+		}
+	else
+		{
+		XORKeyWithData(iKey2, finalBlock);
+		}
+
+	// cipher class expects the output buffer to be empty.
+	iMacValue.Zero();
+
+	iCipherImpl->ProcessFinalL(finalBlock, iMacValue);
+	
+    return (iImplementationUid == CryptoSpi::KAlgorithmCipherAesXcbcMac96)? iMacValue.Left(KAesXcbcMac96Size): TPtrC8(iMacValue);
+	}
+
+void CCMacImpl::ReInitialiseAndSetKeyL(const CKey& aKey)
+	{
+	Reset();
+	SetKeyL(aKey);
+	}
+
+
+CCMacImpl* CCMacImpl::CopyL()
+	{
+	CCMacImpl* clone = new(ELeave) CCMacImpl(*this);
+	CleanupStack::PushL(clone);
+	clone->iKey = CKey::NewL(*iKey);
+	CryptoSpi::CSymmetricCipherFactory::CreateSymmetricCipherL(clone->iCipherImpl,
+												CryptoSpi::KAesUid,
+												*iKey,
+												CryptoSpi::KCryptoModeEncryptUid,
+												CryptoSpi::KOperationModeCBCUid,
+												CryptoSpi::KPaddingModeNoneUid,
+												NULL);
+	clone->iCipherImpl->SetIvL(TPtrC8(clone->iE, KMacBlockSize));
+	CleanupStack::Pop();
+	return clone;	
+	}
+	
+CCMacImpl* CCMacImpl::ReplicateL()
+	{
+	CCMacImpl* replica = CopyL();
+	replica->Reset();
+	return replica;
+	}