sl@0: /* sl@0: * Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: * All rights reserved. sl@0: * This component and the accompanying materials are made available sl@0: * under the terms of the License "Eclipse Public License v1.0" sl@0: * which accompanies this distribution, and is available sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: * sl@0: * Initial Contributors: sl@0: * Nokia Corporation - initial contribution. sl@0: * sl@0: * Contributors: sl@0: * sl@0: * Description: sl@0: * sl@0: */ sl@0: sl@0: sl@0: #ifndef __SYMMETRICCIPHERIMPL_H__ sl@0: #define __SYMMETRICCIPHERIMPL_H__ sl@0: sl@0: /** sl@0: @file sl@0: @internalComponent sl@0: @released sl@0: */ sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include "symmetriccipherplugin.h" sl@0: sl@0: /** The maximum block size supported (in bytes) */ sl@0: const TUint KMaxBlockSizeSupported = 32; sl@0: sl@0: /** sl@0: Abstract base class for symmetric cipher plug-ins. sl@0: */ sl@0: namespace SoftwareCrypto sl@0: { sl@0: using namespace CryptoSpi; sl@0: sl@0: NONSHARABLE_CLASS(CSymmetricCipherImpl) : public CBase, public MSymmetricCipher sl@0: { sl@0: public: sl@0: /** sl@0: Implemented by each cipher subclass to determine whether the sl@0: specified key length is valid for that cipher. sl@0: This is called by ConstructL and SetKeyL sl@0: @param aKeyLength The key length in bytes to verify. sl@0: */ sl@0: virtual TBool IsValidKeyLength(TInt aKeyBytes) const = 0; sl@0: sl@0: /** sl@0: Helper function implemented by concrete cipher sub-class that sl@0: allows GetCharacteristicsL to return the correct characteristics object. sl@0: @return The implemention uid sl@0: */ sl@0: virtual TUid ImplementationUid() const = 0; sl@0: sl@0: /** sl@0: Gets the strength of the current key, needed to check whether the cipher sl@0: may operate if strong cryptography is not enabled. sl@0: @return The strength of the current key sl@0: */ sl@0: virtual TInt GetKeyStrength() const; sl@0: sl@0: sl@0: // Override MPlugin virtual functions sl@0: void Close(); sl@0: TAny* GetExtension(TUid aExtensionId); sl@0: void GetCharacteristicsL(const TCharacteristics*& aPluginCharacteristics); sl@0: // End of MPlugin sl@0: sl@0: // Override MSymmetricCipherBase virtual functions sl@0: TInt KeySize() const; sl@0: sl@0: /// Destructor sl@0: ~CSymmetricCipherImpl(); sl@0: sl@0: protected: sl@0: sl@0: //Constructor sl@0: CSymmetricCipherImpl(); sl@0: sl@0: /** sl@0: Second phase of construction. Always call ConstructL in the super-class sl@0: if your override this method. sl@0: sl@0: @param aKey The key to initialise the cipher with. sl@0: */ sl@0: virtual void ConstructL(const CKey& aKey); sl@0: sl@0: /** sl@0: Extracts the raw symmetric key from a generic key object. The buffer sl@0: is placed on the cleanup stack. sl@0: sl@0: @param aKey The key object sl@0: @return A buffer containing the raw key value sl@0: */ sl@0: HBufC8* ExtractKeyDataLC(const CKey& aKey) const; sl@0: sl@0: /** sl@0: Zeros a buffer before deleting it to ensure that sl@0: the contents will not be visible to another process if the page sl@0: is re-used. sl@0: @param aBuffer The pointer (possibly null) to the buffer to delete. This sl@0: is set to null after deletion. sl@0: */ sl@0: void SecureDelete(HBufC8*& aBuffer); sl@0: sl@0: /** sl@0: Extracts the raw key from aKey and sets iKey and iKeyBytes sl@0: The key length is also checked to meet export restrictions and sl@0: to ensure that it is appropriate for the cipher. sl@0: @param aKey The key sl@0: */ sl@0: virtual void DoSetKeyL(const CKey& aKey); sl@0: sl@0: sl@0: protected: sl@0: /// the key, extracted from a CKey object sl@0: HBufC8* iKey; sl@0: sl@0: /// key size in bytes sl@0: TUint iKeyBytes; sl@0: sl@0: }; sl@0: sl@0: NONSHARABLE_CLASS(CSymmetricStreamCipherImpl) : public CSymmetricCipherImpl sl@0: { sl@0: public: sl@0: // Destructor sl@0: ~CSymmetricStreamCipherImpl(); sl@0: sl@0: // Override MSymmetricCipherBase virtual functions sl@0: TInt BlockSize() const; sl@0: void SetKeyL(const CKey& aKey); // override DoSetKeyL instead sl@0: void SetCryptoModeL(TUid aCryptoMode); sl@0: void SetOperationModeL(TUid aOperationMode); sl@0: void SetPaddingModeL(TUid aPaddingMode); sl@0: void SetIvL(const TDesC8& aIv); sl@0: TInt MaxOutputLength(TInt aInputLength) const; sl@0: TInt MaxFinalOutputLength(TInt aInputLength) const; sl@0: // End of MSymmetricCipherBase sl@0: sl@0: // Override MSymmetricCipher virtual functions sl@0: void ProcessL(const TDesC8& aInput, TDes8& aOutput); sl@0: void ProcessFinalL(const TDesC8& aInput, TDes8& aOutput); sl@0: // End of MSymmetricCipher sl@0: sl@0: protected: sl@0: // Constructor sl@0: CSymmetricStreamCipherImpl(); sl@0: sl@0: // Override CSymmetricCipherImpl virtual functions sl@0: virtual void ConstructL(const CKey& aKey); sl@0: sl@0: /** sl@0: Performs an encryption or decryption on supplied data. sl@0: @param aData On input, data to be transformed; sl@0: on return, transformed data. sl@0: */ sl@0: virtual void DoProcess(TDes8& aData) = 0; sl@0: }; sl@0: sl@0: NONSHARABLE_CLASS(CSymmetricBlockCipherImpl) : public CSymmetricCipherImpl sl@0: { sl@0: public: sl@0: sl@0: sl@0: /** sl@0: This function is invoked by SetKey and SetCryptoMode sl@0: allowing the cipher sub-class to rebuild it's key schedule. sl@0: N.B. It is assumed that the key schedule is NOT modified sl@0: by TransformEncrypt or TransformDecrypt sl@0: */ sl@0: virtual void SetKeySchedule() = 0; sl@0: sl@0: // Override MPlugin virtual functions sl@0: void Reset(); // Always call reset in super-class if you override this sl@0: // End of MPlugin virtual functions sl@0: sl@0: // Override MSymmetricCipherBase virtual functions sl@0: TInt BlockSize() const; sl@0: void SetKeyL(const CKey& aKey); // override DoSetKeyL instead sl@0: void SetCryptoModeL(TUid aCryptoMode); // override DoSetCryptoModeL instead sl@0: void SetOperationModeL(TUid aOperationMode); // override DoSetOperationMode instead sl@0: void SetPaddingModeL(TUid aPaddingMode); // override DoSetPaddingModeL instead sl@0: void SetIvL(const TDesC8& aIv); sl@0: sl@0: TInt MaxOutputLength(TInt aInputLength) const; sl@0: TInt MaxFinalOutputLength(TInt aInputLength) const; sl@0: // End of MSymmetricCipherBase sl@0: sl@0: // Override MSymmetricCipher virtual functions sl@0: void ProcessL(const TDesC8& aInput, TDes8& aOutput); sl@0: void ProcessFinalL(const TDesC8& aInput, TDes8& aOutput); sl@0: // End of MSymmetricCipher sl@0: sl@0: /// Destructor sl@0: ~CSymmetricBlockCipherImpl(); sl@0: protected: sl@0: /** sl@0: Constructor sl@0: @param aBlockBytes The block size in bytes sl@0: @param aOperationMode The mode of operation e.g. CBC sl@0: @param aCryptoMode Whether to encrypt or decrypt sl@0: */ sl@0: CSymmetricBlockCipherImpl( sl@0: TUint8 aBlockBytes, sl@0: TUid aOperationMode, sl@0: TUid aCryptoMode, sl@0: TUid aPaddingMode); sl@0: sl@0: // Override CSymmetricCipherImpl virtual functions sl@0: virtual void ConstructL(const CKey& aKey); sl@0: sl@0: /** sl@0: Validates and sets the crypto mode (iCryptoMode) sl@0: @param aCryptoMode The crypto mode sl@0: */ sl@0: virtual void DoSetCryptoModeL(TUid aCryptoMode); sl@0: sl@0: /** sl@0: Validates and sets the operation mode (iOperationMode) sl@0: @param aOperationMode The operation mode sl@0: */ sl@0: virtual void DoSetOperationModeL(TUid aOperationMode); sl@0: sl@0: /** sl@0: Validates and sets the padding mode (iPaddingMode & iPadding) sl@0: @param aPadding The desired padding mode sl@0: */ sl@0: virtual void DoSetPaddingModeL(TUid aPadding); sl@0: sl@0: void DoSetIvL(const TDesC8& aIv); sl@0: sl@0: inline void ModeEncryptStart(TUint8* aBuffer); sl@0: inline void ModeEncryptEnd(TUint8* aBuffer); sl@0: inline void ModeDecryptStart(TUint8* aBuffer); sl@0: inline void ModeDecryptEnd(TUint8* aBuffer); sl@0: sl@0: private: sl@0: sl@0: /** sl@0: Encrypts a number of blocks of data sl@0: sl@0: @param aBuffer The buffer containing exactly aNumBlocks of data to destructively encrypt sl@0: @param aNumBlocks The number of blocks of data to encrypt sl@0: */ sl@0: virtual void TransformEncrypt(TUint8* aBuffer, TUint aNumBlocks) = 0; sl@0: sl@0: /** sl@0: Decrypts a number of blocks of data sl@0: sl@0: @param aBuffer The buffer containing exactly aNumBlocks of data to destructively decrypt sl@0: @param aNumBlocks The number of blocks of data to decrypt sl@0: */ sl@0: virtual void TransformDecrypt(TUint8* aBuffer, TUint aNumBlocks) = 0; sl@0: sl@0: /// Pad the last block and encrypt sl@0: void DoProcessFinalEncryptL(const TDesC8& aInput, TDes8& aOutput); sl@0: sl@0: /// Decrypt and unpad the last block sl@0: void DoProcessFinalDecryptL(const TDesC8& aInput, TDes8& aOutput); sl@0: sl@0: inline void Transform(TUint8* aBuffer, TUint aNumBlocks); sl@0: sl@0: void ProcessCtrL(const TDesC8& aInput, TDes8& aOutput); sl@0: sl@0: protected: sl@0: sl@0: /// block size in bytes, current largest block size is 16 bytes (AES) sl@0: TUint8 iBlockBytes; sl@0: /// encryption or decryption sl@0: TUid iCryptoMode; sl@0: /// The block cipher mode e.g. ECB, CBC sl@0: TUid iOperationMode; sl@0: /// the current padding scheme sl@0: TUid iPaddingMode; sl@0: sl@0: /// the initialisation vector sl@0: RBuf8 iIv; sl@0: sl@0: /// current padding scheme implementation sl@0: CPadding* iPadding; sl@0: /// buffer to store blocks sl@0: RBuf8 iInputStore; sl@0: /// buffer to store input / output of padding sl@0: RBuf8 iPaddingBlock; sl@0: sl@0: /// The current block of cipher text - for CBC sl@0: TUint32* iCurrentCipherText; sl@0: /// A pointer to the current block of cipher text sl@0: TUint8* iCurrentCipherTextPtr; sl@0: sl@0: /** Used in both CBC and CTR mode. In CBC mode it stores the result of the last transform. In CTR mode sl@0: it stores the counter.*/ sl@0: TUint32* iRegister; sl@0: /** A pointer to iRegister.*/ sl@0: TUint8* iRegisterPtr; sl@0: sl@0: /** Used in CTR mode to buffer plaintext during encryption.*/ sl@0: HBufC8* iBufferedPlaintext; sl@0: /** Pointer to manipulate iBufferedPlaintext.*/ sl@0: TPtr8 iBufferedPlaintextPtr; sl@0: sl@0: /** CTR mode behaves like a stream cipher allowing arbitrary sized inputs to the encryption/decryption functions. sl@0: When handling an input whose length is not a multiple of the blocksize iCtrUnusedKeystream is used to buffer sl@0: the unused portions of keystream for use in the next call. Cleared in Reset().*/ sl@0: HBufC8* iCtrUnusedKeystream; sl@0: /** Pointer to manipulate iCtrUnusedKeystream.*/ sl@0: TPtr8 iCtrUnusedKeystreamPtr; sl@0: }; sl@0: sl@0: sl@0: inline void CSymmetricBlockCipherImpl::Transform(TUint8* aBuffer, TUint aNumBlocks) sl@0: { sl@0: if (iCryptoMode.iUid == KCryptoModeEncrypt) //if in CTR mode always in crypto mode encrypt sl@0: { sl@0: TransformEncrypt(aBuffer, aNumBlocks); sl@0: } sl@0: else if (iCryptoMode.iUid == KCryptoModeDecrypt) sl@0: { sl@0: TransformDecrypt(aBuffer, aNumBlocks); sl@0: } sl@0: else sl@0: { sl@0: ASSERT(EFalse); sl@0: } sl@0: } sl@0: sl@0: inline void CSymmetricBlockCipherImpl::ModeEncryptStart(TUint8* aBuffer) sl@0: { sl@0: if (iOperationMode.iUid == KOperationModeCBC) sl@0: { sl@0: for (TInt i = 0; i < iBlockBytes; ++i) sl@0: { sl@0: aBuffer[i] ^= iRegisterPtr[i]; sl@0: } sl@0: } sl@0: else if (iOperationMode.iUid == KOperationModeCTR) sl@0: { sl@0: iBufferedPlaintextPtr.Copy(aBuffer, iBlockBytes); sl@0: Mem::Copy(aBuffer, iRegister, iBlockBytes); sl@0: } sl@0: } sl@0: sl@0: inline void CSymmetricBlockCipherImpl::ModeEncryptEnd(TUint8* aBuffer) sl@0: { sl@0: if (iOperationMode.iUid == KOperationModeCBC) sl@0: { sl@0: for (TInt i = 0; i < iBlockBytes; ++i) sl@0: { sl@0: iRegisterPtr[i] = aBuffer[i]; sl@0: } sl@0: } sl@0: else if (iOperationMode.iUid == KOperationModeCTR) sl@0: { sl@0: //XOR the plaintext with the keystream and increment counter sl@0: for (TInt i = 0; i < iBlockBytes; ++i) sl@0: { sl@0: aBuffer[i] ^= iBufferedPlaintextPtr[i]; sl@0: } sl@0: for (TInt i = iBlockBytes - 1; i >= 0; --i) sl@0: { sl@0: if (++(iRegisterPtr[i]) != 0) break; sl@0: } sl@0: } sl@0: } sl@0: sl@0: inline void CSymmetricBlockCipherImpl::ModeDecryptStart(TUint8* aBuffer) sl@0: { sl@0: __ASSERT_DEBUG((iOperationMode.iUid != KOperationModeCTR), User::Panic(_L("CSymmetricBlockCipherImpl.h"), 1)); sl@0: if (iOperationMode.iUid == KOperationModeCBC) sl@0: { sl@0: for (TInt i = 0; i < iBlockBytes; ++i) sl@0: { sl@0: iCurrentCipherTextPtr[i] = aBuffer[i]; sl@0: } sl@0: } sl@0: } sl@0: sl@0: inline void CSymmetricBlockCipherImpl::ModeDecryptEnd(TUint8* aBuffer) sl@0: { sl@0: __ASSERT_DEBUG((iOperationMode.iUid != KOperationModeCTR), User::Panic(_L("CSymmetricBlockCipherImpl.h"), 2)); sl@0: if (iOperationMode.iUid == KOperationModeCBC) sl@0: { sl@0: // xor the output with the previous cipher text sl@0: for (TInt i = 0; i < iBlockBytes; ++i) sl@0: { sl@0: aBuffer[i] ^= iRegisterPtr[i]; sl@0: iRegisterPtr[i] = iCurrentCipherTextPtr[i]; sl@0: } sl@0: } sl@0: } sl@0: } sl@0: sl@0: #endif // __SYMMETRICCIPHERIMPL_H__