// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// sa_crypt.cpp - IPv6/IPv4 IPSEC interface to crypto libraries
// IPsec interface to cryptographic libraries -- the implementation.
//
/**
@file sa_crypt.cpp
*/
#include "ext_hdr.h"
#include <networking/pfkeyv2.h>
#include "sa_spec.h"
#include "sa_crypt.h"
#include <networking/ipsecerr.h>
#include "ipseccrypto.h"
#include "keys.h"
#include <cryptospi/cryptospidef.h>
#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
#include <cryptospi/cryptomacapi.h>
#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
class TLibraryPtr
/**
* Description of installed cryptographic library.
*/
{
public:
TLibraryPtr() : iLibrary(NULL), iName(KNullDesC), iAlgs(NULL), iNum(0) {}
TLibraryPtr(CProtocolCrypto* aLibrary, const TDesC &aName, TAlgorithmDesc *algs, TUint aNum)
: iLibrary(aLibrary), iName(aName), iAlgs(algs), iNum(aNum) {}
CProtocolCrypto* iLibrary; //< Library (protocol) instance
TProtocolName iName; //< Symbolic name of the library
TAlgorithmDesc *iAlgs; //< Supported Algorithms descriptions
TUint iNum; //< Number of Algorithms
};
class CLibraryList : public CArrayFixFlat<TLibraryPtr>
/**
* List of installed libraries.
* Implemented as an array of TLibraryPtr, each of which
* describes one cryptographi library.
*/
{
public:
CLibraryList() : CArrayFixFlat<TLibraryPtr>(2) {}
~CLibraryList();
void AddL(CProtocolCrypto* aLibrary);
TUint Lookup(const TAlgorithmMap &aMap, TLibraryPtr **aLib);
};
void CLibraryList::AddL(CProtocolCrypto* aLibrary)
/**
* Add a cryptographic library to the list.
*
* Find out the list of algoritms supported by this library (AlgorithmList()), and
* if there are some, then add this library to the list of available libaries.
*
* @param aLibrary The crypto protocol.
* @leave error if library cannot be added.
*/
{
TAlgorithmDesc *algs = NULL;
TServerProtocolDesc desc;
aLibrary->Identify(&desc);
TUint num = aLibrary->AlgorithmList(algs);
//coverity[leave_without_push]
LOG(Log::Printf(_L("Registering crypto library: %S with %d algorithms"), &desc.iName, num));
if (algs)
{
CleanupStack::PushL(algs);
TLibraryPtr ptr(aLibrary, desc.iName, algs, num);
AppendL(ptr);
CleanupStack::Pop();
aLibrary->Open();
#ifdef _LOG
for (TInt i = 0; i < num; ++i)
{
const TAlgorithmDesc &a = algs[i];
if (a.iAlgType == EAlgorithmClass_Digest)
{
Log::Printf(_L("\tDigest %S block=%d"), &a.iName, a.iBlock);
}
else if (a.iAlgType == EAlgorithmClass_Cipher)
{
Log::Printf(_L("\tCipher %S block=%d, IV=%d key min=%d max=%d"),
&a.iName, a.iBlock, a.iVector, a.iMinBits, a.iMaxBits);
}
#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
else if (a.iAlgType == EAlgorithmClass_Mac)
{
Log::Printf(_L("\tMac %S block=%d, IV=%d key min=%d max=%d"),
&a.iName, a.iBlock, a.iVector, a.iMinBits, a.iMaxBits);
}
#endif // SYMBIAN_IPSEC_VOIP_SUPPORT
else
{
Log::Printf(_L("\tUnknown %S block=%d, IV=%d key min=%d max=%d"),
&a.iName, a.iBlock, a.iVector, a.iMinBits, a.iMaxBits);
}
}
#endif
}
}
CLibraryList::~CLibraryList()
/**
* Desctructor.
*
* Resease resources and Close() the crypto protocol modules.
*/
{
TInt i, n;
n = Count();
TLibraryPtr *lib;
for (i = 0; i < n; i++)
{
lib = &operator[](i);
delete[] lib->iAlgs;
if (lib->iLibrary)
lib->iLibrary->Close();
}
}
TUint CLibraryList::Lookup(const TAlgorithmMap &aMap, TLibraryPtr **aLib)
{
/**
* Lookup a library that implements the specified algorithm.
*
* If the map entry specifies a specific library, then only that
* library is examined for a match of algorithm name.
*
* The algorithm search is based on algorithm name (not on number).
*
* @param aMap The algorithm to find.
* @retval The library that implements it.
*/
TInt i, n;
n = Count();
TLibraryPtr *lib;
for (i = 0; i < n; i++)
{
lib = &operator[](i);
if (aMap.iLibrary.Length() == 0 ||
aMap.iLibrary == lib->iName)
{
//
// Search Algorithms within this library
//
for (TUint j = 0; j < lib->iNum; ++j)
{
if (lib->iAlgs[j].iName == aMap.iAlgorithm)
{
*aLib = lib;
return j;
}
}
}
}
// Requested algorithm is not available! This is configuration
// error, because Security Policy should not request algorithms
// that are not installed.
*aLib = NULL;
return 0;
}
CIpsecCryptoManager::CIpsecCryptoManager()
/**
* Constructor.
*
* Only called from CIpsecCryptoManager::NewL().
*/
{
}
CIpsecCryptoManager* CIpsecCryptoManager::NewL()
/**
* Return instance of crypto library manager.
*
* @return Cryptographic libarary manager.
*/
{
CIpsecCryptoManager *self = new (ELeave) CIpsecCryptoManager();
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
void CIpsecCryptoManager::ConstructL()
/**
* Construction.
*
* The construction creates initial library list (empty) and algorithm map
* (initialised with the default mapping). The default mapping uses the standard
* algorithm number symbols defined in the standard <networking/pfkeyv2.h> as follows:
* @code
* // Algorithm Bits Library Name
* SADB_AALG_MD5HMAC, 96, KNullDesC, KIpsecName_MD5
* SADB_AALG_SHA1HMAC, 96, KNullDesC, KIpsecName_SHA1
* SADB_EALG_DESCBC, 64, KNullDesC, KIpsecName_DES_CBC
* SADB_EALG_3DESCBC, 64, KNullDesC, KIpsecName_3DES_CBC
* SADB_EALG_NULL , 0, KNullDesC, KNullDesC
* SADB_X_AALG_AES_XCBC_MAC, 128, KNullDesC, KIpsecName_AES_XCBC_MAC
* @endcode
*
* @leave error if not enough memory.
*/
{
iLibraryList = new (ELeave) CLibraryList;
iAlgorithmList = new (ELeave) CAlgorithmList;
// Default mapping IPSEC algorithm numbers to engines:
// Should read these mappings from some ini file. For test purposes,
// the following mappings are now hard coded (library = "" => use
// whichever defines the algorithm first).
iAlgorithmList->AddL(EAlgorithmClass_Digest, SADB_AALG_MD5HMAC , 96, KNullDesC, KIpsecName_MD5);
iAlgorithmList->AddL(EAlgorithmClass_Digest, SADB_AALG_SHA1HMAC , 96, KNullDesC, KIpsecName_SHA1);
iAlgorithmList->AddL(EAlgorithmClass_Cipher, SADB_EALG_DESCBC , 64, KNullDesC, KIpsecName_DES_CBC);
iAlgorithmList->AddL(EAlgorithmClass_Cipher, SADB_EALG_3DESCBC , 64, KNullDesC, KIpsecName_3DES_CBC);
iAlgorithmList->AddL(EAlgorithmClass_Cipher, SADB_EALG_AESCBC , 64, KNullDesC, KIpsecName_AES_CBC);
#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
iAlgorithmList->AddL(EAlgorithmClass_Mac, SADB_AALG_AES_XCBC_MAC , 128,KNullDesC,KIpsecName_AES_XCBC_MAC );
#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
#ifdef SYMBIAN_CRYPTOSPI
iAlgorithmList->AddL(EAlgorithmClass_Cipher, SADB_EALG_AESCTR , 64, KNullDesC, KIpsecName_AES_CTR);
#endif //SYMBIAN_CRYPTOSPI
iAlgorithmList->AddL(EAlgorithmClass_Cipher, SADB_EALG_NULL , 0, KNullDesC, KNullDesC);
}
CIpsecCryptoManager::~CIpsecCryptoManager()
/**
* Descructor.
*
* Delete algorithm mapping and library list.
*/
{
delete iLibraryList;
delete iAlgorithmList;
}
void CIpsecCryptoManager::SetAlgorithms(CAlgorithmList*& aList)
/**
* Update the algorithm map with a new mapping table.
*
* Replace the current algorithm list with a the new list, take ownership
* of the structure and place NULL into aList.
*
* Algorithm mapping cannot be set to NULL using this method.
*
* @param aList The algorithm list (must be non-NULL)
*/
{
if (aList)
{
// Replace old with new
delete iAlgorithmList;
iAlgorithmList = aList;
aList = NULL;
}
#ifdef _LOG
if (iAlgorithmList)
{
const TInt N = iAlgorithmList->Count();
for (TInt i = 0; i < N; ++i)
{
const TAlgorithmMap &map = (*iAlgorithmList)[i];
_LIT(KEncr, "ENCR");
_LIT(KAuth, "AUTH");
Log::Printf(_L("\tAlgorithmMap %S %d (bits=%d) maps to %S.%S"),
map.iClass == EAlgorithmClass_Digest ? &KAuth() : &KEncr(),
map.iId, map.iBits,
&map.iLibrary, &map.iAlgorithm);
}
}
else
{
Log::Printf(_L("\tAlgorithmMap does not exist"));
}
#endif
}
void CIpsecCryptoManager::AddLibraryL(CProtocolCrypto *aLibrary)
/**
* Add a cryptographic library to the list.
*
* Add a cryptographic library packaged as a protocol into the
* list of installed libraries. The CLibraryList::AddL() does
* the major work.
*
* @param aLibrary The crypto protocol.
*/
{
iLibraryList->AddL(aLibrary);
}
CArrayFixFlat<struct sadb_alg> *CIpsecCryptoManager::SupportedAlgorithms
(TInt &aNumAuth, TInt &aNumEncrypt)
/**
* Ask the supported algorithms of a library.
*
* This function has a very specialized use: return supported
* algorithms, when a PFKEY reply to the REGISTER message is generated
* (CProtocolKey::ExecRegister). The format of the return value is tailored
* for that purpose.
*
* Return a dynamically alloated (heap) array of 'sadb_alg'
* descriptions. The first aNumAuth descriptors are authentication
* algorithms, and the tail aNumEncrypt are encryption
* algorithms.
*
* @retval aNumAuth Count of authentication algorithms
* @retval aNumEncrypt Count of cipher algorithms
* return Algorithm descriptions
*
* The return is guaranteed to be non-NULL, if aNumAuth + aNumEncrypt > 0.
*/
{
CArrayFixFlat<struct sadb_alg> *algs;
TInt n;
aNumAuth = 0;
aNumEncrypt = 0;
if (iAlgorithmList == NULL ||
iLibraryList == NULL ||
(n = iAlgorithmList->Count()) == 0)
return NULL; // No algorithms supported!
//
// Allocate all the space that is needed
//
// Sets 'aNumEncrypt' in case the heap allocations
// fail (a NULL return with non-zero count is used
// to indicate Memory Allocation error).
aNumEncrypt = n;
algs = new CArrayFixFlat<struct sadb_alg>(n);
if (!algs)
return NULL;
TRAPD(left, algs->ResizeL(n));
if (left)
{
delete algs;
return NULL;
}
aNumEncrypt = 0;
//
// -- All requred heap space has now been allocated --
// (The space is contigous in memory)
struct sadb_alg *auth = algs->Back(0);
struct sadb_alg *encrypt = algs->End(0);
for (TInt i = 0; i < n; ++i)
{
struct sadb_alg *alg;
TAlgorithmMap &p = iAlgorithmList->At(i);
if (p.iAlgorithm.Length() == 0 && p.iClass == EAlgorithmClass_Cipher )
{
// The NULL encryption is indicated by empty string in the
// algorithm name. NULL encryption is supported, if the
// mapping has such entry configured...
alg = encrypt - ++aNumEncrypt;
alg->sadb_alg_id = (TUint8)p.iId;
alg->sadb_alg_ivlen = 0;
alg->sadb_alg_minbits = 0;
alg->sadb_alg_maxbits = 0;
alg->sadb_alg_reserved = 0;
continue;
}
TLibraryPtr *lib;
TInt j = iLibraryList->Lookup(p, &lib);
if (lib != NULL)
{
// A matching library instance and algorithm
// located, fill in the algorithm description.
if (p.iClass == EAlgorithmClass_Digest)
{
alg = auth + aNumAuth++;
alg->sadb_alg_ivlen = 0;
}
else if (p.iClass == EAlgorithmClass_Cipher)
{
alg = encrypt - ++aNumEncrypt;
alg->sadb_alg_ivlen = (TUint8)lib->iAlgs[j].iVector;
}
#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
else if (p.iClass == EAlgorithmClass_Mac )
{
alg = auth + aNumAuth++;
alg->sadb_alg_ivlen = 0;
}
#endif //SYMBIAN_IPSEC_VOIP_SUPPORT
else
continue; // Some unknown algorithm class, that
// cannot be used by this implementation.
alg->sadb_alg_id = (TUint8)p.iId;
alg->sadb_alg_minbits = (TUint16)lib->iAlgs[j].iMinBits;
alg->sadb_alg_maxbits = (TUint16)lib->iAlgs[j].iMaxBits;
alg->sadb_alg_reserved = 0;
}
}
return algs;
}
class CAuthenticationHmac : public CAuthenticationBase
/**
* HMAC authentication.
*
* Implement the (RFC-2104) HMAC based keyed authentication as used by IPsec.
*/
{
friend class CIpsecCryptoManager;
public:
virtual void Init();
virtual void Update(const TDesC8& aMessage);
virtual const TDesC8 &Final(TInt aSize);
virtual TInt Compare(const TDesC8& aDigest);
virtual TInt BlockSize() const {return iBlockSize;}
//
// Return the number of bytes defined by the algorithm
// map, not the real digest length of the algorithm.
virtual TInt DigestSize() const {return (iBits + 7) / 8;}
protected:
static CAuthenticationHmac* NewL(const TLibraryPtr &lib, TUint anIndex, const TDesC8 &aKey, TInt aBits);
void ConstructL(const TLibraryPtr &lib, TUint anIndex, const TDesC8 &aKey, TInt aBits);
virtual ~CAuthenticationHmac();
private:
CAuthenticationHmac();
protected:
HBufC8 *iHmac_ipad; //< Precomputed HMAC input pad
HBufC8 *iHmac_opad; //< Precomputed HMAC output pad
HBufC8 *iTemp; //< Working space (at least native digest size)
TInt iBlockSize; //< The blocksize in bytes
TInt iDigestSize; //< The digest size in bytes
TInt iBits; //< Number of bits used from the digest.
CMessageDigestCrypto *iDigest;//< The raw message digest engine
};
CAuthenticationHmac::CAuthenticationHmac()
/**
* Constructor.
*/
{
}
CAuthenticationHmac* CAuthenticationHmac::NewL(const TLibraryPtr &aLib, TUint anIndex, const TDesC8 &aKey, TInt aBits)
/**
* Create HMAC authentication engine.
*
* @param aLib The library to use for the digest engine
* @param anIndex The digest algorithm number in library
* @param aKey The authentication key
* @param aBits The number of bits used from the digets.
*/
{
CAuthenticationHmac *self = new (ELeave) CAuthenticationHmac();
CleanupStack::PushL(self);
self->ConstructL(aLib, anIndex, aKey, aBits);
CleanupStack::Pop(); // self
return self;
}
void CAuthenticationHmac::ConstructL(const TLibraryPtr &aLib, TUint anIndex, const TDesC8 &aKey, TInt aBits)
{
/**
* Setup HMAC processing using the specified digest.
*
* @param aLib The library to use for the digest engine
* @param anIndex The digest algorithm number in library
* @param aKey The authentication key
* @param aBits The number of bits used from the digets.
*/
iDigest = aLib.iLibrary->MessageDigest(anIndex);
iBlockSize = aLib.iAlgs[anIndex].iBlock;
iDigestSize = aLib.iAlgs[anIndex].iVector;
iBits = aBits;
iHmac_ipad = HBufC8::NewMaxL(iBlockSize);
iHmac_opad = HBufC8::NewMaxL(iBlockSize);
iTemp = HBufC8::NewMaxL(iDigestSize);
TPtr8 ipad(iHmac_ipad->Des());
TPtr8 opad(iHmac_opad->Des());
if (aKey.Length() > iBlockSize)
{
iDigest->Init();
iDigest->Update(aKey);
iDigest->Final(ipad);
ipad.SetLength(iDigestSize);
}
else
ipad = aKey;
opad.SetLength(iBlockSize);
int i;
for (i = 0; i < ipad.Length(); ++i)
{
opad[i] = (TUint8)(ipad[i] ^ 0x5c);
ipad[i] ^= 0x36;
}
ipad.SetLength(iBlockSize);
for ( ;i < iBlockSize; ++i)
{
ipad[i] = 0x36;
opad[i] = 0x5c;
}
}
CAuthenticationHmac::~CAuthenticationHmac()
/**
* Destructor.
*
* Clear the memory areas containing the key information, before
* releasing the memory.
*/
{
if (iHmac_ipad)
{
iHmac_ipad->Des().FillZ();
delete iHmac_ipad;
}
if (iHmac_opad)
{
iHmac_opad->Des().FillZ();
delete iHmac_opad;
}
if (iTemp)
{
iTemp->Des().FillZ();
delete iTemp;
}
delete iDigest;
}
void CAuthenticationHmac::Init()
/**
* Initialize authentication for a packet.
*
* Reset digest enginge and feed the input (HMAC) pad to it.
*/
{
iDigest->Init(); // Initialize Digest engine
iDigest->Update(*iHmac_ipad); // Feed in the precomputed input pad
};
void CAuthenticationHmac::Update(const TDesC8& aMessage)
/**
* Feed data to the digest.
*
* @param aMessage The data.
*/
{
iDigest->Update(aMessage); // Feed actual payload material
}
const TDesC8 &CAuthenticationHmac::Final(TInt aSize)
/**
* Finish the digest computation and return ICV.
*
* @param aSize The length of the ICV (bytes).
* @return The computed ICV
*/
{
TPtr8 ptr = iTemp->Des();
ptr.SetLength(iDigestSize); // Ensure correct length! [also in *iTemp!]
iDigest->Final(ptr); // Get Current Digest Value
iDigest->Init(); // Initialize Digest Engine
iDigest->Update(*iHmac_opad); // Feed in the precomputed output pad
iDigest->Update(ptr); // Merge with digest from the first phase
iDigest->Final(ptr); // and produce the final digest value.
if (ptr.Length() > aSize) // The caller may want a trucated value
ptr.SetLength(aSize); // [This changes also *iTemp length!]
return *iTemp;
}
TInt CAuthenticationHmac::Compare(const TDesC8 &aDigest)
/**
* Finish the digets computation and compare with ICV.
*
* @param aDigest The ICV to match
* @return comparison result (= 0, match, != 0, no match).
*/
{
TPtr8 ptr = iTemp->Des();
ptr.SetLength(iDigestSize); // Ensure correct length!
iDigest->Final(ptr); // Get Current Digest Value
iDigest->Init(); // Initialize Digest Engine
iDigest->Update(*iHmac_opad); // Feed in the precomputed output pad
iDigest->Update(ptr); // Merge with digest from the first phase
iDigest->Final(ptr); // and produce the final digest value.
// The caller may want a tructated value
ptr.SetLength(aDigest.Length());
return aDigest.Compare(ptr);
}
class CEncryptionCipher : public CEncryptionBase
/**
* IPsec Cipher class using externally given algorithm.
*
* Acts as an intermediate between the IPsec and the raw external
* cryptographic algorithm.
*/
{
friend class CIpsecCryptoManager;
public:
virtual void EncryptL(const TDesC8& anIV); // Reset encryption engine
virtual void DecryptL(const TDesC8& anIV); // Reset encryption engine
virtual void UpdateL(TDes8& aBuf, TDes8& aBufOut); // Encrypt/decrypt a block
virtual void UpdateFinalL(TDes8& aBuf, TDes8& aBufOut); // Encrypt/decrypt the last block
virtual TInt BlockSize() const {return iBlockSize; } // Fetch the block size of the algorithm under consideration
virtual TInt GetOutputLength(TInt aInputLen); // Fetch the encrypt/decrypt output length of given block from crypto
virtual TInt GetFinalOutputLength(TInt aInputLen); // Fetch the encrypt/decrypt output length of final block from crypto
virtual TInt IVSize() const {return iIVSize;} // Fetch the IVSize of the algorithm under consideration
virtual void Reset(); // Reset the encryptor/decryptor state at the crypto layer
protected:
static CEncryptionCipher* NewL(const TLibraryPtr &aLib, TUint anIndex, const TDesC8 &aKey, TInt aBits);
void ConstructL(const TLibraryPtr &aLib, TUint anIndex, const TDesC8 &aKey, TInt aBits);
virtual ~CEncryptionCipher();
TInt iBlockSize; //< The blocksize in bytes
TInt iIVSize; //< The IV size in bytes
TInt iBits; //< Number of bits used from the IV
CryptoSpi::CSymmetricCipher *iEncrypt; //< The raw encryption engine
};
CEncryptionCipher*
CEncryptionCipher::NewL(const TLibraryPtr &aLib, TUint anIndex, const TDesC8 &aKey, TInt aBits)
/**
* Construct cipher engine.
*
* @param aLib The library to use.
* @param anIndex The algorithm number in library.
* @param aKey The encryption key to be used in the encryption/decryption operation
* @param aBits The IV length.
*/
{
CEncryptionCipher *self = new (ELeave) CEncryptionCipher();
CleanupStack::PushL(self);
self->ConstructL(aLib, anIndex, aKey, aBits);
CleanupStack::Pop(); // self
return self;
}
void CEncryptionCipher::ConstructL(const TLibraryPtr &aLib, TUint anIndex, const TDesC8 &aKey, TInt aBits)
{
iEncrypt = aLib.iLibrary->SymmetricCipherL(anIndex, aKey);
iBlockSize = aLib.iAlgs[anIndex].iBlock;
iIVSize = aLib.iAlgs[anIndex].iVector;
iBits = aBits;
}
CEncryptionCipher::~CEncryptionCipher()
/**
* Destructor.
*/
{
delete iEncrypt;
}
void CEncryptionCipher::EncryptL(const TDesC8& anIV)
/**
* Start cipher in encryption mode.
*
* @param anIV The IV to start with.
*/
{
iEncrypt->SetCryptoModeL(CryptoSpi::KCryptoModeEncryptUid);
iEncrypt->SetIvL(anIV);
}
void CEncryptionCipher::DecryptL(const TDesC8& anIV)
/**
* Start cipher in decryption mode.
*
* @param anIV The IV to start with.
*/
{
iEncrypt->SetCryptoModeL(CryptoSpi::KCryptoModeDecryptUid);
iEncrypt->SetIvL(anIV);
}
TInt CEncryptionCipher::GetOutputLength(TInt aInputLen)
/**
* Determine output length for the given input length
*
*@param aInputLen Length of the input data
*/
{
return iEncrypt->MaxOutputLength(aInputLen);
}
TInt CEncryptionCipher::GetFinalOutputLength(TInt aInputLen)
/**
* Determine output length for the given input length
*
*@param aInputLen Length of the input data
*/
{
return iEncrypt->MaxFinalOutputLength(aInputLen);
}
void CEncryptionCipher::UpdateL(TDes8& aBuf, TDes8& aBufOut)
/**
* Feed data to cipher engine (decrypt or encrypt).
*
* @param aBuf The input data buffer for encryption/decryption operation
* @param aBufOut The output data buffer for encryption/decryption operation
*
*/
{
iEncrypt->ProcessL(aBuf, aBufOut);
}
void CEncryptionCipher::UpdateFinalL(TDes8& aBuf, TDes8& aBufOut)
/**
* Feed data to cipher engine (decrypt or encrypt) to process the final block.
*
* @param aBuf The input data buffer for encryption/decryption operation
* @param aBufOut The output data buffer for encryption/decryption operation
*/
{
iEncrypt->ProcessFinalL(aBuf, aBufOut);
}
void CEncryptionCipher::Reset ()
/**
* Reset the state of encryption/decryption operation. Invoked as part of handling of internal errors.
*
* @param <None>
*/
{
if (iEncrypt)
{
iEncrypt->Reset();
}
}
class CEncryptionNull : public CEncryptionBase
/**
* NULL Encryption Engine.
*
* Implements the NULL encryption for the RFC-2410 purposes.
*/
{
friend class CIpsecCryptoManager;
public:
virtual void EncryptL(const TDesC8& /*anIV*/) {} // Reset encryption engine
virtual void DecryptL(const TDesC8& /*anIV*/) {} // Reset encryption engine
virtual void UpdateL(TDes8& aBuf, TDes8& aBufOut) { aBufOut.Copy(aBuf);} // Encrypt/decrypt a block
virtual void UpdateFinalL(TDes8& aBuf, TDes8& aBufOut) { aBufOut.Copy(aBuf);} // Encrypt/decrypt last block
virtual TInt GetOutputLength(TInt aInputLength) { return aInputLength;}
virtual TInt GetFinalOutputLength(TInt aInputLength) { return aInputLength;}
virtual TInt BlockSize() const {return 1; }
virtual TInt IVSize() const {return 0;}
virtual void Reset() {}
protected:
CEncryptionNull() {}
~CEncryptionNull() {}
};
CEncryptionBase *CIpsecCryptoManager::NewEncryptL(TInt anAlg, const TDesC8 &aKey)
/**
* Create an instance of cipher engine.
*
* Create a new IPsec encryption engine (CEncryptionBase) using the key and
* encryption algorithm (anAlg).
*
* @li First, use the algorithm number to locate the symbolic name
* name of the algorithm from the algorithm map
* @li then use this name to search supported algorithm from the
* installed crypto libraries.
* If found, ask the the library to create a symmetric cipher engine for
* this algorithm.
*
* @param anAlg The algorithm number
* @param aKey The key for the algorithm
* @return The cipher engine.
*/
{
TAlgorithmMap *map = iAlgorithmList->Lookup(EAlgorithmClass_Cipher, anAlg);
if (!map)
User::Leave(EIpsec_UnknownCipherNumber);
if (map->iAlgorithm.Length() == 0)
//
// The NULL encryption is indicated by empty string in the
// algorithm name. Instantiate a NULL encryption "cipher"
return new CEncryptionNull();
TLibraryPtr *lib;
TUint index = iLibraryList->Lookup(*map, &lib);
if (!lib)
User::Leave(EIpsec_UnavailableCipher);
LOG(Log::Printf(_L("\t* using cipher %S(%d) from library %S"), &map->iAlgorithm, anAlg, &lib->iName));
CEncryptionCipher *enc = CEncryptionCipher::NewL(*lib, index, aKey, map->iBits);
if (enc && enc->iEncrypt)
{
return enc; // All OK.
}
delete enc;
//
// Getting here implies fatal error, something is not working
//
return NULL;
}
CAuthenticationBase *CIpsecCryptoManager::NewAuthL(TInt anAlg, const TDesC8 &aKey)
/**
* Create an instance of authentication engine.
* Create a new IPsec authentication engine (CAuthenticationBase) using the key and
* digest algorithm (anAlg). First use the algorithm number to find the symbolic
* name of the algorithm from the algorithm map, then use this name to search
* supported algorithm from the installed crypto libraries. If found,
* ask the library to create a raw message digest engine for this algorithm.
*
* The current IPsec authentication uses the digest engine to implement HMAC
* keyed-hash authentication as described in RFC-2104. The number of bits
* actually used from the digest value is determined by the respective
* configuration parameter in the algorithm map entry.
*
* @param anAlg The authentication algorithm number
* @param aKey The authentication key
* @return The authentication engine.
*
* @leave EIpsec_UnknownDigestNumber if anAlg does not appear in algorithm list
* @leave EIpsec_UnavailableDigest if no library implements the requested algorithm
* @leave other on other errors
*/
{
TAlgorithmMap *map = iAlgorithmList->Lookup(EAlgorithmClass_Digest, anAlg);
if (!map)
User::Leave(EIpsec_UnknownDigestNumber);
if (map->iAlgorithm.Length() > 0)
{
TLibraryPtr *lib;
TUint index = iLibraryList->Lookup(*map, &lib);
if (!lib)
User::Leave(EIpsec_UnavailableDigest);
LOG(Log::Printf(_L("\t* using digest %S(%d) from library %S"), &map->iAlgorithm, anAlg, &lib->iName));
return CAuthenticationHmac::NewL(*lib, index, aKey, map->iBits);
}
//
// Getting here implies fatal error, something is not working
//
return NULL;
}
#ifdef SYMBIAN_IPSEC_VOIP_SUPPORT
class CAuthenticationMac : public CAuthenticationBase
{
friend class CIpsecCryptoManager;
public:
virtual void Init() ;
virtual void Update(const TDesC8& aMessage);
virtual const TDesC8 &Final(TInt aSize);
virtual TInt BlockSize() const {return iBlockSize;}
virtual TInt Compare(const TDesC8& aDigest);
virtual TInt DigestSize() const {return (iBits + 7) / 8;}
//
// Return the number of bytes defined by the algorithm
// map, not the real digest length of the algorithm.
virtual TInt MacSize() const {return (iBits + 7) / 8;}
protected:
static CAuthenticationMac* NewL(const TLibraryPtr &lib, TUint anIndex, const TDesC8 &aKey, TInt aBits);
void ConstructL(const TLibraryPtr &lib, TUint anIndex, const TDesC8 &aKey, TInt aBits);
virtual ~CAuthenticationMac();
private:
CAuthenticationMac();
protected:
TInt iBlockSize; //< The blocksize in bytes
TInt iMacOutputSize; //< The digest size in bytes
TInt iBits; //< Number of bits used from the digest.
TInt iIVSize;
HBufC8* iTemp;
CMacCrypto *iMacCrypto;
CryptoSpi::CMac *iMacImpl;
};
CAuthenticationMac::CAuthenticationMac()
/**
* Constructor.
*/
{
}
CAuthenticationMac::~CAuthenticationMac()
/**
* Destructor.
*
* Clear the memory areas containing the key information, before
* releasing the memory.
*/
{
}
void CAuthenticationMac::Init()
/**
* Initialize authentication for a packet.
*
* Reset digest enginge and feed the input (HMAC) pad to it.
*/
{
};
CAuthenticationMac* CAuthenticationMac::NewL(const TLibraryPtr &aLib, TUint anIndex, const TDesC8 &aKey, TInt aBits)
/**
* Create MAC authentication engine.
*
* @param aLib The library to use for the MacCrypto engine
* @param anIndex The digest algorithm number in library
* @param aKey The authentication key
* @param aBits The number of bits used from the digets.
*/
{
CAuthenticationMac *self = new (ELeave) CAuthenticationMac();
CleanupStack::PushL(self);
self->ConstructL(aLib, anIndex, aKey, aBits);
CleanupStack::Pop(); // self
return self;
}
void CAuthenticationMac ::ConstructL(const TLibraryPtr &aLib, TUint anIndex, const TDesC8 &aKey, TInt aBits)
{
iMacImpl = aLib.iLibrary->GetMacImplementationL( aKey);
iMacOutputSize = aLib.iAlgs[anIndex].iVector;
iBlockSize = aLib.iAlgs[anIndex].iBlock;
iIVSize = aLib.iAlgs[anIndex].iVector;
iBits = aBits;
iTemp = HBufC8::NewMaxL(iMacOutputSize);
}
void CAuthenticationMac::Update(const TDesC8& aMessage)
/**
* Feed data to the digest.
*
* @param aMessage The data.
*/
{
iMacImpl->UpdateL(aMessage); // Feed actual payload material
}
const TDesC8 &CAuthenticationMac::Final(TInt /* aSize */)
/**
* Finish the digest computation
*/
{
//presently return temp value
return *iTemp;
}
TInt CAuthenticationMac::Compare(const TDesC8 &aDigest)
/**
* Finish the digets computation and compare with ICV.
*
* @param aDigest The ICV to match
* @return comparison result (= 0, match, != 0, no match).
*/
{
return aDigest.Compare(iTemp->Des());
}
CAuthenticationBase *CIpsecCryptoManager::NewMacL(TInt anAlg, const TDesC8 &aKey)
{
TAlgorithmMap *map = iAlgorithmList->Lookup(EAlgorithmClass_Mac, anAlg);
if (!map)
User::Leave(EIpsec_UnknownCipherNumber);
if (map->iAlgorithm.Length() > 0)
{
TLibraryPtr *lib;
TUint index = iLibraryList->Lookup(*map, &lib);
if (!lib)
User::Leave(EIpsec_UnavailableCipher);
LOG(Log::Printf(_L("\t* using digest %S(%d) from library %S"), &map->iAlgorithm, anAlg, &lib->iName));
return CAuthenticationMac::NewL(*lib, index, aKey, map->iBits);
}
//
// Getting here implies fatal error, something is not working
//
return NULL;
}
#endif //SYMBIAN_IPSEC_VOIP_SUPPORT