os/security/cryptoplugins/cryptospiplugins/source/softwarecrypto/symmetriccipherimpl.cpp
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/security/cryptoplugins/cryptospiplugins/source/softwarecrypto/symmetriccipherimpl.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,650 @@
1.4 +/*
1.5 +* Copyright (c) 2007-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 +*
1.19 +*/
1.20 +
1.21 +
1.22 +#include "symmetriccipherimpl.h"
1.23 +
1.24 +#include <e32def.h>
1.25 +#include <cryptostrength.h>
1.26 +#include <cryptospi/cryptospidef.h>
1.27 +#include "keys.h"
1.28 +#include <cryptopanic.h>
1.29 +#include <cryptospi/plugincharacteristics.h>
1.30 +#include "pluginconfig.h"
1.31 +#include <securityerr.h>
1.32 +#include "common/inlines.h"
1.33 +
1.34 +using namespace SoftwareCrypto;
1.35 +
1.36 +//
1.37 +// Implementation of Symmetric Cipher class
1.38 +//
1.39 +CSymmetricCipherImpl::CSymmetricCipherImpl()
1.40 + {
1.41 + }
1.42 +
1.43 +void CSymmetricCipherImpl::ConstructL(const CKey& aKey)
1.44 + {
1.45 + DoSetKeyL(aKey);
1.46 + }
1.47 +
1.48 +void CSymmetricCipherImpl::SecureDelete(HBufC8*& aBuffer)
1.49 + {
1.50 + if (aBuffer)
1.51 + {
1.52 + aBuffer->Des().FillZ();
1.53 + }
1.54 + delete aBuffer;
1.55 + aBuffer = 0;
1.56 + }
1.57 +
1.58 +CSymmetricCipherImpl::~CSymmetricCipherImpl()
1.59 + {
1.60 + SecureDelete(iKey);
1.61 + }
1.62 +
1.63 +void CSymmetricCipherImpl::Close()
1.64 + {
1.65 + delete this;
1.66 + }
1.67 +
1.68 +TAny* CSymmetricCipherImpl::GetExtension(TUid /*aExtensionId*/)
1.69 + {
1.70 + return 0;
1.71 + }
1.72 +
1.73 +void CSymmetricCipherImpl::GetCharacteristicsL(const TAny*& aPluginCharacteristics)
1.74 + {
1.75 + TInt numCiphers = sizeof(KSymmetricCipherCharacteristics)/sizeof(TSymmetricCipherCharacteristics*);
1.76 + TInt32 implUid = ImplementationUid().iUid;
1.77 + for (TInt i = 0; i < numCiphers; ++i)
1.78 + {
1.79 + if (KSymmetricCipherCharacteristics[i]->cmn.iImplementationUID == implUid)
1.80 + {
1.81 + aPluginCharacteristics = KSymmetricCipherCharacteristics[i];
1.82 + break;
1.83 + }
1.84 + }
1.85 + }
1.86 +
1.87 +TInt CSymmetricCipherImpl::GetKeyStrength() const
1.88 + {
1.89 + return BytesToBits(iKey->Length());
1.90 + }
1.91 +
1.92 +HBufC8* CSymmetricCipherImpl::ExtractKeyDataLC(const CKey& aKey) const
1.93 + {
1.94 + const TDesC8& keyContent = aKey.GetTDesC8L(KSymmetricKeyParameterUid);
1.95 + return keyContent.AllocLC();
1.96 + }
1.97 +
1.98 +TInt CSymmetricCipherImpl::KeySize() const
1.99 + {
1.100 + // return key size in BITS
1.101 + return BytesToBits(iKeyBytes);
1.102 + }
1.103 +
1.104 +void CSymmetricCipherImpl::DoSetKeyL(const CKey& aKey)
1.105 + {
1.106 + HBufC8* key = ExtractKeyDataLC(aKey);
1.107 + TInt keyLength(key->Length());
1.108 +
1.109 + TCrypto::IsSymmetricWeakEnoughL(BytesToBits(keyLength));
1.110 + if (! IsValidKeyLength(keyLength))
1.111 + {
1.112 + CleanupStack::PopAndDestroy(key);
1.113 + User::Leave(KErrNotSupported);
1.114 + }
1.115 +
1.116 + SecureDelete(iKey);
1.117 + CleanupStack::Pop(key);
1.118 + iKey = key;
1.119 + iKeyBytes = keyLength;
1.120 + }
1.121 +
1.122 +//
1.123 +// Implementation of Symmetric Stream Cipher
1.124 +//
1.125 +CSymmetricStreamCipherImpl::CSymmetricStreamCipherImpl()
1.126 + {
1.127 + }
1.128 +
1.129 +CSymmetricStreamCipherImpl::~CSymmetricStreamCipherImpl()
1.130 + {
1.131 + }
1.132 +
1.133 +void CSymmetricStreamCipherImpl::SetKeyL(const CKey& aKey)
1.134 + {
1.135 + DoSetKeyL(aKey);
1.136 + TCrypto::IsSymmetricWeakEnoughL(GetKeyStrength());
1.137 + Reset();
1.138 + }
1.139 +
1.140 +void CSymmetricStreamCipherImpl::ConstructL(const CKey& aKey)
1.141 + {
1.142 + CSymmetricCipherImpl::ConstructL(aKey);
1.143 + }
1.144 +
1.145 +TInt CSymmetricStreamCipherImpl::BlockSize() const
1.146 + {
1.147 + // return block size in BITS
1.148 + return BYTE_BITS;
1.149 + }
1.150 +
1.151 +void CSymmetricStreamCipherImpl::SetCryptoModeL(TUid /*aCryptoMode*/)
1.152 + {
1.153 + // Call the reset method.
1.154 + Reset();
1.155 + }
1.156 +
1.157 +TInt CSymmetricStreamCipherImpl::MaxOutputLength(TInt aInputLength) const
1.158 + {
1.159 + return aInputLength;
1.160 + }
1.161 +
1.162 +TInt CSymmetricStreamCipherImpl::MaxFinalOutputLength(TInt aInputLength) const
1.163 + {
1.164 + return aInputLength;
1.165 + }
1.166 +
1.167 +void CSymmetricStreamCipherImpl::ProcessL(const TDesC8& aInput, TDes8& aOutput)
1.168 + {
1.169 + TInt outputIndex = aOutput.Size();
1.170 +
1.171 + // aOutput may already have outputIndex bytes of data in it
1.172 + // check there will still be enough space to process the result
1.173 + __ASSERT_DEBUG(aOutput.MaxLength() - outputIndex >= MaxOutputLength(aInput.Length()), User::Panic(KCryptoPanic, ECryptoPanicOutputDescriptorOverflow));
1.174 +
1.175 + aOutput.Append(aInput);
1.176 +
1.177 + TPtr8 transformBuf((TUint8*)(aOutput.Ptr()) + outputIndex, aInput.Size(),
1.178 + aInput.Size());
1.179 + DoProcess(transformBuf);
1.180 + }
1.181 +
1.182 +void CSymmetricStreamCipherImpl::ProcessFinalL(const TDesC8& aInput, TDes8& aOutput)
1.183 + {
1.184 + ProcessL(aInput, aOutput);
1.185 + }
1.186 +
1.187 +//
1.188 +// Implementation of Symmetric Block Cipher
1.189 +//
1.190 +CSymmetricBlockCipherImpl::CSymmetricBlockCipherImpl(
1.191 + TUint8 aBlockBytes,
1.192 + TUid aCryptoMode,
1.193 + TUid aOperationMode,
1.194 + TUid aPaddingMode) :
1.195 + iBlockBytes(aBlockBytes),
1.196 + iCryptoMode(aCryptoMode),
1.197 + iOperationMode(aOperationMode),
1.198 + iPaddingMode(aPaddingMode),
1.199 + iBufferedPlaintextPtr(0,0,0),
1.200 + iCtrUnusedKeystreamPtr(0,0,0)
1.201 + {
1.202 + }
1.203 +
1.204 +CSymmetricBlockCipherImpl::~CSymmetricBlockCipherImpl()
1.205 + {
1.206 + delete iPadding;
1.207 + delete [] iRegister;
1.208 + delete [] iCurrentCipherText;
1.209 + delete iBufferedPlaintext;
1.210 + delete iCtrUnusedKeystream;
1.211 + iIv.Close();
1.212 + iInputStore.Close();
1.213 + iPaddingBlock.Close();
1.214 + }
1.215 +
1.216 +
1.217 +void CSymmetricBlockCipherImpl::ConstructL(const CKey& aKey)
1.218 + {
1.219 + CSymmetricCipherImpl::ConstructL(aKey);
1.220 + DoSetOperationModeL(iOperationMode);
1.221 + DoSetCryptoModeL(iCryptoMode);
1.222 + DoSetPaddingModeL(iPaddingMode);
1.223 +
1.224 + iInputStore.ReAllocL(iBlockBytes);
1.225 + iPaddingBlock.ReAllocL(iBlockBytes);
1.226 +
1.227 + iRegister = new(ELeave) TUint32[iBlockBytes/4];
1.228 + iRegisterPtr = reinterpret_cast<TUint8*>(iRegister);
1.229 +
1.230 + iCurrentCipherText = new(ELeave) TUint32[iBlockBytes/4];
1.231 + iCurrentCipherTextPtr = reinterpret_cast<TUint8*>(iCurrentCipherText);
1.232 +
1.233 + iBufferedPlaintext = HBufC8::NewL(iBlockBytes);
1.234 + iBufferedPlaintextPtr.Set(iBufferedPlaintext->Des());
1.235 +
1.236 + iCtrUnusedKeystream = HBufC8::NewL(iBlockBytes);
1.237 + iCtrUnusedKeystreamPtr.Set(iCtrUnusedKeystream->Des());
1.238 + }
1.239 +
1.240 +void CSymmetricBlockCipherImpl::Reset()
1.241 + {
1.242 + iInputStore.Zero();
1.243 + iPaddingBlock.Zero();
1.244 + iCtrUnusedKeystreamPtr.Zero();
1.245 +
1.246 + if (iOperationMode.iUid == KOperationModeCBC)
1.247 + {
1.248 + // only copy the IV if it is already set
1.249 + if (iIv.MaxLength() > 0)
1.250 + {
1.251 + Mem::Copy(iRegisterPtr, &iIv[0], iBlockBytes);
1.252 + }
1.253 + }
1.254 + }
1.255 +
1.256 +void CSymmetricBlockCipherImpl::SetKeyL(const CKey& aKey)
1.257 + {
1.258 + DoSetKeyL(aKey);
1.259 + TCrypto::IsSymmetricWeakEnoughL(GetKeyStrength());
1.260 + SetKeySchedule();
1.261 + Reset();
1.262 + }
1.263 +
1.264 +void CSymmetricBlockCipherImpl::SetOperationModeL(TUid aOperationMode)
1.265 + {
1.266 + DoSetOperationModeL(aOperationMode);
1.267 + Reset();
1.268 + }
1.269 +
1.270 +void CSymmetricBlockCipherImpl::SetCryptoModeL(TUid aCryptoMode)
1.271 + {
1.272 + DoSetCryptoModeL(aCryptoMode);
1.273 + SetKeySchedule();
1.274 + Reset();
1.275 + }
1.276 +
1.277 +void CSymmetricBlockCipherImpl::SetPaddingModeL(TUid aPaddingMode)
1.278 + {
1.279 + DoSetPaddingModeL(aPaddingMode);
1.280 + Reset();
1.281 + }
1.282 +
1.283 +void CSymmetricBlockCipherImpl::SetIvL(const TDesC8& aIv)
1.284 + {
1.285 + if ((iOperationMode.iUid != KOperationModeCBC) && (iOperationMode.iUid != KOperationModeCTR))
1.286 + {
1.287 + User::Leave(KErrNotSupported);
1.288 + }
1.289 + DoSetIvL(aIv);
1.290 + Reset();
1.291 + }
1.292 +
1.293 +void CSymmetricBlockCipherImpl::DoSetOperationModeL(TUid aOperationMode)
1.294 + {
1.295 + switch (aOperationMode.iUid)
1.296 + {
1.297 + case KOperationModeNone:
1.298 + case KOperationModeECB:
1.299 + case KOperationModeCBC:
1.300 + break;
1.301 + case KOperationModeCTR:
1.302 + SetCryptoModeL(KCryptoModeEncryptUid);
1.303 + break;
1.304 + default:
1.305 + User::Leave(KErrNotSupported);
1.306 + }
1.307 + iOperationMode = aOperationMode;
1.308 + }
1.309 +
1.310 +void CSymmetricBlockCipherImpl::DoSetCryptoModeL(TUid aCryptoMode)
1.311 + {
1.312 + switch (aCryptoMode.iUid)
1.313 + {
1.314 + case KCryptoModeEncrypt:
1.315 + break;
1.316 + case KCryptoModeDecrypt:
1.317 + if (iOperationMode.iUid == KOperationModeCTR)
1.318 + {
1.319 + return;
1.320 + }
1.321 + break;
1.322 + default:
1.323 + User::Leave(KErrNotSupported);
1.324 + }
1.325 + iCryptoMode = aCryptoMode;
1.326 + }
1.327 +
1.328 +void CSymmetricBlockCipherImpl::DoSetPaddingModeL(TUid aPaddingMode)
1.329 + {
1.330 + CPadding* padding(0);
1.331 + switch (aPaddingMode.iUid)
1.332 + {
1.333 + case KPaddingModeNone:
1.334 + padding = CPaddingNone::NewL(iBlockBytes);
1.335 + break;
1.336 + case KPaddingModeSSLv3:
1.337 + padding = CPaddingSSLv3::NewL(iBlockBytes);
1.338 + break;
1.339 + case KPaddingModePKCS7:
1.340 + padding = CPaddingPKCS7::NewL(iBlockBytes);
1.341 + break;
1.342 + default:
1.343 + User::Leave(KErrNotSupported);
1.344 + }
1.345 + delete iPadding;
1.346 + iPadding = padding;
1.347 + iPaddingMode = aPaddingMode;
1.348 + }
1.349 +
1.350 +void CSymmetricBlockCipherImpl::DoSetIvL(const TDesC8& aIv)
1.351 + {
1.352 + iIv.ReAllocL(iBlockBytes);
1.353 + iIv.SetLength(iBlockBytes);
1.354 +
1.355 + iIv.Zero();
1.356 + if (aIv.Length() != iBlockBytes)
1.357 + {
1.358 + User::Leave(KErrArgument);
1.359 + }
1.360 + iIv = aIv;
1.361 + Mem::Copy(iRegisterPtr, &iIv[0], iBlockBytes); //for CTR mode
1.362 +
1.363 + }
1.364 +
1.365 +TInt CSymmetricBlockCipherImpl::BlockSize() const
1.366 + {
1.367 + // return block size in BITS
1.368 + if (iOperationMode.iUid == KOperationModeCTR)
1.369 + {
1.370 + return 8;
1.371 + }
1.372 + else
1.373 + {
1.374 + return BytesToBits(iBlockBytes);
1.375 + }
1.376 + }
1.377 +
1.378 +TInt CSymmetricBlockCipherImpl::MaxOutputLength(TInt aInputLength) const
1.379 + {
1.380 + if (iOperationMode.iUid == KOperationModeCTR)
1.381 + {
1.382 + return aInputLength;
1.383 + }
1.384 + else
1.385 + {
1.386 + // The maximum output length required for Process is equal to the
1.387 + // size of the number of whole input blocks available.
1.388 + //
1.389 + // The block bytes is a power of two so we can use this to avoid
1.390 + // doing a real mod operation
1.391 + TUint inputStoreLength(iInputStore.Length());
1.392 + TInt rem = (aInputLength + inputStoreLength) & (iBlockBytes - 1);
1.393 + return (aInputLength + inputStoreLength - rem);
1.394 + }
1.395 + }
1.396 +
1.397 +TInt CSymmetricBlockCipherImpl::MaxFinalOutputLength(TInt aInputLength) const
1.398 + {
1.399 + if (iOperationMode.iUid == KOperationModeCTR)
1.400 + {
1.401 + return aInputLength;
1.402 + }
1.403 + else if (iCryptoMode.iUid == KCryptoModeEncrypt)
1.404 + {
1.405 + return iPadding->MaxPaddedLength(iInputStore.Length() + aInputLength);
1.406 + }
1.407 + else
1.408 + {
1.409 + return iPadding->MaxUnPaddedLength(aInputLength + iInputStore.Size());
1.410 + }
1.411 + }
1.412 +
1.413 +void CSymmetricBlockCipherImpl::ProcessL(const TDesC8& aInput, TDes8& aOutput)
1.414 + {
1.415 + // if we're running in CBC or CTR mode then we must have an IV set before we can
1.416 + // do any processing ie call SetIvL() before this method
1.417 + if ((iOperationMode.iUid == KOperationModeCBC) || (iOperationMode.iUid == KOperationModeCTR))
1.418 + {
1.419 + if (iIv.MaxLength() == 0)
1.420 + {
1.421 + User::Leave(KErrNotSupported);
1.422 + }
1.423 + }
1.424 +
1.425 + TInt inputLength(aInput.Length());
1.426 + TInt inputStoreLength(iInputStore.Length());
1.427 +
1.428 + if (MaxOutputLength(inputLength) > aOutput.MaxLength())
1.429 + {
1.430 + User::Leave(KErrOverflow);
1.431 + }
1.432 +
1.433 + if (iOperationMode.iUid == KOperationModeCTR)
1.434 + {
1.435 + ProcessCtrL(aInput, aOutput);
1.436 + }
1.437 + else
1.438 + {
1.439 + TUint8 blockSizeLog = CryptoLog2(iBlockBytes);
1.440 + TInt wholeBlocks = (inputLength + inputStoreLength) >> blockSizeLog;
1.441 + TInt wholeBlocksSize = wholeBlocks << blockSizeLog;
1.442 +
1.443 + if (wholeBlocks)
1.444 + {
1.445 + TInt outputLength(aOutput.Length());
1.446 +
1.447 + if (inputStoreLength > 0)
1.448 + {
1.449 + aOutput.Append(iInputStore);
1.450 + iInputStore.Zero();
1.451 + }
1.452 + aOutput.Append(aInput.Left(wholeBlocksSize - inputStoreLength));
1.453 + Transform(const_cast<TUint8*>(aOutput.Ptr()) + outputLength, wholeBlocks);
1.454 + }
1.455 +
1.456 + TInt remainingBytes = inputLength + inputStoreLength - wholeBlocksSize;
1.457 + if (remainingBytes > 0)
1.458 + {
1.459 + iInputStore.Append(aInput.Right(remainingBytes));
1.460 + }
1.461 + }
1.462 + }
1.463 +
1.464 +void CSymmetricBlockCipherImpl::ProcessFinalL(const TDesC8& aInput, TDes8& aOutput)
1.465 + {
1.466 + if (iOperationMode.iUid == KOperationModeCTR)
1.467 + {
1.468 + ProcessL(aInput, aOutput);
1.469 + }
1.470 + else
1.471 + {
1.472 + // if we're running in CBC mode then we must have an IV set before we can
1.473 + // do any processing ie call SetIvL() before this method
1.474 + if (iOperationMode.iUid == KOperationModeCBC)
1.475 + {
1.476 + if (iIv.MaxLength() == 0)
1.477 + {
1.478 + User::Leave(KErrNotSupported);
1.479 + }
1.480 + }
1.481 +
1.482 + if (iCryptoMode.iUid == KCryptoModeEncrypt)
1.483 + {
1.484 + return DoProcessFinalEncryptL(aInput, aOutput);
1.485 + }
1.486 + else
1.487 + {
1.488 + return DoProcessFinalDecryptL(aInput, aOutput);
1.489 + }
1.490 + }
1.491 + }
1.492 +
1.493 +void CSymmetricBlockCipherImpl::DoProcessFinalEncryptL(const TDesC8& aInput, TDes8& aOutput)
1.494 + {
1.495 + if (MaxFinalOutputLength(aInput.Length()) > aOutput.MaxLength() - aOutput.Length())
1.496 + {
1.497 + User::Leave(KErrOverflow);
1.498 + }
1.499 +
1.500 + // process everything up to the last (possibly empty block)
1.501 + TInt outputStartIndex = aOutput.Length();
1.502 + ProcessL(aInput, aOutput);
1.503 +
1.504 + // pad the plaintext
1.505 + iPadding->PadL(iInputStore, iPaddingBlock);
1.506 +
1.507 + // if padding required
1.508 + if (iPaddingBlock.Length() > 0)
1.509 + {
1.510 + iInputStore.Zero();
1.511 +
1.512 + // make sure the output is a multiple of the block size
1.513 + User::LeaveIfError(((aOutput.Length() - outputStartIndex + iPaddingBlock.Length()) % iBlockBytes) == 0 ? KErrNone : KErrInvalidPadding);
1.514 +
1.515 + outputStartIndex = aOutput.Length();
1.516 + aOutput.Append(iPaddingBlock);
1.517 + iPaddingBlock.Zero();
1.518 + TransformEncrypt(const_cast<TUint8*>(aOutput.Ptr()) + outputStartIndex, 1);
1.519 + }
1.520 + }
1.521 +
1.522 +void CSymmetricBlockCipherImpl::DoProcessFinalDecryptL(const TDesC8& aInput, TDes8& aOutput)
1.523 + {
1.524 + if (MaxFinalOutputLength(aInput.Length()) > aOutput.MaxLength() - aOutput.Length())
1.525 + {
1.526 + User::Leave(KErrOverflow);
1.527 + }
1.528 +
1.529 + // Input length (including inputstore) must be a multiple of the
1.530 + // block size in length
1.531 + if ((aInput.Length() + iInputStore.Length()) & (iBlockBytes - 1))
1.532 + {
1.533 + User::Leave(KErrArgument);
1.534 + }
1.535 +
1.536 + if(aInput.Length() > iBlockBytes)
1.537 + {
1.538 + HBufC8* processBuf = HBufC8::NewLC(MaxFinalOutputLength(aInput.Length()));
1.539 + TPtr8 processPtr = processBuf->Des();
1.540 +
1.541 + ProcessL(aInput, processPtr);
1.542 +
1.543 + ASSERT(iInputStore.Length()==0); // all the blocks should have been decrypted
1.544 +
1.545 + // Unpad processPtr into aOutput
1.546 + iPadding->UnPadL(processPtr, aOutput);
1.547 +
1.548 + CleanupStack::PopAndDestroy(processBuf);
1.549 + }
1.550 + else
1.551 + {
1.552 + // now contains the final ciphertext block
1.553 + iInputStore.Append(aInput);
1.554 +
1.555 + // Decrypt the last _padding_ blocksize into a new buffer
1.556 + TransformDecrypt(const_cast<TUint8*>(iInputStore.Ptr()), 1);
1.557 +
1.558 + // Unpad the last block and append to output
1.559 + iPadding->UnPadL(iInputStore, aOutput);
1.560 + }
1.561 +
1.562 + iPaddingBlock.Zero();
1.563 + iInputStore.Zero();
1.564 + }
1.565 +
1.566 +
1.567 +/**
1.568 +CTR mode behaves like a stream cipher, accepting input of any arbitrary length. This results
1.569 +in a significant body of code that behaves fundamentally differently to the ECB and CBC modes.
1.570 +ProcessCtrL() is called by ProcessL() when operating in CTR mode, wrapping up all this
1.571 +functionality into a separate method for clarity.
1.572 +
1.573 +Encrypting zero-filled bytes will return the keystream since the output of Transformation is simply
1.574 +the input XORed with the keystream.
1.575 +
1.576 +See: http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
1.577 +*/
1.578 +void CSymmetricBlockCipherImpl::ProcessCtrL(const TDesC8& aInput, TDes8& aOutput)
1.579 + {
1.580 + TInt inputLength(aInput.Length());
1.581 +
1.582 + TInt outputLength(aOutput.Length());
1.583 + TInt amountToXor = Min(iCtrUnusedKeystreamPtr.Length(), inputLength);
1.584 +
1.585 + // Try applying previously unused key stream bytes.
1.586 + if (amountToXor > 0)
1.587 + {
1.588 + aOutput.Append(aInput.Left(amountToXor));
1.589 + for (TInt i = 0; i < amountToXor; ++i)
1.590 + {
1.591 + aOutput[outputLength + i] ^= iCtrUnusedKeystreamPtr[i];
1.592 + }
1.593 + iCtrUnusedKeystreamPtr = iCtrUnusedKeystreamPtr.RightTPtr((iCtrUnusedKeystreamPtr.Length() - amountToXor));
1.594 + }
1.595 +
1.596 + TInt amountToEncode = inputLength - amountToXor;
1.597 +
1.598 + if ((iCtrUnusedKeystreamPtr.Length() == 0) && (amountToEncode > 0))
1.599 + {
1.600 + // For each whole block's worth of input, transform it.
1.601 + TInt wholeBlocks = (amountToEncode) / iBlockBytes;
1.602 + TInt wholeBlocksSize = wholeBlocks * iBlockBytes;
1.603 + outputLength = aOutput.Length();
1.604 +
1.605 + if (wholeBlocks)
1.606 + {
1.607 + aOutput.Append(aInput.Mid(amountToXor, wholeBlocksSize));
1.608 + Transform(const_cast<TUint8*>(aOutput.Ptr()) + outputLength, wholeBlocks);
1.609 + }
1.610 +
1.611 + // CTR mode can handle arbitrary sized inputs. Here any remaining input data of less than the block size
1.612 + // is padded with zeros and then transformed. On return this padded section of the block will contain the next
1.613 + // sequence of keystream, which is copied to iCtrUnusedKeystream for use next time ProcessCtrL() is called.
1.614 + TInt remainingBytes = amountToEncode - wholeBlocksSize;
1.615 + iCtrUnusedKeystreamPtr = iCtrUnusedKeystream->Des();
1.616 + iCtrUnusedKeystreamPtr.SetMax();
1.617 + iCtrUnusedKeystreamPtr.FillZ();
1.618 + iCtrUnusedKeystreamPtr.Copy(aInput.Right(remainingBytes));
1.619 + iCtrUnusedKeystreamPtr.SetLength(iBlockBytes);
1.620 +
1.621 + Transform(const_cast<TUint8*>(iCtrUnusedKeystreamPtr.Ptr()), 1);
1.622 +
1.623 + aOutput.Append(iCtrUnusedKeystreamPtr.Left(remainingBytes));
1.624 +
1.625 + iCtrUnusedKeystreamPtr = iCtrUnusedKeystreamPtr.RightTPtr((iCtrUnusedKeystreamPtr.Length() - remainingBytes));
1.626 + }
1.627 + }
1.628 +
1.629 +
1.630 +
1.631 +// Methods implemented in subclass. No coverage here.
1.632 +#ifdef _BullseyeCoverage
1.633 +#pragma suppress_warnings on
1.634 +#pragma BullseyeCoverage off
1.635 +#pragma suppress_warnings off
1.636 +#endif
1.637 +void CSymmetricStreamCipherImpl::SetOperationModeL(TUid /*aOperationMode*/)
1.638 + {
1.639 + // Override in subclass
1.640 + User::Leave(KErrNotSupported);
1.641 + }
1.642 +
1.643 +void CSymmetricStreamCipherImpl::SetPaddingModeL(TUid /*aPaddingMode*/)
1.644 + {
1.645 + // Override in subclass
1.646 + User::Leave(KErrNotSupported);
1.647 + }
1.648 +
1.649 +void CSymmetricStreamCipherImpl::SetIvL(const TDesC8& /*aIv*/)
1.650 + {
1.651 + // Override in subclass
1.652 + User::Leave(KErrNotSupported);
1.653 + }