os/security/cryptoplugins/cryptospiplugins/test/h4drv/crypto_h4_plugin/h4cipherimpl.cpp
Update contrib.
2 * Copyright (c) 2007-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.
24 #include "h4cipherimpl.h"
27 #include <cryptostrength.h>
28 #include <cryptospi/cryptospidef.h>
30 #include <cryptospi/plugincharacteristics.h>
31 #include "pluginconfig.h"
32 #include <cryptopanic.h>
33 #include <securityerr.h>
34 #include "keyhandle.h"
36 using namespace HwCrypto;
38 #define BytesToBits(byteCount) (byteCount*8)
41 // Implementation of Symmetric Cipher class
43 CH4CipherImpl::CH4CipherImpl(TUint8 aBlockBytes,
47 : iBlockBytes(aBlockBytes),
48 iCryptoMode(aCryptoMode),
49 iOperationMode(aOperationMode),
50 iPaddingMode(aPaddingMode)
54 void CH4CipherImpl::ConstructL(const CKey& aKey)
57 SetOperationModeL(iOperationMode);
58 SetCryptoModeL(iCryptoMode);
59 SetPaddingModeL(iPaddingMode);
61 iPartialBlock.ReAllocL(iBlockBytes);
62 iPaddingBlock.ReAllocL(iBlockBytes);
64 iIv.ReAllocL(iBlockBytes);
65 // iIv.SetLength(iBlockBytes);
66 // TRandom::RandomL(iIv);
69 CExtendedCharacteristics* CH4CipherImpl::CreateExtendedCharacteristicsL()
71 // All Symbian software plug-ins have unlimited concurrency, cannot be reserved
72 // for exclusive use and are not CERTIFIED to be standards compliant.
74 // return CExtendedCharacteristics::NewL(KMaxTInt, iStandardsConformance, EFalse);
78 CH4CipherImpl::~CH4CipherImpl()
82 iPartialBlock.Close();
83 iPaddingBlock.Close();
86 iStandardsConformance.Close();
89 void CH4CipherImpl::Close()
94 TAny* CH4CipherImpl::GetExtension(TUid /*aExtensionId*/)
99 void CH4CipherImpl::GetCharacteristicsL(const TAny*& aPluginCharacteristics)
101 TInt numCiphers = sizeof(KSymmetricCipherCharacteristics)/sizeof(TSymmetricCipherCharacteristics*);
102 TInt32 implUid = ImplementationUid().iUid;
103 for (TInt i = 0; i < numCiphers; ++i)
105 if (KSymmetricCipherCharacteristics[i]->cmn.iImplementationUID == implUid)
107 aPluginCharacteristics = KSymmetricCipherCharacteristics[i];
114 void CH4CipherImpl::Reset()
116 iPartialBlock.Zero();
117 iPaddingBlock.Zero();
119 // Reconfigure h/w based on iCryptoMode/iOperationMode/iKey/iIv
120 TRAP_IGNORE(DoSetupL());
121 iNeedToSetupHw = EFalse;
125 TInt CH4CipherImpl::GetKeyStrength() const
127 return BytesToBits(iKey->Length());
130 HBufC8* CH4CipherImpl::ExtractKeyDataLC(const CKey& aKey) const
132 const TDesC8& keyContent = aKey.GetTDesC8L(KSymmetricKeyParameterUid);
133 return keyContent.AllocLC();
136 TInt CH4CipherImpl::KeySize() const
138 // return key size in BITS
139 return BytesToBits(iKeyBytes);
142 void CH4CipherImpl::SetKeyL(const CKey& aKey)
144 HBufC8* key = ExtractKeyDataLC(aKey);
145 TInt keyLength(key->Length());
147 const TKeyProperty &keyProps = aKey.KeyProperty();
149 if(keyProps.iKeyType != KSymmetricKeyUid)
151 User::Leave(KErrArgument);
154 if(keyProps.iKeyAttribute == KNonEmbeddedKeyUid)
156 // Not an embedded key, so key is the actual key data and we
157 // can therefore check its strength...
158 TCrypto::IsSymmetricWeakEnoughL(BytesToBits(keyLength));
159 if (! IsValidKeyLength(keyLength))
161 User::Leave(KErrNotSupported);
166 CleanupStack::Pop(key);
168 iKeyBytes = keyLength;
170 // H/W needs reconfiguring
171 iNeedToSetupHw = ETrue;
174 TInt CH4CipherImpl::BlockSize() const
176 // return block size in BITS
177 return BytesToBits(iBlockBytes);
180 void CH4CipherImpl::SetCryptoModeL(TUid aCryptoMode)
182 switch (aCryptoMode.iUid)
184 case KCryptoModeEncrypt:
185 case KCryptoModeDecrypt:
188 User::Leave(KErrNotSupported);
190 iCryptoMode = aCryptoMode;
191 // H/W needs reconfiguring
192 iNeedToSetupHw = ETrue;
195 void CH4CipherImpl::SetOperationModeL(TUid aOperationMode)
197 switch (aOperationMode.iUid)
199 case KOperationModeNone:
200 case KOperationModeECB:
201 case KOperationModeCBC:
204 User::Leave(KErrNotSupported);
206 iOperationMode = aOperationMode;
207 // H/W needs reconfiguring
208 iNeedToSetupHw = ETrue;
211 void CH4CipherImpl::SetPaddingModeL(TUid aPaddingMode)
213 if(!iPadding || (aPaddingMode != iPaddingMode))
215 CPadding* padding(0);
216 switch (aPaddingMode.iUid)
218 case KPaddingModeNone:
219 padding = CPaddingNone::NewL(iBlockBytes);
221 case KPaddingModeSSLv3:
222 padding = CPaddingSSLv3::NewL(iBlockBytes);
224 case KPaddingModePKCS7:
225 padding = CPaddingPKCS7::NewL(iBlockBytes);
228 User::Leave(KErrNotSupported);
232 iPaddingMode = aPaddingMode;
235 // H/W needs reconfiguring
236 iNeedToSetupHw = ETrue;
239 void CH4CipherImpl::SetIvL(const TDesC8& aIv)
241 if (iOperationMode.iUid != KOperationModeCBC)
243 User::Leave(KErrNotSupported);
246 if (aIv.Length() != iBlockBytes)
248 User::Leave(KErrArgument);
252 // H/W needs reconfiguring
253 iNeedToSetupHw = ETrue;
264 TInt CH4CipherImpl::MaxOutputLength(TInt aInputLength) const
266 // The maximum output length required for Process is equal to the
267 // size of the number of whole input blocks available.
269 // The block bytes is a power of two so we can use this to avoid
270 // doing a real mod operation
271 TUint partialBlockLength(iPartialBlock.Length());
272 return (partialBlockLength + aInputLength) & ~TUint32(iBlockBytes - 1);
275 TInt CH4CipherImpl::MaxFinalOutputLength(TInt aInputLength) const
277 if (iCryptoMode.iUid == KCryptoModeEncrypt)
279 return iPadding->MaxPaddedLength(iPartialBlock.Length() + aInputLength);
283 return iPadding->MaxUnPaddedLength(aInputLength + iPartialBlock.Length());
289 void CH4CipherImpl::ProcessL(const TDesC8& aInput, TDes8& aOutput)
293 // Reconfigure h/w based on iCryptoMode/iOperationMode/iKey/iIv
295 iNeedToSetupHw = EFalse;
298 TInt inputLength(aInput.Length());
299 if (MaxOutputLength(inputLength) > aOutput.MaxLength())
301 User::Leave(KErrOverflow);
304 TInt partialBlockLength(iPartialBlock.Length()); // partial data written to h/w last time
305 TUint32 totalInput = partialBlockLength + inputLength;
307 // Pass new data to h/w driver
308 DoWriteL(aInput.Ptr(), inputLength);
310 if(totalInput < iBlockBytes)
312 // Keep a copy of the partial block which is inside the h/w
313 // driver in case we need to calculate pad for it later...
314 if(inputLength) iPartialBlock.Append(aInput);
315 // Not enough written yet for more data to be available yet.
320 // We have completed the previous partial block so we no
321 // longer need to keep a copy of it
322 iPartialBlock.Zero();
323 // Work out length of partial block at end of current data
324 TUint32 trailing = TUint32(partialBlockLength + inputLength) & TUint32(iBlockBytes - 1);
325 // Keep a copy of the partial block data
326 if(trailing) iPartialBlock.Append(aInput.Right(trailing));
330 // Work out how much data is available for reading.
332 // The h/w processes data a block at a time, and we only ever read
333 // a multiple of the block size so the available data will always
334 // be a multiple of the blocksize.
336 TUint32 availableData = totalInput & ~TUint32(iBlockBytes - 1);
339 // Read available data
340 DoReadL(aOutput, availableData);
344 void CH4CipherImpl::ProcessFinalL(const TDesC8& aInput, TDes8& aOutput)
348 // Reconfigure h/w based on iCryptoMode/iOperationMode/iKey/iIv
350 iNeedToSetupHw = EFalse;
353 if(MaxFinalOutputLength(aInput.Length()) > aOutput.MaxLength() - aOutput.Length())
355 User::Leave(KErrOverflow);
359 if(iCryptoMode.iUid == KCryptoModeEncrypt)
361 // process everything up to the last (possibly empty block)
362 ProcessL(aInput, aOutput);
365 iPaddingBlock.Zero();
366 iPadding->PadL(iPartialBlock, iPaddingBlock);
368 TUint32 padLength = iPaddingBlock.Length();
369 // Make sure pad worked
370 if(padLength & TUint32(iBlockBytes-1))
372 User::Leave(KErrInvalidPadding);
379 // We have already written iPartialBlock data to the h/w
380 // so skip those bytes which are in the pad.
381 TUint32 partialLength = iPartialBlock.Length();
384 // Make sure the pad algorithm did not change the bytes at
385 // the start of the block....
386 if(iPaddingBlock.Left(partialLength) != iPartialBlock)
388 User::Leave(KErrInvalidPadding);
391 // Pass new data to h/w driver
392 DoWriteL(iPaddingBlock.Ptr() + partialLength, padLength - partialLength);
394 // Have now written an exact multiple of blocks to h/w so clear partial
395 iPartialBlock.Zero();
398 DoReadL(aOutput, padLength);
405 // Input length (including inputstore) must be a multiple of the
406 // block size in length
407 if ((aInput.Length() + iPartialBlock.Length()) & (iBlockBytes - 1))
409 User::Leave(KErrArgument);
412 // process everything up to the last (possibly empty block)
413 ProcessL(aInput, aOutput);
414 ASSERT(iPartialBlock.Length()==0); // all the blocks should have been decrypted
416 // Retrieve last decrypted block.
417 iPaddingBlock = aOutput.Right(iBlockBytes);
418 aOutput.SetLength(aOutput.Length() - iBlockBytes);
420 // Unpad the last block and (re)append to output
421 iPadding->UnPadL(iPaddingBlock, aOutput);
423 iPaddingBlock.Zero();
424 iPartialBlock.Zero();