1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/security/cryptoplugins/cryptospiplugins/source/softwarecrypto/cmacimpl.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,416 @@
1.4 +/*
1.5 +* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
1.6 +* All rights reserved.
1.7 +* This component and the accompanying materials are made available
1.8 +* under the terms of the License "Eclipse Public License v1.0"
1.9 +* which accompanies this distribution, and is available
1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.11 +*
1.12 +* Initial Contributors:
1.13 +* Nokia Corporation - initial contribution.
1.14 +*
1.15 +* Contributors:
1.16 +*
1.17 +* Description:
1.18 +* Software Mac Implementation
1.19 +* plugin-dll headers
1.20 +*
1.21 +*/
1.22 +
1.23 +
1.24 +/**
1.25 + @file
1.26 +*/
1.27 +#include "cmacimpl.h"
1.28 +#include "pluginconfig.h"
1.29 +#include <cryptospi/cryptomacapi.h>
1.30 +
1.31 +
1.32 +using namespace SoftwareCrypto;
1.33 +using namespace CryptoSpi;
1.34 +
1.35 +/**
1.36 + * Constants used to generate Key1, Key2 and Key3
1.37 + */
1.38 +const TUint8 K1Constant[] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
1.39 +const TUint8 K2Constant[] = {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02};
1.40 +const TUint8 K3Constant[] = {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03};
1.41 +
1.42 +const TInt KAesXcbcMac96Size = 12;
1.43 +
1.44 +
1.45 +CCMacImpl* CCMacImpl::NewL(const CKey& aKey, CSymmetricCipher* aSymmetricCipher, TInt32 aAlgorithmUid)
1.46 + {
1.47 + CCMacImpl* self = CCMacImpl::NewLC(aKey, aSymmetricCipher, aAlgorithmUid);
1.48 + CleanupStack::Pop(self);
1.49 + return self;
1.50 + }
1.51 +
1.52 +CCMacImpl* CCMacImpl::NewLC(const CKey& aKey, CSymmetricCipher* aSymmetricCipher, TInt32 aAlgorithmUid)
1.53 + {
1.54 + CCMacImpl* self = NULL;
1.55 + TRAPD(err, self = new (ELeave) CCMacImpl(aSymmetricCipher));
1.56 + if(err!=KErrNone)
1.57 + {
1.58 + delete aSymmetricCipher;
1.59 + User::Leave(err);
1.60 + }
1.61 + CleanupStack::PushL(self);
1.62 + self->ConstructL(aKey, aAlgorithmUid);
1.63 + return self;
1.64 + }
1.65 +
1.66 +CKey* CCMacImpl::Create128bitKeyL(const CKey& aKey)
1.67 + {
1.68 + TBuf8<KMacBlockSize> keybuffer;
1.69 + CryptoSpi::CKey* key = NULL;
1.70 +
1.71 + const TDesC8& keyContent=aKey.GetTDesC8L(CryptoSpi::KSymmetricKeyParameterUid);
1.72 +
1.73 + if( (TUint32)keyContent.Size() > KMacBlockSize)
1.74 + {
1.75 + // Create key
1.76 + CryptoSpi::CCryptoParams* keyParams = CryptoSpi::CCryptoParams::NewLC();
1.77 + keybuffer.SetLength(KMacBlockSize);
1.78 + keybuffer.FillZ();
1.79 + // 'keybuffer' is the key with 128 zero bits.
1.80 + keyParams->AddL(keybuffer, CryptoSpi::KSymmetricKeyParameterUid);
1.81 + key=CryptoSpi::CKey::NewLC(aKey.KeyProperty(),*keyParams);
1.82 + // evaluate final key data.
1.83 + SetKeyL(*key);
1.84 + CleanupStack::PopAndDestroy(2, keyParams);
1.85 + keybuffer.Copy(FinalL(keyContent));
1.86 + // 'keybuffer' contains the final key data.
1.87 + }
1.88 + else
1.89 + {
1.90 + keybuffer.Copy(keyContent);
1.91 + TUint i;
1.92 + for (i=keybuffer.Size();i<KMacBlockSize;++i)
1.93 + {
1.94 + keybuffer.Append(0);
1.95 + }
1.96 + // 'keybuffer' contains the final key data.
1.97 + }
1.98 +
1.99 + // create a new CKey instance and assign it to iKey using 'keybuffer'.
1.100 + CryptoSpi::CCryptoParams* keyParams = CryptoSpi::CCryptoParams::NewLC();
1.101 + keyParams->AddL(keybuffer, CryptoSpi::KSymmetricKeyParameterUid);
1.102 + key=CryptoSpi::CKey::NewL(aKey.KeyProperty(),*keyParams);
1.103 + CleanupStack::PopAndDestroy(keyParams);
1.104 +
1.105 + // 'key' will contain the final CKey instance.
1.106 + return key;
1.107 + }
1.108 +
1.109 +void CCMacImpl::SetKeyL(const CKey& aKey)
1.110 + {
1.111 + const TPtrC8 KeyConstant1(K1Constant, KMacBlockSize);
1.112 + const TPtrC8 KeyConstant2(K2Constant, KMacBlockSize);
1.113 + const TPtrC8 KeyConstant3(K3Constant, KMacBlockSize);
1.114 +
1.115 + // Initialize the cipher class to encrypt Keyconstants to generate additional keys.
1.116 + if (iImplementationUid == CryptoSpi::KAlgorithmCipherAesXcbcPrf128)
1.117 + {
1.118 + // RFC 4434: keys that were not equal in length to 128 bits will no longer be
1.119 + // rejected but instead will be made 128 bits for AES-XCBC-PRF-128 Algorithm only.
1.120 + CryptoSpi::CKey* key = Create128bitKeyL(aKey);
1.121 + CleanupStack::PushL(key);
1.122 + iCipherImpl->SetKeyL(*key);
1.123 + CleanupStack::PopAndDestroy(key);
1.124 + }
1.125 + else
1.126 + {
1.127 + iCipherImpl->SetKeyL(aKey);
1.128 + }
1.129 + iCipherImpl->SetCryptoModeL(CryptoSpi::KCryptoModeEncryptUid);
1.130 + iCipherImpl->SetOperationModeL(CryptoSpi::KOperationModeNoneUid);
1.131 +
1.132 + // cipher class expects the output buffer to be empty.
1.133 + iKey1.Zero();
1.134 + iKey2.Zero();
1.135 + iKey3.Zero();
1.136 +
1.137 + // aKey is used to generate Key1, Key2 and Key3.
1.138 + // Where Key1 = encrypt KeyConstant1 with aKey
1.139 + // Where Key2 = encrypt KeyConstant2 with aKey
1.140 + // Where Key3 = encrypt KeyConstant3 with aKey
1.141 +
1.142 + // Key1 is used to encrypt the data whereas
1.143 + // Key2 and Key3 is used to XOR with the last
1.144 + // block.
1.145 + iCipherImpl->ProcessFinalL(KeyConstant1, iKey1);
1.146 + iCipherImpl->ProcessFinalL(KeyConstant2, iKey2);
1.147 + iCipherImpl->ProcessFinalL(KeyConstant3, iKey3);
1.148 +
1.149 + // Create CKey instance with key1
1.150 + CCryptoParams* keyParam =CCryptoParams::NewLC();
1.151 + keyParam->AddL(iKey1, CryptoSpi::KSymmetricKeyParameterUid);
1.152 +
1.153 + delete iKey;
1.154 + iKey = NULL;
1.155 + iKey=CKey::NewL(aKey.KeyProperty(), *keyParam);
1.156 + // Initialize the cipher class for MAC calculation.
1.157 + iCipherImpl->SetKeyL(*iKey);
1.158 + iCipherImpl->SetOperationModeL(CryptoSpi::KOperationModeCBCUid);
1.159 + Mem::FillZ(iE, sizeof(iE));
1.160 + iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
1.161 +
1.162 + CleanupStack::PopAndDestroy(keyParam);
1.163 + }
1.164 +
1.165 +CCMacImpl::~CCMacImpl()
1.166 + {
1.167 + delete iKey;
1.168 + delete iCipherImpl;
1.169 + }
1.170 +
1.171 +CCMacImpl::CCMacImpl(const CCMacImpl& aCCMacImpl)
1.172 + {
1.173 + iImplementationUid = aCCMacImpl.iImplementationUid;
1.174 + iKey1.Copy(aCCMacImpl.iKey1);
1.175 + iKey2.Copy(aCCMacImpl.iKey2);
1.176 + iKey3.Copy(aCCMacImpl.iKey3);
1.177 +
1.178 + (void)Mem::Copy(iE, aCCMacImpl.iE, sizeof(iE));
1.179 + (void)Mem::Copy(iData, aCCMacImpl.iData, sizeof(iData));
1.180 +
1.181 + iCurrentTotalLength = aCCMacImpl.iCurrentTotalLength;
1.182 + }
1.183 +
1.184 +const CExtendedCharacteristics* CCMacImpl::GetExtendedCharacteristicsL()
1.185 + {
1.186 + return iCipherImpl->GetExtendedCharacteristicsL();
1.187 + }
1.188 +
1.189 +CCMacImpl::CCMacImpl(CryptoSpi::CSymmetricCipher* aSymmetricCipher)
1.190 + {
1.191 + iCipherImpl = aSymmetricCipher;
1.192 + aSymmetricCipher = NULL;
1.193 + iMacValue.SetLength(KMacBlockSize);
1.194 + }
1.195 +
1.196 +void CCMacImpl::ConstructL(const CKey& aKey, TInt32 aAlgorithmUid)
1.197 + {
1.198 + iImplementationUid = aAlgorithmUid;
1.199 +
1.200 + switch(aAlgorithmUid)
1.201 + {
1.202 + case CryptoSpi::KAlgorithmCipherAesXcbcMac96:
1.203 + case CryptoSpi::KAlgorithmCipherAesXcbcPrf128:
1.204 + {
1.205 + SetKeyL(aKey);
1.206 + break;
1.207 + }
1.208 + default:
1.209 + {
1.210 + User::Leave(KErrNotSupported);
1.211 + }
1.212 + }
1.213 + }
1.214 +
1.215 +/**
1.216 + * Takes the message and XOR it with iData.
1.217 + *
1.218 + * @param aKey 128bit key. This key will be XORed with iData.
1.219 + * @param aOutput The result of the XOR operation will be copied to this.
1.220 + * Its length should be 128bit (16bytes).
1.221 + */
1.222 +
1.223 +void CCMacImpl::XORKeyWithData(const TDesC8& aKey, TDes8& aOutput)
1.224 + {
1.225 + for (TInt i = 0; i < KMacBlockSize; ++i)
1.226 + {
1.227 + aOutput[i] = iData[i] ^ aKey[i];
1.228 + }
1.229 + }
1.230 +
1.231 +/**
1.232 + * This function is used to pad message M to make the total message
1.233 + * length multiple of block size (128bit). The last block M[n] will be
1.234 + * padded with a single "1" bit followed by the number of "0" bits required
1.235 + * to increase M[n]'s size to 128 bits (Block Size).
1.236 + *
1.237 + * Used in AES-XCBC-MAC-96 and AES-XCBC-PRF-128 Mac algorithms.
1.238 + */
1.239 +void CCMacImpl::PadMessage()
1.240 + {
1.241 + if(iCurrentTotalLength < KMacBlockSize)
1.242 + {
1.243 + iData[iCurrentTotalLength] = 0x80;
1.244 + Mem::FillZ(iData + iCurrentTotalLength+1, KMacBlockSize - iCurrentTotalLength - 1);
1.245 + }
1.246 + }
1.247 +
1.248 +void CCMacImpl::Reset()
1.249 + {
1.250 + Mem::FillZ(iE,sizeof(iE));
1.251 + iCurrentTotalLength =0;
1.252 + // record for Reset, for the next time MacL, UpdateL or FinalL is called as we
1.253 + // cannot leave in Reset.
1.254 + TRAP(iDelayedReset, iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize)));
1.255 + }
1.256 +
1.257 +TPtrC8 CCMacImpl::MacL(const TDesC8& aMessage)
1.258 + {
1.259 + // Reset the cipher with iE as 128 zero bits as it leaved in previous call to Reset.
1.260 + if (iDelayedReset != KErrNone)
1.261 + {
1.262 + // iE was reset to 128 zero bits in previous call to Reset which leaved.
1.263 + iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
1.264 + iDelayedReset = KErrNone;
1.265 + }
1.266 +
1.267 + if (aMessage!=KNullDesC8())
1.268 + {
1.269 + DoUpdateL(aMessage);
1.270 + }
1.271 +
1.272 + // Calculate MAC
1.273 + TPtrC8 macPtr(KNullDesC8());
1.274 + macPtr.Set(DoFinalL());
1.275 +
1.276 + // Restore the internal state.
1.277 + // We don't want to save any state change happened in
1.278 + // DoFinalL.
1.279 + // iE is not updated in DoFinalL function and hence
1.280 + // can be used to reset iCipherImpl to previous state.
1.281 + iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
1.282 +
1.283 + return macPtr;
1.284 + }
1.285 +
1.286 +TPtrC8 CCMacImpl::FinalL(const TDesC8& aMessage)
1.287 + {
1.288 + // Reset the cipher with iE as 128 zero bits as it leaved in previous call to Reset.
1.289 + if (iDelayedReset == KErrNone)
1.290 + {
1.291 + // iE was reset to 128 zero bits in previous call to Reset which leaved.
1.292 + iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
1.293 + iDelayedReset = KErrNone;
1.294 + }
1.295 +
1.296 + if (aMessage!=KNullDesC8())
1.297 + {
1.298 + DoUpdateL(aMessage);
1.299 + }
1.300 + TPtrC8 macPtr(KNullDesC8());
1.301 + macPtr.Set(DoFinalL());
1.302 + Reset();
1.303 + return macPtr;
1.304 + }
1.305 +
1.306 +void CCMacImpl::UpdateL(const TDesC8& aMessage)
1.307 + {
1.308 + // Reset the cipher with iE as 128 zero bits as it leaved in previous call to Reset.
1.309 + if (iDelayedReset == KErrNone)
1.310 + {
1.311 + // iE was reset to 128 zero bits in previous call to Reset which leaved.
1.312 + iCipherImpl->SetIvL(TPtrC8(iE, KMacBlockSize));
1.313 + iDelayedReset = KErrNone;
1.314 + }
1.315 +
1.316 + if (aMessage!=KNullDesC8())
1.317 + {
1.318 + DoUpdateL(aMessage);
1.319 + }
1.320 + }
1.321 +
1.322 +void CCMacImpl::ProcessBlockL()
1.323 + {
1.324 + TPtrC8 dataPtr(iData, KMacBlockSize);
1.325 + TPtr8 intermediateCipherPtr(iE,0,KMacBlockSize);
1.326 + // iData (Block) should be XORed with iE calculated
1.327 + // from previoue processing. If it's the first processing
1.328 + // then iE will be zero.
1.329 + // Here we are not doing explicit XORing because iCpherImpl
1.330 + // is set in CBC mode. Therefore this operation will be
1.331 + // done by iCipherImpl
1.332 + iCipherImpl->ProcessL(dataPtr, intermediateCipherPtr);
1.333 + // After processing discard the block.
1.334 + iCurrentTotalLength = 0;
1.335 + }
1.336 +
1.337 +void CCMacImpl::DoUpdateL(const TDesC8& aMessage)
1.338 + {
1.339 + TInt curLength = aMessage.Length();
1.340 + const TUint8* msgPtr = aMessage.Ptr();
1.341 +
1.342 + while(curLength > 0)
1.343 + {
1.344 + // If block is formed then process it.
1.345 + if(iCurrentTotalLength == KMacBlockSize)
1.346 + ProcessBlockL();
1.347 +
1.348 + // Check the space left in the block.
1.349 + TUint remainingLength = KMacBlockSize - iCurrentTotalLength;
1.350 + // If unprocesed message length is less then remainingLength
1.351 + // then copy the entire data to iData else copy till iData
1.352 + // if full.
1.353 + TUint length = Min(curLength, remainingLength);
1.354 +
1.355 +
1.356 + // Discard the return value obtained from Mem::Copy( ) function.
1.357 + (void)Mem::Copy(iData+iCurrentTotalLength, msgPtr, length);
1.358 + // Update data offset
1.359 + iCurrentTotalLength += length;
1.360 + curLength -= length;
1.361 + msgPtr += length;
1.362 + }
1.363 + }
1.364 +
1.365 +TPtrC8 CCMacImpl::DoFinalL()
1.366 + {
1.367 + TBuf8<KMacBlockSize> finalBlock;
1.368 + finalBlock.SetLength(KMacBlockSize);
1.369 +
1.370 + // If padding is required then use Key3
1.371 + // else use Key2.
1.372 + if(iCurrentTotalLength < KMacBlockSize)
1.373 + {
1.374 + PadMessage();
1.375 + XORKeyWithData(iKey3, finalBlock);
1.376 + }
1.377 + else
1.378 + {
1.379 + XORKeyWithData(iKey2, finalBlock);
1.380 + }
1.381 +
1.382 + // cipher class expects the output buffer to be empty.
1.383 + iMacValue.Zero();
1.384 +
1.385 + iCipherImpl->ProcessFinalL(finalBlock, iMacValue);
1.386 +
1.387 + return (iImplementationUid == CryptoSpi::KAlgorithmCipherAesXcbcMac96)? iMacValue.Left(KAesXcbcMac96Size): TPtrC8(iMacValue);
1.388 + }
1.389 +
1.390 +void CCMacImpl::ReInitialiseAndSetKeyL(const CKey& aKey)
1.391 + {
1.392 + Reset();
1.393 + SetKeyL(aKey);
1.394 + }
1.395 +
1.396 +
1.397 +CCMacImpl* CCMacImpl::CopyL()
1.398 + {
1.399 + CCMacImpl* clone = new(ELeave) CCMacImpl(*this);
1.400 + CleanupStack::PushL(clone);
1.401 + clone->iKey = CKey::NewL(*iKey);
1.402 + CryptoSpi::CSymmetricCipherFactory::CreateSymmetricCipherL(clone->iCipherImpl,
1.403 + CryptoSpi::KAesUid,
1.404 + *iKey,
1.405 + CryptoSpi::KCryptoModeEncryptUid,
1.406 + CryptoSpi::KOperationModeCBCUid,
1.407 + CryptoSpi::KPaddingModeNoneUid,
1.408 + NULL);
1.409 + clone->iCipherImpl->SetIvL(TPtrC8(clone->iE, KMacBlockSize));
1.410 + CleanupStack::Pop();
1.411 + return clone;
1.412 + }
1.413 +
1.414 +CCMacImpl* CCMacImpl::ReplicateL()
1.415 + {
1.416 + CCMacImpl* replica = CopyL();
1.417 + replica->Reset();
1.418 + return replica;
1.419 + }