--- /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;
+ }