First public contribution.
2 * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
4 * This component and the accompanying materials are made available
5 * under the terms of the License "Eclipse Public License v1.0"
6 * which accompanies this distribution, and is available
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
15 * Software Mac Implementation
25 #include "pluginconfig.h"
26 #include <cryptospi/cryptomacapi.h>
29 using namespace SoftwareCrypto;
30 using namespace CryptoSpi;
33 * Constants used to generate Key1, Key2 and Key3
35 const TUint8 K1Constant[] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
36 const TUint8 K2Constant[] = {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02};
37 const TUint8 K3Constant[] = {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03};
39 const TInt KAesXcbcMac96Size = 12;
42 CCMacImpl* CCMacImpl::NewL(const CKey& aKey, CSymmetricCipher* aSymmetricCipher, TInt32 aAlgorithmUid)
44 CCMacImpl* self = CCMacImpl::NewLC(aKey, aSymmetricCipher, aAlgorithmUid);
45 CleanupStack::Pop(self);
49 CCMacImpl* CCMacImpl::NewLC(const CKey& aKey, CSymmetricCipher* aSymmetricCipher, TInt32 aAlgorithmUid)
51 CCMacImpl* self = NULL;
52 TRAPD(err, self = new (ELeave) CCMacImpl(aSymmetricCipher));
55 delete aSymmetricCipher;
58 CleanupStack::PushL(self);
59 self->ConstructL(aKey, aAlgorithmUid);
63 CKey* CCMacImpl::Create128bitKeyL(const CKey& aKey)
65 TBuf8<KMacBlockSize> keybuffer;
66 CryptoSpi::CKey* key = NULL;
68 const TDesC8& keyContent=aKey.GetTDesC8L(CryptoSpi::KSymmetricKeyParameterUid);
70 if( (TUint32)keyContent.Size() > KMacBlockSize)
73 CryptoSpi::CCryptoParams* keyParams = CryptoSpi::CCryptoParams::NewLC();
74 keybuffer.SetLength(KMacBlockSize);
76 // 'keybuffer' is the key with 128 zero bits.
77 keyParams->AddL(keybuffer, CryptoSpi::KSymmetricKeyParameterUid);
78 key=CryptoSpi::CKey::NewLC(aKey.KeyProperty(),*keyParams);
79 // evaluate final key data.
81 CleanupStack::PopAndDestroy(2, keyParams);
82 keybuffer.Copy(FinalL(keyContent));
83 // 'keybuffer' contains the final key data.
87 keybuffer.Copy(keyContent);
89 for (i=keybuffer.Size();i<KMacBlockSize;++i)
93 // 'keybuffer' contains the final key data.
96 // create a new CKey instance and assign it to iKey using 'keybuffer'.
97 CryptoSpi::CCryptoParams* keyParams = CryptoSpi::CCryptoParams::NewLC();
98 keyParams->AddL(keybuffer, CryptoSpi::KSymmetricKeyParameterUid);
99 key=CryptoSpi::CKey::NewL(aKey.KeyProperty(),*keyParams);
100 CleanupStack::PopAndDestroy(keyParams);
102 // 'key' will contain the final CKey instance.
106 void CCMacImpl::SetKeyL(const CKey& aKey)
108 const TPtrC8 KeyConstant1(K1Constant, KMacBlockSize);
109 const TPtrC8 KeyConstant2(K2Constant, KMacBlockSize);
110 const TPtrC8 KeyConstant3(K3Constant, KMacBlockSize);
112 // Initialize the cipher class to encrypt Keyconstants to generate additional keys.
113 if (iImplementationUid == CryptoSpi::KAlgorithmCipherAesXcbcPrf128)
115 // RFC 4434: keys that were not equal in length to 128 bits will no longer be
116 // rejected but instead will be made 128 bits for AES-XCBC-PRF-128 Algorithm only.
117 CryptoSpi::CKey* key = Create128bitKeyL(aKey);
118 CleanupStack::PushL(key);
119 iCipherImpl->SetKeyL(*key);
120 CleanupStack::PopAndDestroy(key);
124 iCipherImpl->SetKeyL(aKey);
126 iCipherImpl->SetCryptoModeL(CryptoSpi::KCryptoModeEncryptUid);
127 iCipherImpl->SetOperationModeL(CryptoSpi::KOperationModeNoneUid);
129 // cipher class expects the output buffer to be empty.
134 // aKey is used to generate Key1, Key2 and Key3.
135 // Where Key1 = encrypt KeyConstant1 with aKey
136 // Where Key2 = encrypt KeyConstant2 with aKey
137 // Where Key3 = encrypt KeyConstant3 with aKey
139 // Key1 is used to encrypt the data whereas
140 // Key2 and Key3 is used to XOR with the last
142 iCipherImpl->ProcessFinalL(KeyConstant1, iKey1);
143 iCipherImpl->ProcessFinalL(KeyConstant2, iKey2);
144 iCipherImpl->ProcessFinalL(KeyConstant3, iKey3);
146 // Create CKey instance with key1
147 CCryptoParams* keyParam =CCryptoParams::NewLC();
148 keyParam->AddL(iKey1, CryptoSpi::KSymmetricKeyParameterUid);
152 iKey=CKey::NewL(aKey.KeyProperty(), *keyParam);
153 // Initialize the cipher class for MAC calculation.
154 iCipherImpl->SetKeyL(*iKey);
155 iCipherImpl->SetOperationModeL(CryptoSpi::KOperationModeCBCUid);
156 Mem::FillZ(iE, sizeof(iE));
157 iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
159 CleanupStack::PopAndDestroy(keyParam);
162 CCMacImpl::~CCMacImpl()
168 CCMacImpl::CCMacImpl(const CCMacImpl& aCCMacImpl)
170 iImplementationUid = aCCMacImpl.iImplementationUid;
171 iKey1.Copy(aCCMacImpl.iKey1);
172 iKey2.Copy(aCCMacImpl.iKey2);
173 iKey3.Copy(aCCMacImpl.iKey3);
175 (void)Mem::Copy(iE, aCCMacImpl.iE, sizeof(iE));
176 (void)Mem::Copy(iData, aCCMacImpl.iData, sizeof(iData));
178 iCurrentTotalLength = aCCMacImpl.iCurrentTotalLength;
181 const CExtendedCharacteristics* CCMacImpl::GetExtendedCharacteristicsL()
183 return iCipherImpl->GetExtendedCharacteristicsL();
186 CCMacImpl::CCMacImpl(CryptoSpi::CSymmetricCipher* aSymmetricCipher)
188 iCipherImpl = aSymmetricCipher;
189 aSymmetricCipher = NULL;
190 iMacValue.SetLength(KMacBlockSize);
193 void CCMacImpl::ConstructL(const CKey& aKey, TInt32 aAlgorithmUid)
195 iImplementationUid = aAlgorithmUid;
197 switch(aAlgorithmUid)
199 case CryptoSpi::KAlgorithmCipherAesXcbcMac96:
200 case CryptoSpi::KAlgorithmCipherAesXcbcPrf128:
207 User::Leave(KErrNotSupported);
213 * Takes the message and XOR it with iData.
215 * @param aKey 128bit key. This key will be XORed with iData.
216 * @param aOutput The result of the XOR operation will be copied to this.
217 * Its length should be 128bit (16bytes).
220 void CCMacImpl::XORKeyWithData(const TDesC8& aKey, TDes8& aOutput)
222 for (TInt i = 0; i < KMacBlockSize; ++i)
224 aOutput[i] = iData[i] ^ aKey[i];
229 * This function is used to pad message M to make the total message
230 * length multiple of block size (128bit). The last block M[n] will be
231 * padded with a single "1" bit followed by the number of "0" bits required
232 * to increase M[n]'s size to 128 bits (Block Size).
234 * Used in AES-XCBC-MAC-96 and AES-XCBC-PRF-128 Mac algorithms.
236 void CCMacImpl::PadMessage()
238 if(iCurrentTotalLength < KMacBlockSize)
240 iData[iCurrentTotalLength] = 0x80;
241 Mem::FillZ(iData + iCurrentTotalLength+1, KMacBlockSize - iCurrentTotalLength - 1);
245 void CCMacImpl::Reset()
247 Mem::FillZ(iE,sizeof(iE));
248 iCurrentTotalLength =0;
249 // record for Reset, for the next time MacL, UpdateL or FinalL is called as we
250 // cannot leave in Reset.
251 TRAP(iDelayedReset, iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize)));
254 TPtrC8 CCMacImpl::MacL(const TDesC8& aMessage)
256 // Reset the cipher with iE as 128 zero bits as it leaved in previous call to Reset.
257 if (iDelayedReset != KErrNone)
259 // iE was reset to 128 zero bits in previous call to Reset which leaved.
260 iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
261 iDelayedReset = KErrNone;
264 if (aMessage!=KNullDesC8())
270 TPtrC8 macPtr(KNullDesC8());
271 macPtr.Set(DoFinalL());
273 // Restore the internal state.
274 // We don't want to save any state change happened in
276 // iE is not updated in DoFinalL function and hence
277 // can be used to reset iCipherImpl to previous state.
278 iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
283 TPtrC8 CCMacImpl::FinalL(const TDesC8& aMessage)
285 // Reset the cipher with iE as 128 zero bits as it leaved in previous call to Reset.
286 if (iDelayedReset == KErrNone)
288 // iE was reset to 128 zero bits in previous call to Reset which leaved.
289 iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
290 iDelayedReset = KErrNone;
293 if (aMessage!=KNullDesC8())
297 TPtrC8 macPtr(KNullDesC8());
298 macPtr.Set(DoFinalL());
303 void CCMacImpl::UpdateL(const TDesC8& aMessage)
305 // Reset the cipher with iE as 128 zero bits as it leaved in previous call to Reset.
306 if (iDelayedReset == KErrNone)
308 // iE was reset to 128 zero bits in previous call to Reset which leaved.
309 iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
310 iDelayedReset = KErrNone;
313 if (aMessage!=KNullDesC8())
319 void CCMacImpl::ProcessBlockL()
321 TPtrC8 dataPtr(iData, KMacBlockSize);
322 TPtr8 intermediateCipherPtr(iE,0,KMacBlockSize);
323 // iData (Block) should be XORed with iE calculated
324 // from previoue processing. If it's the first processing
325 // then iE will be zero.
326 // Here we are not doing explicit XORing because iCpherImpl
327 // is set in CBC mode. Therefore this operation will be
328 // done by iCipherImpl
329 iCipherImpl->ProcessL(dataPtr, intermediateCipherPtr);
330 // After processing discard the block.
331 iCurrentTotalLength = 0;
334 void CCMacImpl::DoUpdateL(const TDesC8& aMessage)
336 TInt curLength = aMessage.Length();
337 const TUint8* msgPtr = aMessage.Ptr();
341 // If block is formed then process it.
342 if(iCurrentTotalLength == KMacBlockSize)
345 // Check the space left in the block.
346 TUint remainingLength = KMacBlockSize - iCurrentTotalLength;
347 // If unprocesed message length is less then remainingLength
348 // then copy the entire data to iData else copy till iData
350 TUint length = Min(curLength, remainingLength);
353 // Discard the return value obtained from Mem::Copy( ) function.
354 (void)Mem::Copy(iData+iCurrentTotalLength, msgPtr, length);
355 // Update data offset
356 iCurrentTotalLength += length;
362 TPtrC8 CCMacImpl::DoFinalL()
364 TBuf8<KMacBlockSize> finalBlock;
365 finalBlock.SetLength(KMacBlockSize);
367 // If padding is required then use Key3
369 if(iCurrentTotalLength < KMacBlockSize)
372 XORKeyWithData(iKey3, finalBlock);
376 XORKeyWithData(iKey2, finalBlock);
379 // cipher class expects the output buffer to be empty.
382 iCipherImpl->ProcessFinalL(finalBlock, iMacValue);
384 return (iImplementationUid == CryptoSpi::KAlgorithmCipherAesXcbcMac96)? iMacValue.Left(KAesXcbcMac96Size): TPtrC8(iMacValue);
387 void CCMacImpl::ReInitialiseAndSetKeyL(const CKey& aKey)
394 CCMacImpl* CCMacImpl::CopyL()
396 CCMacImpl* clone = new(ELeave) CCMacImpl(*this);
397 CleanupStack::PushL(clone);
398 clone->iKey = CKey::NewL(*iKey);
399 CryptoSpi::CSymmetricCipherFactory::CreateSymmetricCipherL(clone->iCipherImpl,
402 CryptoSpi::KCryptoModeEncryptUid,
403 CryptoSpi::KOperationModeCBCUid,
404 CryptoSpi::KPaddingModeNoneUid,
406 clone->iCipherImpl->SetIvL(TPtrC8(clone->iE, KMacBlockSize));
411 CCMacImpl* CCMacImpl::ReplicateL()
413 CCMacImpl* replica = CopyL();