First public contribution.
2 * Copyright (c) 2007-2010 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.
19 #include "symmetriccipherimpl.h"
22 #include <cryptostrength.h>
23 #include <cryptospi/cryptospidef.h>
24 #include <cryptospi/keys.h>
25 #include <cryptospi/plugincharacteristics.h>
26 #include "pluginconfig.h"
27 #include <cryptopanic.h>
28 #include <securityerr.h>
29 #include "../../../source/common/inlines.h"
31 using namespace SoftwareCrypto;
34 // Implementation of Symmetric Cipher class
36 CSymmetricCipherImpl::CSymmetricCipherImpl()
40 void CSymmetricCipherImpl::ConstructL(const CKey& aKey)
45 void CSymmetricCipherImpl::SecureDelete(HBufC8*& aBuffer)
49 aBuffer->Des().FillZ();
55 CSymmetricCipherImpl::~CSymmetricCipherImpl()
60 void CSymmetricCipherImpl::Close()
65 TAny* CSymmetricCipherImpl::GetExtension(TUid /*aExtensionId*/)
70 void CSymmetricCipherImpl::GetCharacteristicsL(const TAny*& aPluginCharacteristics)
72 TInt numCiphers = sizeof(KSymmetricCipherCharacteristics)/sizeof(TSymmetricCipherCharacteristics*);
73 TInt32 implUid = ImplementationUid().iUid;
74 for (TInt i = 0; i < numCiphers; ++i)
76 if (KSymmetricCipherCharacteristics[i]->cmn.iImplementationUID == implUid)
78 aPluginCharacteristics = KSymmetricCipherCharacteristics[i];
84 TInt CSymmetricCipherImpl::GetKeyStrength() const
86 return BytesToBits(iKey->Length());
89 HBufC8* CSymmetricCipherImpl::ExtractKeyDataLC(const CKey& aKey) const
91 const TDesC8& keyContent = aKey.GetTDesC8L(KSymmetricKeyParameterUid);
92 return keyContent.AllocLC();
95 TInt CSymmetricCipherImpl::KeySize() const
97 // return key size in BITS
98 return BytesToBits(iKeyBytes);
101 void CSymmetricCipherImpl::DoSetKeyL(const CKey& aKey)
103 HBufC8* key = ExtractKeyDataLC(aKey);
104 TInt keyLength(key->Length());
106 TCrypto::IsSymmetricWeakEnoughL(BytesToBits(keyLength));
107 if (! IsValidKeyLength(keyLength))
109 CleanupStack::PopAndDestroy(key);
110 User::Leave(KErrNotSupported);
114 CleanupStack::Pop(key);
116 iKeyBytes = keyLength;
120 // Implementation of Symmetric Stream Cipher
122 CSymmetricStreamCipherImpl::CSymmetricStreamCipherImpl()
126 CSymmetricStreamCipherImpl::~CSymmetricStreamCipherImpl()
130 void CSymmetricStreamCipherImpl::SetKeyL(const CKey& aKey)
133 TCrypto::IsSymmetricWeakEnoughL(GetKeyStrength());
137 void CSymmetricStreamCipherImpl::ConstructL(const CKey& aKey)
139 CSymmetricCipherImpl::ConstructL(aKey);
142 TInt CSymmetricStreamCipherImpl::BlockSize() const
144 // return block size in BITS
148 void CSymmetricStreamCipherImpl::SetOperationModeL(TUid /*aOperationMode*/)
150 User::Leave(KErrNotSupported);
153 void CSymmetricStreamCipherImpl::SetCryptoModeL(TUid /*aCryptoMode*/)
155 // Call the reset method.
159 void CSymmetricStreamCipherImpl::SetPaddingModeL(TUid /*aPaddingMode*/)
161 User::Leave(KErrNotSupported);
164 void CSymmetricStreamCipherImpl::SetIvL(const TDesC8& /*aIv*/)
166 User::Leave(KErrNotSupported);
169 TInt CSymmetricStreamCipherImpl::MaxOutputLength(TInt aInputLength) const
174 TInt CSymmetricStreamCipherImpl::MaxFinalOutputLength(TInt aInputLength) const
179 void CSymmetricStreamCipherImpl::ProcessL(const TDesC8& aInput, TDes8& aOutput)
181 TInt outputIndex = aOutput.Size();
183 // aOutput may already have outputIndex bytes of data in it
184 // check there will still be enough space to process the result
185 __ASSERT_DEBUG(aOutput.MaxLength() - outputIndex >= MaxOutputLength(aInput.Length()), User::Panic(KCryptoPanic, ECryptoPanicOutputDescriptorOverflow));
187 aOutput.Append(aInput);
189 TPtr8 transformBuf((TUint8*)(aOutput.Ptr()) + outputIndex, aInput.Size(),
191 DoProcess(transformBuf);
194 void CSymmetricStreamCipherImpl::ProcessFinalL(const TDesC8& aInput, TDes8& aOutput)
196 ProcessL(aInput, aOutput);
200 // Implementation of Symmetric Block Cipher
202 CSymmetricBlockCipherImpl::CSymmetricBlockCipherImpl(
207 iBlockBytes(aBlockBytes),
208 iCryptoMode(aCryptoMode),
209 iOperationMode(aOperationMode),
210 iPaddingMode(aPaddingMode)
214 CSymmetricBlockCipherImpl::~CSymmetricBlockCipherImpl()
218 delete iCurrentCipherText;
221 iPaddingBlock.Close();
225 void CSymmetricBlockCipherImpl::ConstructL(const CKey& aKey)
227 CSymmetricCipherImpl::ConstructL(aKey);
228 DoSetOperationModeL(iOperationMode);
229 DoSetCryptoModeL(iCryptoMode);
230 DoSetPaddingModeL(iPaddingMode);
232 iInputStore.ReAllocL(iBlockBytes);
233 iPaddingBlock.ReAllocL(iBlockBytes);
235 iCbcRegister = new(ELeave) TUint32[iBlockBytes/4];
236 iCbcRegisterPtr = reinterpret_cast<TUint8*>(iCbcRegister);
238 iCurrentCipherText = new(ELeave) TUint32[iBlockBytes/4];
239 iCurrentCipherTextPtr = reinterpret_cast<TUint8*>(iCurrentCipherText);
242 void CSymmetricBlockCipherImpl::Reset()
245 iPaddingBlock.Zero();
247 if (iOperationMode.iUid == KOperationModeCBC)
249 // only copy the IV if it is already set
250 if (iIv.MaxLength() > 0)
252 Mem::Copy(iCbcRegisterPtr, &iIv[0], iBlockBytes);
257 void CSymmetricBlockCipherImpl::SetKeyL(const CKey& aKey)
260 TCrypto::IsSymmetricWeakEnoughL(GetKeyStrength());
265 void CSymmetricBlockCipherImpl::SetOperationModeL(TUid aOperationMode)
267 DoSetOperationModeL(aOperationMode);
271 void CSymmetricBlockCipherImpl::SetCryptoModeL(TUid aCryptoMode)
273 DoSetCryptoModeL(aCryptoMode);
278 void CSymmetricBlockCipherImpl::SetPaddingModeL(TUid aPaddingMode)
280 DoSetPaddingModeL(aPaddingMode);
284 void CSymmetricBlockCipherImpl::SetIvL(const TDesC8& aIv)
286 if (iOperationMode.iUid != KOperationModeCBC)
288 User::Leave(KErrNotSupported);
294 void CSymmetricBlockCipherImpl::DoSetOperationModeL(TUid aOperationMode)
296 switch (aOperationMode.iUid)
298 case KOperationModeNone:
299 case KOperationModeECB:
300 case KOperationModeCBC:
303 User::Leave(KErrNotSupported);
305 iOperationMode = aOperationMode;
308 void CSymmetricBlockCipherImpl::DoSetCryptoModeL(TUid aCryptoMode)
310 switch (aCryptoMode.iUid)
312 case KCryptoModeEncrypt:
313 case KCryptoModeDecrypt:
316 User::Leave(KErrNotSupported);
318 iCryptoMode = aCryptoMode;
321 void CSymmetricBlockCipherImpl::DoSetPaddingModeL(TUid aPaddingMode)
323 CPadding* padding(0);
324 switch (aPaddingMode.iUid)
326 case KPaddingModeNone:
327 padding = CPaddingNone::NewL(iBlockBytes);
329 case KPaddingModeSSLv3:
330 padding = CPaddingSSLv3::NewL(iBlockBytes);
332 case KPaddingModePKCS7:
333 padding = CPaddingPKCS7::NewL(iBlockBytes);
336 User::Leave(KErrNotSupported);
340 iPaddingMode = aPaddingMode;
343 void CSymmetricBlockCipherImpl::DoSetIvL(const TDesC8& aIv)
345 iIv.ReAllocL(iBlockBytes);
346 iIv.SetLength(iBlockBytes);
349 if (aIv.Length() != iBlockBytes)
351 User::Leave(KErrArgument);
356 TInt CSymmetricBlockCipherImpl::BlockSize() const
358 // return block size in BITS
359 return BytesToBits(iBlockBytes);
362 TInt CSymmetricBlockCipherImpl::MaxOutputLength(TInt aInputLength) const
364 // The maximum output length required for Process is equal to the
365 // size of the number of whole input blocks available.
367 // The block bytes is a power of two so we can use this to avoid
368 // doing a real mod operation
369 TUint inputStoreLength(iInputStore.Length());
370 TInt rem = (aInputLength + inputStoreLength) & (iBlockBytes - 1);
371 return (aInputLength + inputStoreLength - rem);
374 TInt CSymmetricBlockCipherImpl::MaxFinalOutputLength(TInt aInputLength) const
376 if (iCryptoMode.iUid == KCryptoModeEncrypt)
378 return iPadding->MaxPaddedLength(iInputStore.Length() + aInputLength);
382 return iPadding->MaxUnPaddedLength(aInputLength + iInputStore.Size());
386 void CSymmetricBlockCipherImpl::ProcessL(const TDesC8& aInput, TDes8& aOutput)
388 // if we're running in CBC mode then we must have an IV set before we can
389 // do any processing ie call SetIvL() before this method
390 if (iOperationMode.iUid == KOperationModeCBC)
392 if (iIv.MaxLength() == 0)
394 User::Leave(KErrNotSupported);
398 TInt inputLength(aInput.Length());
399 TInt inputStoreLength(iInputStore.Length());
401 if (MaxOutputLength(inputLength) > aOutput.MaxLength())
403 User::Leave(KErrOverflow);
406 TUint8 blockSizeLog = CryptoLog2(iBlockBytes);
407 TInt wholeBlocks = (inputLength + inputStoreLength) >> blockSizeLog;
408 TInt wholeBlocksSize = wholeBlocks << blockSizeLog;
412 TInt outputLength(aOutput.Length());
414 if (inputStoreLength > 0)
416 aOutput.Append(iInputStore);
419 aOutput.Append(aInput.Left(wholeBlocksSize - inputStoreLength));
420 Transform(const_cast<TUint8*>(aOutput.Ptr()) + outputLength, wholeBlocks);
423 TInt remainingBytes = inputLength + inputStoreLength - wholeBlocksSize;
424 if (remainingBytes > 0)
426 iInputStore.Append(aInput.Right(remainingBytes));
430 void CSymmetricBlockCipherImpl::ProcessFinalL(const TDesC8& aInput, TDes8& aOutput)
432 // if we're running in CBC mode then we must have an IV set before we can
433 // do any processing ie call SetIvL() before this method
434 if (iOperationMode.iUid == KOperationModeCBC)
436 if (iIv.MaxLength() == 0)
438 User::Leave(KErrNotSupported);
442 if (iCryptoMode.iUid == KCryptoModeEncrypt)
444 return DoProcessFinalEncryptL(aInput, aOutput);
448 return DoProcessFinalDecryptL(aInput, aOutput);
452 void CSymmetricBlockCipherImpl::DoProcessFinalEncryptL(const TDesC8& aInput, TDes8& aOutput)
454 if (MaxFinalOutputLength(aInput.Length()) > aOutput.MaxLength() - aOutput.Length())
456 User::Leave(KErrOverflow);
459 // process everything up to the last (possibly empty block)
460 TInt outputStartIndex = aOutput.Length();
461 ProcessL(aInput, aOutput);
464 iPadding->PadL(iInputStore, iPaddingBlock);
466 // if padding required
467 if (iPaddingBlock.Length() > 0)
471 // make sure the output is a multiple of the block size
472 User::LeaveIfError(((aOutput.Length() - outputStartIndex + iPaddingBlock.Length()) % iBlockBytes) == 0 ? KErrNone : KErrInvalidPadding);
474 outputStartIndex = aOutput.Length();
475 aOutput.Append(iPaddingBlock);
476 iPaddingBlock.Zero();
477 TransformEncrypt(const_cast<TUint8*>(aOutput.Ptr()) + outputStartIndex, 1);
481 void CSymmetricBlockCipherImpl::DoProcessFinalDecryptL(const TDesC8& aInput, TDes8& aOutput)
483 if (MaxFinalOutputLength(aInput.Length()) > aOutput.MaxLength() - aOutput.Length())
485 User::Leave(KErrOverflow);
488 // Input length (including inputstore) must be a multiple of the
489 // block size in length
490 if ((aInput.Length() + iInputStore.Length()) & (iBlockBytes - 1))
492 User::Leave(KErrArgument);
495 TInt bytesProcessed(0);
496 if(aInput.Length() > iBlockBytes)
498 // the last block lies entirely within aInput so decrypt everything up
500 bytesProcessed = aInput.Length() - iBlockBytes;
501 ProcessL(aInput.Left(bytesProcessed), aOutput);
502 ASSERT(iInputStore.Length()==0); // all the blocks should have been decrypted
506 // if the input is less than one block in length then this + input
507 // store should combine to give exactly one block of data
508 ASSERT((iInputStore.Length() + aInput.Length()) == iBlockBytes);
511 // now contains the final ciphertext block
512 iInputStore.Append(aInput.Right(aInput.Length() - bytesProcessed));
514 // Decrypt the last _padding_ blocksize into a new buffer
515 TransformDecrypt(const_cast<TUint8*>(iInputStore.Ptr()), 1);
517 // Unpad the last block and append to output
518 iPadding->UnPadL(iInputStore, aOutput);
520 iPaddingBlock.Zero();