diff -r da2ae96f639b -r cd501b96611d cryptoplugins/cryptospiplugins/source/softwarecrypto/cmacimpl.cpp --- /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 + + +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 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();iAddL(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 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; + }