diff -r 000000000000 -r 33413c0669b9 vpnengine/ikev2lib/src/ikecrypto.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vpnengine/ikev2lib/src/ikecrypto.cpp Thu Dec 17 09:14:51 2009 +0200 @@ -0,0 +1,332 @@ +/* +* Copyright (c) 2003-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: Intermediate class between IKEv2 and crypto library. +* +*/ + + +#include "dhparameters.h" +#include "ikecrypto.h" +#include "ikev2const.h" + +CDHKeys* CDHKeys::NewL(const TDesC8& aN, const TDesC8& aG) +{ + CDHKeys *keys = new (ELeave) CDHKeys(); + keys->iDHKey = TUtlCrypto::MakeDiffieHellmanL(aN, aG); + keys->iModuluslength = aN.Length(); + return keys; +} + +CDHKeys* CDHKeys::CreateDHKeyL(TUint aGroupDesc) +{ + TPtrC8 prime_ptr(NULL, 0); + TPtrC8 gen_ptr(NULL, 0); + + switch (aGroupDesc) + { + case DH_GROUP_768: + prime_ptr.Set((TUint8 *)&MODP_768_PRIME[0], MODP_768_PRIME_LENGTH); + gen_ptr.Set((TUint8 *)&MODP_768_GENERATOR[0], MODP_768_GENERATOR_LENGTH); + break; + case DH_GROUP_1024: + prime_ptr.Set((TUint8 *)&MODP_1024_PRIME[0], MODP_1024_PRIME_LENGTH); + gen_ptr.Set((TUint8 *)&MODP_1024_GENERATOR[0], MODP_1024_GENERATOR_LENGTH); + break; + case DH_GROUP_1536: + prime_ptr.Set((TUint8 *)&MODP_1536_PRIME[0], MODP_1536_PRIME_LENGTH); + gen_ptr.Set((TUint8 *)&MODP_1536_GENERATOR[0], MODP_1536_GENERATOR_LENGTH); + break; + case DH_GROUP_2048: + prime_ptr.Set((TUint8 *)&MODP_2048_PRIME[0], MODP_2048_PRIME_LENGTH); + gen_ptr.Set((TUint8 *)&MODP_2048_GENERATOR[0], MODP_2048_GENERATOR_LENGTH); + break; + default: //Cannot happen because checked before!!! + User::Leave(KErrNotSupported); + } + + CDHKeys *DhKeys = CDHKeys::NewL(prime_ptr, gen_ptr); + + return DhKeys; +} + +HBufC8* CDHKeys::ComputeAgreedKeyL(const TDesC8 &aPeerPublicKey) +{ + return (HBufC8*)KValueL(aPeerPublicKey); +} + + +HBufC8* CDHKeys::GetPubKey() +{ + HBufC8* DHPublicKey = (HBufC8*)iPubKey; + iPubKey = NULL; // Exclusive ownership of iPubKey buffer is returned to caller + return DHPublicKey; +} + +void CDHKeys::XValueL() +{ + if ( !iPubKey ) + iPubKey = iDHKey->GenerateXL(); +} + +CDHKeys::~CDHKeys() +{ + delete iDHKey; +} + + +void IkeCrypto::DecryptL(const TUint8* aInput, TUint8* aOutput, TInt aLength, + TUint8* aIV, const TDesC8& aKey, TUint16 aEncrAlg) +{ + TUtlCrypto::TUtlSymmetricCipherId CipherId; + TInt IVLth; + IkeCrypto::AlgorithmInfo(IKEV2_ENCR, aEncrAlg, &IVLth, &CipherId); + + if ( !aInput || !aOutput || !aIV ) + User::Leave(KErrArgument); + + TPtrC8 IvPtr(aIV, IVLth); + TPtrC8 CipherText(aInput, aLength); + TPtr8 PlainText(aOutput, aLength); + + CUtlSymmetricCipher* UtlCipher = + TUtlCrypto::MakeSymmetricDecryptorL(CipherId, aKey, IvPtr); + CleanupStack::PushL(UtlCipher); + UtlCipher->ProcessFinalL(CipherText, PlainText); + CleanupStack::PopAndDestroy(UtlCipher); +} + + +void IkeCrypto::EncryptL(const TDesC8& aInput, TPtr8& aOutput, + const TDesC8& aIv, const TDesC8& aKey, TUint16 aEncrAlg) +{ + TUtlCrypto::TUtlSymmetricCipherId CipherId; + TInt CbLth; + IkeCrypto::AlgorithmInfo(IKEV2_ENCR, aEncrAlg, &CbLth, &CipherId); + + __ASSERT_DEBUG(CbLth == aIv.Length(), User::Invariant()); + __ASSERT_DEBUG(aInput.Length() % CbLth == 0, User::Invariant()); + __ASSERT_DEBUG(aInput.Length() <= aOutput.MaxLength(), User::Invariant()); + + CUtlSymmetricCipher* UtlCipher = + TUtlCrypto::MakeSymmetricEncryptorL(CipherId, aKey, aIv); + CleanupStack::PushL(UtlCipher); + UtlCipher->ProcessFinalL(aInput, aOutput); + CleanupStack::PopAndDestroy(UtlCipher); +} + +TInt IkeCrypto::IntegHMACL(const TDesC8& aInput, TDes8& aChecksum, const TDesC8& aKeyData, TUint16 aIntegAlg) +{ + TUtlCrypto::TUtlMessageDigestId DigestId; + TInt HmacLth; + IkeCrypto::AlgorithmInfo(IKEV2_INTEG, aIntegAlg, &HmacLth, NULL, &DigestId); + CUtlMessageDigest* Digest = TUtlCrypto::MakeMessageDigesterL(DigestId, aKeyData); + + const TPtrC8 hash = Digest->Final(aInput); + + //We don't always use the whole hash. + //(e.g., HMAC-SHA1-96 uses only first 12 bytes) + __ASSERT_DEBUG(hash.Length() >= HmacLth, User::Invariant()); + + aChecksum = hash.Left(HmacLth); + delete Digest; + + return HmacLth; +} + +HBufC8* IkeCrypto::PrfhmacL(const TDesC8& aInput, const TDesC8& aKeyData, TUint16 aPrfAlg) +{ + TUtlCrypto::TUtlMessageDigestId DigestId; + TInt PrfLth; + IkeCrypto::AlgorithmInfo(IKEV2_PRF, aPrfAlg, &PrfLth, NULL, &DigestId); + CUtlMessageDigest* Digest = TUtlCrypto::MakeMessageDigesterL(DigestId, aKeyData); + CleanupStack::PushL(Digest); + + HBufC8* checksum = Digest->Final(aInput).AllocL(); + + CleanupStack::PopAndDestroy(Digest); + + return checksum; + +} + +HBufC8* IkeCrypto::PrfL(const TDesC8& aInput, TUint16 aPrfAlg) +{ + TUtlCrypto::TUtlMessageDigestId DigestId; + TInt PrfLth; + IkeCrypto::AlgorithmInfo(IKEV2_PRF, aPrfAlg, &PrfLth, NULL, &DigestId); + CUtlMessageDigest* digest = TUtlCrypto::MakeMessageDigesterL(DigestId); + CleanupStack::PushL(digest); + + HBufC8* hash = digest->Final(aInput).AllocL(); + + CleanupStack::PopAndDestroy(digest); + + return hash; + +} + +TInt IkeCrypto::AlgorithmInfo(TUint16 aTransform, TUint16 aAlgCode, TInt* aBlockLth, + TUtlCrypto::TUtlSymmetricCipherId* aCipherId, + TUtlCrypto::TUtlMessageDigestId* aDigestId) +{ + TInt KeyLth = 0; + TInt BlockLth = 0; + + switch ( aTransform ) + { + case IKEV2_ENCR: + switch ( aAlgCode ) + { + case ENCR_DES: + KeyLth = 8; + BlockLth = 8; + if ( aCipherId ) + *aCipherId = TUtlCrypto::EUtlSymmetricCipherDesCbc; + break; + + case ENCR_3DES: + KeyLth = 24; + BlockLth = 8; + if ( aCipherId ) + *aCipherId = TUtlCrypto::EUtlSymmetricCipher3DesCbc; + break; + + case ENCR_AES_CBC: + KeyLth = 0; + BlockLth = 16; + if ( aCipherId ) + *aCipherId = TUtlCrypto::EUtlSymmetricCipherAesCbc; + break; + + case ENCR_NULL: + KeyLth = 0; + BlockLth = 0; + break; + default: + break; + } + break; + + case IKEV2_PRF: + switch ( aAlgCode ) + { + case PRF_HMAC_MD5: + KeyLth = 16; + BlockLth = 16; + if ( aDigestId ) + *aDigestId = TUtlCrypto::EUtlMessageDigestMd5; + break; + + case PRF_HMAC_SHA1: + KeyLth = 20; + BlockLth = 20; + if ( aDigestId ) + *aDigestId = TUtlCrypto::EUtlMessageDigestSha1; + break; + + default: + break; + } + break; + + case IKEV2_INTEG: + switch ( aAlgCode ) + { + case AUTH_HMAC_MD5_96: + KeyLth = 16; + BlockLth = 12; + if ( aDigestId ) + *aDigestId = TUtlCrypto::EUtlMessageDigestMd5; + break; + + case AUTH_HMAC_SHA1_96: + KeyLth = 20; + BlockLth = 12; + if ( aDigestId ) + *aDigestId = TUtlCrypto::EUtlMessageDigestSha1; + break; + + default: + break; + } + break; + + default: + break; + + } + + if ( aBlockLth ) + *aBlockLth = BlockLth; + + return KeyLth; + +} + +HBufC8* IkeCrypto::GenerateKeyingMaterialL(const TDesC8& aK, const TDesC8& aS, TInt aKeyMatLth, TUint16 aPRFAlg) +{ + // + // Since the amount of keying material needed may be greater than + // the size of the output of the prf algorithm prf+ is used as + // follows prf+ (K,S) = T1 | T2 | T3 | T4 | ... + // where: T1 = prf (K, S | 0x01) + // T2 = prf (K, T1 | S | 0x02) .. + // TN = prf (K, TN-1 | S | 0xN ) ;[ N < 256 ] + // + TInt PrfKeyLth = IkeCrypto::AlgorithmInfo(IKEV2_PRF, aPRFAlg, NULL); + TInt S_Lth = aS.Length(); + TUint8 IterCount = (TUint8)((aKeyMatLth/PrfKeyLth) + 1); + HBufC8* KeyMat = HBufC8::NewL((IterCount * PrfKeyLth) + S_Lth + 1); + CleanupStack::PushL(KeyMat); + TPtr8 KeyMatPtr(KeyMat->Des()); + + TUint8 i = 1; + // + // Produce key material T1 | T2 | T3 | T4 | ... + // + + HBufC8* tValue = NULL; + HBufC8* inputBuffer = HBufC8::NewLC(PrfKeyLth + aS.Length() + sizeof(i)); + TPtr8 inputBufferPtr(inputBuffer->Des()); + while ( i <= IterCount ) + { + inputBufferPtr.Zero(); + if (tValue != NULL) + { + inputBufferPtr.Append(*tValue); + } + // + // Append value S into key material buffer and concatenate 8 bit integer + // value i into S + // + inputBufferPtr.Append(aS); + inputBufferPtr.Append(&i, sizeof(i)); + + delete tValue; + tValue = NULL; + // + // Calculate TN = prf (SKEYSEED, TN-1 | S | 0xN) + // + tValue = IkeCrypto::PrfhmacL(*inputBuffer, aK, aPRFAlg); + KeyMatPtr.Append(*tValue); + i++; + } + delete tValue; + + CleanupStack::PopAndDestroy(inputBuffer); + CleanupStack::Pop(); // Keymat + + return KeyMat; +} +