vpnengine/ikev2lib/src/ikecrypto.cpp
changeset 0 33413c0669b9
child 8 032d3a818f49
--- /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;
+}
+