1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/security/crypto/weakcryptospi/test/tplugins/src/symmetriccipherimpl.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,524 @@
1.4 +/*
1.5 +* Copyright (c) 2007-2010 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 <cryptospi/keys.h>
1.28 +#include <cryptospi/plugincharacteristics.h>
1.29 +#include "pluginconfig.h"
1.30 +#include <cryptopanic.h>
1.31 +#include <securityerr.h>
1.32 +#include "../../../source/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 8;
1.149 + }
1.150 +
1.151 +void CSymmetricStreamCipherImpl::SetOperationModeL(TUid /*aOperationMode*/)
1.152 + {
1.153 + User::Leave(KErrNotSupported);
1.154 + }
1.155 +
1.156 +void CSymmetricStreamCipherImpl::SetCryptoModeL(TUid /*aCryptoMode*/)
1.157 + {
1.158 + // Call the reset method.
1.159 + Reset();
1.160 + }
1.161 +
1.162 +void CSymmetricStreamCipherImpl::SetPaddingModeL(TUid /*aPaddingMode*/)
1.163 + {
1.164 + User::Leave(KErrNotSupported);
1.165 + }
1.166 +
1.167 +void CSymmetricStreamCipherImpl::SetIvL(const TDesC8& /*aIv*/)
1.168 + {
1.169 + User::Leave(KErrNotSupported);
1.170 + }
1.171 +
1.172 +TInt CSymmetricStreamCipherImpl::MaxOutputLength(TInt aInputLength) const
1.173 + {
1.174 + return aInputLength;
1.175 + }
1.176 +
1.177 +TInt CSymmetricStreamCipherImpl::MaxFinalOutputLength(TInt aInputLength) const
1.178 + {
1.179 + return aInputLength;
1.180 + }
1.181 +
1.182 +void CSymmetricStreamCipherImpl::ProcessL(const TDesC8& aInput, TDes8& aOutput)
1.183 + {
1.184 + TInt outputIndex = aOutput.Size();
1.185 +
1.186 + // aOutput may already have outputIndex bytes of data in it
1.187 + // check there will still be enough space to process the result
1.188 + __ASSERT_DEBUG(aOutput.MaxLength() - outputIndex >= MaxOutputLength(aInput.Length()), User::Panic(KCryptoPanic, ECryptoPanicOutputDescriptorOverflow));
1.189 +
1.190 + aOutput.Append(aInput);
1.191 +
1.192 + TPtr8 transformBuf((TUint8*)(aOutput.Ptr()) + outputIndex, aInput.Size(),
1.193 + aInput.Size());
1.194 + DoProcess(transformBuf);
1.195 + }
1.196 +
1.197 +void CSymmetricStreamCipherImpl::ProcessFinalL(const TDesC8& aInput, TDes8& aOutput)
1.198 + {
1.199 + ProcessL(aInput, aOutput);
1.200 + }
1.201 +
1.202 +//
1.203 +// Implementation of Symmetric Block Cipher
1.204 +//
1.205 +CSymmetricBlockCipherImpl::CSymmetricBlockCipherImpl(
1.206 + TUint8 aBlockBytes,
1.207 + TUid aCryptoMode,
1.208 + TUid aOperationMode,
1.209 + TUid aPaddingMode) :
1.210 + iBlockBytes(aBlockBytes),
1.211 + iCryptoMode(aCryptoMode),
1.212 + iOperationMode(aOperationMode),
1.213 + iPaddingMode(aPaddingMode)
1.214 + {
1.215 + }
1.216 +
1.217 +CSymmetricBlockCipherImpl::~CSymmetricBlockCipherImpl()
1.218 + {
1.219 + delete iPadding;
1.220 + delete iCbcRegister;
1.221 + delete iCurrentCipherText;
1.222 + iIv.Close();
1.223 + iInputStore.Close();
1.224 + iPaddingBlock.Close();
1.225 + }
1.226 +
1.227 +
1.228 +void CSymmetricBlockCipherImpl::ConstructL(const CKey& aKey)
1.229 + {
1.230 + CSymmetricCipherImpl::ConstructL(aKey);
1.231 + DoSetOperationModeL(iOperationMode);
1.232 + DoSetCryptoModeL(iCryptoMode);
1.233 + DoSetPaddingModeL(iPaddingMode);
1.234 +
1.235 + iInputStore.ReAllocL(iBlockBytes);
1.236 + iPaddingBlock.ReAllocL(iBlockBytes);
1.237 +
1.238 + iCbcRegister = new(ELeave) TUint32[iBlockBytes/4];
1.239 + iCbcRegisterPtr = reinterpret_cast<TUint8*>(iCbcRegister);
1.240 +
1.241 + iCurrentCipherText = new(ELeave) TUint32[iBlockBytes/4];
1.242 + iCurrentCipherTextPtr = reinterpret_cast<TUint8*>(iCurrentCipherText);
1.243 + }
1.244 +
1.245 +void CSymmetricBlockCipherImpl::Reset()
1.246 + {
1.247 + iInputStore.Zero();
1.248 + iPaddingBlock.Zero();
1.249 +
1.250 + if (iOperationMode.iUid == KOperationModeCBC)
1.251 + {
1.252 + // only copy the IV if it is already set
1.253 + if (iIv.MaxLength() > 0)
1.254 + {
1.255 + Mem::Copy(iCbcRegisterPtr, &iIv[0], iBlockBytes);
1.256 + }
1.257 + }
1.258 + }
1.259 +
1.260 +void CSymmetricBlockCipherImpl::SetKeyL(const CKey& aKey)
1.261 + {
1.262 + DoSetKeyL(aKey);
1.263 + TCrypto::IsSymmetricWeakEnoughL(GetKeyStrength());
1.264 + SetKeySchedule();
1.265 + Reset();
1.266 + }
1.267 +
1.268 +void CSymmetricBlockCipherImpl::SetOperationModeL(TUid aOperationMode)
1.269 + {
1.270 + DoSetOperationModeL(aOperationMode);
1.271 + Reset();
1.272 + }
1.273 +
1.274 +void CSymmetricBlockCipherImpl::SetCryptoModeL(TUid aCryptoMode)
1.275 + {
1.276 + DoSetCryptoModeL(aCryptoMode);
1.277 + SetKeySchedule();
1.278 + Reset();
1.279 + }
1.280 +
1.281 +void CSymmetricBlockCipherImpl::SetPaddingModeL(TUid aPaddingMode)
1.282 + {
1.283 + DoSetPaddingModeL(aPaddingMode);
1.284 + Reset();
1.285 + }
1.286 +
1.287 +void CSymmetricBlockCipherImpl::SetIvL(const TDesC8& aIv)
1.288 + {
1.289 + if (iOperationMode.iUid != KOperationModeCBC)
1.290 + {
1.291 + User::Leave(KErrNotSupported);
1.292 + }
1.293 + DoSetIvL(aIv);
1.294 + Reset();
1.295 + }
1.296 +
1.297 +void CSymmetricBlockCipherImpl::DoSetOperationModeL(TUid aOperationMode)
1.298 + {
1.299 + switch (aOperationMode.iUid)
1.300 + {
1.301 + case KOperationModeNone:
1.302 + case KOperationModeECB:
1.303 + case KOperationModeCBC:
1.304 + break;
1.305 + default:
1.306 + User::Leave(KErrNotSupported);
1.307 + }
1.308 + iOperationMode = aOperationMode;
1.309 + }
1.310 +
1.311 +void CSymmetricBlockCipherImpl::DoSetCryptoModeL(TUid aCryptoMode)
1.312 + {
1.313 + switch (aCryptoMode.iUid)
1.314 + {
1.315 + case KCryptoModeEncrypt:
1.316 + case KCryptoModeDecrypt:
1.317 + break;
1.318 + default:
1.319 + User::Leave(KErrNotSupported);
1.320 + }
1.321 + iCryptoMode = aCryptoMode;
1.322 + }
1.323 +
1.324 +void CSymmetricBlockCipherImpl::DoSetPaddingModeL(TUid aPaddingMode)
1.325 + {
1.326 + CPadding* padding(0);
1.327 + switch (aPaddingMode.iUid)
1.328 + {
1.329 + case KPaddingModeNone:
1.330 + padding = CPaddingNone::NewL(iBlockBytes);
1.331 + break;
1.332 + case KPaddingModeSSLv3:
1.333 + padding = CPaddingSSLv3::NewL(iBlockBytes);
1.334 + break;
1.335 + case KPaddingModePKCS7:
1.336 + padding = CPaddingPKCS7::NewL(iBlockBytes);
1.337 + break;
1.338 + default:
1.339 + User::Leave(KErrNotSupported);
1.340 + }
1.341 + delete iPadding;
1.342 + iPadding = padding;
1.343 + iPaddingMode = aPaddingMode;
1.344 + }
1.345 +
1.346 +void CSymmetricBlockCipherImpl::DoSetIvL(const TDesC8& aIv)
1.347 + {
1.348 + iIv.ReAllocL(iBlockBytes);
1.349 + iIv.SetLength(iBlockBytes);
1.350 +
1.351 + iIv.Zero();
1.352 + if (aIv.Length() != iBlockBytes)
1.353 + {
1.354 + User::Leave(KErrArgument);
1.355 + }
1.356 + iIv = aIv;
1.357 + }
1.358 +
1.359 +TInt CSymmetricBlockCipherImpl::BlockSize() const
1.360 + {
1.361 + // return block size in BITS
1.362 + return BytesToBits(iBlockBytes);
1.363 + }
1.364 +
1.365 +TInt CSymmetricBlockCipherImpl::MaxOutputLength(TInt aInputLength) const
1.366 + {
1.367 + // The maximum output length required for Process is equal to the
1.368 + // size of the number of whole input blocks available.
1.369 + //
1.370 + // The block bytes is a power of two so we can use this to avoid
1.371 + // doing a real mod operation
1.372 + TUint inputStoreLength(iInputStore.Length());
1.373 + TInt rem = (aInputLength + inputStoreLength) & (iBlockBytes - 1);
1.374 + return (aInputLength + inputStoreLength - rem);
1.375 + }
1.376 +
1.377 +TInt CSymmetricBlockCipherImpl::MaxFinalOutputLength(TInt aInputLength) const
1.378 + {
1.379 + if (iCryptoMode.iUid == KCryptoModeEncrypt)
1.380 + {
1.381 + return iPadding->MaxPaddedLength(iInputStore.Length() + aInputLength);
1.382 + }
1.383 + else
1.384 + {
1.385 + return iPadding->MaxUnPaddedLength(aInputLength + iInputStore.Size());
1.386 + }
1.387 + }
1.388 +
1.389 +void CSymmetricBlockCipherImpl::ProcessL(const TDesC8& aInput, TDes8& aOutput)
1.390 + {
1.391 + // if we're running in CBC mode then we must have an IV set before we can
1.392 + // do any processing ie call SetIvL() before this method
1.393 + if (iOperationMode.iUid == KOperationModeCBC)
1.394 + {
1.395 + if (iIv.MaxLength() == 0)
1.396 + {
1.397 + User::Leave(KErrNotSupported);
1.398 + }
1.399 + }
1.400 +
1.401 + TInt inputLength(aInput.Length());
1.402 + TInt inputStoreLength(iInputStore.Length());
1.403 +
1.404 + if (MaxOutputLength(inputLength) > aOutput.MaxLength())
1.405 + {
1.406 + User::Leave(KErrOverflow);
1.407 + }
1.408 +
1.409 + TUint8 blockSizeLog = CryptoLog2(iBlockBytes);
1.410 + TInt wholeBlocks = (inputLength + inputStoreLength) >> blockSizeLog;
1.411 + TInt wholeBlocksSize = wholeBlocks << blockSizeLog;
1.412 +
1.413 + if (wholeBlocks)
1.414 + {
1.415 + TInt outputLength(aOutput.Length());
1.416 +
1.417 + if (inputStoreLength > 0)
1.418 + {
1.419 + aOutput.Append(iInputStore);
1.420 + iInputStore.Zero();
1.421 + }
1.422 + aOutput.Append(aInput.Left(wholeBlocksSize - inputStoreLength));
1.423 + Transform(const_cast<TUint8*>(aOutput.Ptr()) + outputLength, wholeBlocks);
1.424 + }
1.425 +
1.426 + TInt remainingBytes = inputLength + inputStoreLength - wholeBlocksSize;
1.427 + if (remainingBytes > 0)
1.428 + {
1.429 + iInputStore.Append(aInput.Right(remainingBytes));
1.430 + }
1.431 + }
1.432 +
1.433 +void CSymmetricBlockCipherImpl::ProcessFinalL(const TDesC8& aInput, TDes8& aOutput)
1.434 + {
1.435 + // if we're running in CBC mode then we must have an IV set before we can
1.436 + // do any processing ie call SetIvL() before this method
1.437 + if (iOperationMode.iUid == KOperationModeCBC)
1.438 + {
1.439 + if (iIv.MaxLength() == 0)
1.440 + {
1.441 + User::Leave(KErrNotSupported);
1.442 + }
1.443 + }
1.444 +
1.445 + if (iCryptoMode.iUid == KCryptoModeEncrypt)
1.446 + {
1.447 + return DoProcessFinalEncryptL(aInput, aOutput);
1.448 + }
1.449 + else
1.450 + {
1.451 + return DoProcessFinalDecryptL(aInput, aOutput);
1.452 + }
1.453 + }
1.454 +
1.455 +void CSymmetricBlockCipherImpl::DoProcessFinalEncryptL(const TDesC8& aInput, TDes8& aOutput)
1.456 + {
1.457 + if (MaxFinalOutputLength(aInput.Length()) > aOutput.MaxLength() - aOutput.Length())
1.458 + {
1.459 + User::Leave(KErrOverflow);
1.460 + }
1.461 +
1.462 + // process everything up to the last (possibly empty block)
1.463 + TInt outputStartIndex = aOutput.Length();
1.464 + ProcessL(aInput, aOutput);
1.465 +
1.466 + // pad the plaintext
1.467 + iPadding->PadL(iInputStore, iPaddingBlock);
1.468 +
1.469 + // if padding required
1.470 + if (iPaddingBlock.Length() > 0)
1.471 + {
1.472 + iInputStore.Zero();
1.473 +
1.474 + // make sure the output is a multiple of the block size
1.475 + User::LeaveIfError(((aOutput.Length() - outputStartIndex + iPaddingBlock.Length()) % iBlockBytes) == 0 ? KErrNone : KErrInvalidPadding);
1.476 +
1.477 + outputStartIndex = aOutput.Length();
1.478 + aOutput.Append(iPaddingBlock);
1.479 + iPaddingBlock.Zero();
1.480 + TransformEncrypt(const_cast<TUint8*>(aOutput.Ptr()) + outputStartIndex, 1);
1.481 + }
1.482 + }
1.483 +
1.484 +void CSymmetricBlockCipherImpl::DoProcessFinalDecryptL(const TDesC8& aInput, TDes8& aOutput)
1.485 + {
1.486 + if (MaxFinalOutputLength(aInput.Length()) > aOutput.MaxLength() - aOutput.Length())
1.487 + {
1.488 + User::Leave(KErrOverflow);
1.489 + }
1.490 +
1.491 + // Input length (including inputstore) must be a multiple of the
1.492 + // block size in length
1.493 + if ((aInput.Length() + iInputStore.Length()) & (iBlockBytes - 1))
1.494 + {
1.495 + User::Leave(KErrArgument);
1.496 + }
1.497 +
1.498 + TInt bytesProcessed(0);
1.499 + if(aInput.Length() > iBlockBytes)
1.500 + {
1.501 + // the last block lies entirely within aInput so decrypt everything up
1.502 + // to this point.
1.503 + bytesProcessed = aInput.Length() - iBlockBytes;
1.504 + ProcessL(aInput.Left(bytesProcessed), aOutput);
1.505 + ASSERT(iInputStore.Length()==0); // all the blocks should have been decrypted
1.506 + }
1.507 + else
1.508 + {
1.509 + // if the input is less than one block in length then this + input
1.510 + // store should combine to give exactly one block of data
1.511 + ASSERT((iInputStore.Length() + aInput.Length()) == iBlockBytes);
1.512 + }
1.513 +
1.514 + // now contains the final ciphertext block
1.515 + iInputStore.Append(aInput.Right(aInput.Length() - bytesProcessed));
1.516 +
1.517 + // Decrypt the last _padding_ blocksize into a new buffer
1.518 + TransformDecrypt(const_cast<TUint8*>(iInputStore.Ptr()), 1);
1.519 +
1.520 + // Unpad the last block and append to output
1.521 + iPadding->UnPadL(iInputStore, aOutput);
1.522 +
1.523 + iPaddingBlock.Zero();
1.524 + iInputStore.Zero();
1.525 + }
1.526 +
1.527 +