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