diff -r 000000000000 -r 33413c0669b9 vpnengine/ikev1lib/src/ikev1crypto.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vpnengine/ikev1lib/src/ikev1crypto.cpp Thu Dec 17 09:14:51 2009 +0200 @@ -0,0 +1,369 @@ +/* +* 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: +* Crypto Layer to use and change any cryptolibrary easily. +* Contains all the cryptographic functions used in IKEv1. +* +*/ + + + +#include "ikev1crypto.h" +#include "ikemsgheader.h" +#include "dhparameters.h" +#include "utlcrypto.h" + +CIkeKeys* CIkeKeys::NewL(const TDesC8& aN, const TDesC8& aG) +{ + CIkeKeys *keys = new (ELeave) CIkeKeys(); + keys->iDHKey = TUtlCrypto::MakeDiffieHellmanL(aN, aG); + keys->iModuluslength = aN.Length(); + return keys; +} + +CIkeKeys::~CIkeKeys() +{ + delete iDHKey; +} + + +HBufC8* CIkeKeys::GetPubKey() +{ + HBufC8* DHPublicKey = (HBufC8*)iPubKey; + iPubKey = NULL; // Exclusive ownership of iPubKey buffer is returned to caller + return DHPublicKey; +} + +void CIkeKeys::XValueL() +{ + iPubKey = iDHKey->GenerateXL(); +} + + +const HBufC8* CIkeKeys::KValueL(const TDesC8& aY) const +{ + return iDHKey->CompleteKL(aY); +} + + + + +//Generates a group of parameters depending on the group. +CIkeKeys *CreateDHKeyL(TUint aGroupDesc) +{ + TPtrC8 prime_ptr(NULL, 0); + TPtrC8 gen_ptr(NULL, 0); + + switch (aGroupDesc) + { + case MODP_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 MODP_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 MODP_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 MODP_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; + case EC2N_155: + case EC2N_185: + return NULL; + default: //Cannot happen because checked before!!! + return NULL; + } + + CIkeKeys *arg = CIkeKeys::NewL(prime_ptr, gen_ptr); + + return arg; +} + +CIkeKeys *GeneratePubPrivKeysL(TUint aGroupDesc) +{ + CIkeKeys *dh_key = CreateDHKeyL(aGroupDesc); + if (!dh_key) + return NULL; + dh_key->XValueL(); //Initializes the public and private keys. + + return dh_key; + +} + +HBufC8* ComputeAgreedKeyL(TUint /*aGroupDesc*/, const TDesC8 &aPeerPublicKey, CIkeKeys *aOwnKeys) +{ + if(!aOwnKeys) + return NULL; + + return (HBufC8*)aOwnKeys->KValueL(aPeerPublicKey); +} + +void DecryptL(const TUint8* aInputPayload, TUint8* aOutputPayload, TUint32 aLength, TDes8& aIV, TDesC8& aKey, TUint16 aEncrAlg) +{ + TUtlCrypto::TUtlSymmetricCipherId CipherId = TUtlCrypto::EUtlSymmetricCipherAesCbc; // Defaults + TInt IVLth = AESCBC_IV_LEN; + + if ( aEncrAlg == DES3_CBC ) + { + CipherId = TUtlCrypto::EUtlSymmetricCipher3DesCbc; + IVLth = DESCBC_IV_LEN; + } + else if ( aEncrAlg == DES_CBC) + { + CipherId = TUtlCrypto::EUtlSymmetricCipherDesCbc; + IVLth = DESCBC_IV_LEN; + } + // + // Construct cipher object for symmetric decrypt operation + // + TPtrC8 iv_ptr(aIV.Ptr(), IVLth); + TPtrC8 ciphertext(aInputPayload, aLength); + TPtr8 plaintext(aOutputPayload, aLength); + + CUtlSymmetricCipher* UtlCipher = TUtlCrypto::MakeSymmetricDecryptorL(CipherId, + aKey, + iv_ptr); + + CleanupStack::PushL(UtlCipher); + UtlCipher->ProcessFinalL(ciphertext, plaintext); + CleanupStack::PopAndDestroy(); + aIV.Copy(&aInputPayload[aLength - IVLth], IVLth); //Next IV (last 8 bytes of ciphertext) + +} + +TBool EncryptL(TDes8& aInputPayload, TDes8& aOutputPayload, TDes8& aIV, TDesC8& aKey, TUint16 aEncrAlg) +{ + TUtlCrypto::TUtlSymmetricCipherId CipherId = TUtlCrypto::EUtlSymmetricCipherAesCbc; // Defaults + TInt CbLth = AESCBC_IV_LEN; + + if ( aEncrAlg == DES3_CBC ) + { + CipherId = TUtlCrypto::EUtlSymmetricCipher3DesCbc; + CbLth = DESCBC_IV_LEN; + } + else if ( aEncrAlg == DES_CBC) + { + CipherId = TUtlCrypto::EUtlSymmetricCipherDesCbc; + CbLth = DESCBC_IV_LEN; + } + TPtrC8 iv_ptr(aIV.Ptr(), CbLth); + // + // Add padding, if needed + // + TUint padding_bytes = (aInputPayload.Length() - ISAKMP_HDR_SIZE) % CbLth; + if (padding_bytes != 0) //Padd with 0 at the end if needed + { + TChar c(0); + aInputPayload.AppendFill(c,CbLth-padding_bytes); //Append at the end + } + // + // ISAKMP fixed header not encrypted + // + TPtrC8 plaintext(aInputPayload.Ptr() + ISAKMP_HDR_SIZE, aInputPayload.Length() - ISAKMP_HDR_SIZE);//skip hdr + aOutputPayload.Copy(aInputPayload.Ptr(), ISAKMP_HDR_SIZE); //The same HDR in output + + TPtr8 ciphertext((TUint8 *)aOutputPayload.Ptr() + ISAKMP_HDR_SIZE, 0, aInputPayload.Length() - ISAKMP_HDR_SIZE);//skip hdr + // + // Construct cipher object for symmetric decrypt operation + // + CUtlSymmetricCipher* UtlCipher = TUtlCrypto::MakeSymmetricEncryptorL(CipherId, + aKey, + iv_ptr); + CleanupStack::PushL(UtlCipher); + UtlCipher->ProcessFinalL(plaintext, ciphertext); + CleanupStack::PopAndDestroy(); + // + // Next IV (last cipher block of encrypted buffer) + // + aOutputPayload.SetLength(ISAKMP_HDR_SIZE + ciphertext.Length()); + aIV.Copy(aOutputPayload.Ptr() + aOutputPayload.Length() - CbLth, CbLth); + + return ETrue; + +} + + +void MD5HashL(const TDesC8 &aInData, TDes8& aOutData) +{ + CUtlMessageDigest* Digest = TUtlCrypto::MakeMessageDigesterL(TUtlCrypto::EUtlMessageDigestMd5); + aOutData.Copy(Digest->Final(aInData)); + delete Digest; +} + +void SHA1HashL(const TDesC8 &aInData, TDes8& aOutData) +{ + CUtlMessageDigest* Digest = TUtlCrypto::MakeMessageDigesterL(TUtlCrypto::EUtlMessageDigestSha1); + aOutData.Copy(Digest->Final(aInData)); + delete Digest; +} + +void MD5HmacL(const TDesC8 &aInData, TDes8& aOutData, const TDesC8& aKeyData) +{ + CUtlMessageDigest* Digest = TUtlCrypto::MakeMessageDigesterL(TUtlCrypto::EUtlMessageDigestMd5, + aKeyData); + aOutData.Copy(Digest->Final(aInData)); + delete Digest; +} + +void SHA1HmacL(const TDesC8 &aInData, TDes8& aOutData, const TDesC8& aKeyData) +{ + CUtlMessageDigest* Digest = TUtlCrypto::MakeMessageDigesterL(TUtlCrypto::EUtlMessageDigestSha1, + aKeyData); + aOutData.Copy(Digest->Final(aInData)); + delete Digest; +} + +void Hmac3DesCbcL(const TDesC8 &aInData, TDes8& aOutData, const TDesC8& aKeyData) +{ + TUint8 *pad = new (ELeave) TUint8[PAD_SIZE]; + TInt pad_len = 0; + CleanupStack::PushL(pad); + TBuf8<8> iv; + TBuf8<24> prf_key2; + TPtrC8 prf_key_ptr; + + if ( aKeyData.Length() < 24) //if less than 24 bits the rest must be 0's + { + prf_key2.FillZ(24); + prf_key2.Copy(aKeyData); + prf_key2.SetLength(24); + prf_key_ptr.Set(prf_key2); + } + else + { + prf_key_ptr.Set(aKeyData); + } + iv.FillZ(8); + Mem::Copy(pad, aInData.Ptr(), aInData.Length()); + pad_len = aInData.Length(); + if ( pad_len & 0x07 ) //Add padding to align to byte pieces?????????? + { + Mem::FillZ(&pad[pad_len], 7); + pad_len += 7; + pad_len = (pad_len & 65528) + 8; + } + Cipher3DesL(pad, pad_len, prf_key_ptr, iv, aOutData); + + CleanupStack::PopAndDestroy(); //pad + +} + +void Cipher3DesL(TUint8 *aInData, TInt aInDataLen, const TDesC8 &aPrfKey, TDes8 &aIV, TDes8 &aOutData) +{ + + TPtrC8 iv_ptr(aIV.Ptr(), DESCBC_IV_LEN); + TPtrC8 key_ptr(aPrfKey.Ptr(), 3*DESCBC_KEY_LEN); + + HBufC8 *des_input = HBufC8::NewL(aInDataLen + 8); + CleanupStack::PushL(des_input); + TPtr8 des_input_ptr((TUint8 *)des_input->Des().Ptr(), aInDataLen + 8, aInDataLen + 8); //Contains the PRF input text + TPtrC8 plain_input_text(aInData, aInDataLen);//skip hdr + // + // Construct cipher object for symmetric decrypt operation + // + CUtlSymmetricCipher* UtlCipher = TUtlCrypto::MakeSymmetricEncryptorL(TUtlCrypto::EUtlSymmetricCipher3DesCbc, + key_ptr, + iv_ptr); + CleanupStack::PushL(UtlCipher); + + HBufC8 *des_output= HBufC8::NewL(des_input_ptr.Length() + UtlCipher->BlockSize()); + CleanupStack::PushL(des_output); + TPtr8 des_output_ptr((TUint8 *)des_output->Des().Ptr(), des_input_ptr.Length() + UtlCipher->BlockSize()); + + UtlCipher->ProcessFinalL(plain_input_text, des_output_ptr); + TPtrC8 tmp_input_data(&des_output_ptr[des_output_ptr.Length() - 8], 8); //Input Data to the 2nd 8-bit chunk encryption + UtlCipher->Reset(); //Restart + UtlCipher->ProcessFinalL(tmp_input_data, aOutData); + + // Do second eight bytes + des_input_ptr.Copy(aOutData); + des_input_ptr.Append(plain_input_text); //reattach the input data + UtlCipher->Reset(); //Restart + UtlCipher->ProcessFinalL(des_input_ptr, des_output_ptr); + + tmp_input_data.Set(&des_output_ptr[des_output_ptr.Length() - 8], 8); + TPtr8 out_data_ptr((TUint8 *)aOutData.Ptr() + 8, 0, 8); + UtlCipher->Reset(); //Restart + UtlCipher->ProcessFinalL(tmp_input_data, out_data_ptr); + + // Do third eight bytes + Mem::Copy((TUint8 *)des_input_ptr.Ptr(), aOutData.Ptr() + 8, 8); //last 8 bytes of previous result put at the beginning + //The length of des_input_ptr won't change so the data after byte 8 is still used!!! + UtlCipher->Reset(); //Restart + UtlCipher->ProcessFinalL(des_input_ptr, des_output_ptr); + + tmp_input_data.Set(&des_output_ptr[des_output_ptr.Length() - 8], 8); + out_data_ptr.Set((TUint8 *)aOutData.Ptr() + 16, 0, 8); //the last 8 bytes (16 to 23) + UtlCipher->Reset(); //Restart + UtlCipher->ProcessFinalL(tmp_input_data, out_data_ptr); + + aOutData.SetLength(24); + + CleanupStack::PopAndDestroy(3); // des_output, UtlCipher and des_input +} + +TInt SymmetricCipherL(TUint8 *aInput, TUint8 *aOutput, TInt aLength, + TUint8 *aKey, TUint8 *aIV, TBool aEncr, TInt aEncAlg) +{ + (void)aEncAlg; + TPtrC8 iv_ptr(aIV, DESCBC_IV_LEN ); + TPtrC8 key_ptr(aKey, DESCBC_IV_LEN); + + CUtlSymmetricCipher* UtlCipher; + if ( aEncr ) { + // + // Add padding (according RFC 1423) and encrypt data + // + TInt PaddingBytes = 8 - (aLength % 8); + for ( TInt i = 0; i < PaddingBytes; i++ ) { + *(aInput + aLength + i) = (TUint8)PaddingBytes; + } + aLength += PaddingBytes; + UtlCipher = TUtlCrypto::MakeSymmetricEncryptorL(TUtlCrypto::EUtlSymmetricCipherDesCbc, + key_ptr, iv_ptr); + } + else { + // + // Decrypt data + // + UtlCipher = TUtlCrypto::MakeSymmetricDecryptorL(TUtlCrypto::EUtlSymmetricCipherDesCbc, + key_ptr, iv_ptr); + } + CleanupStack::PushL(UtlCipher); + TPtrC8 inp(aInput, aLength); + TPtr8 outp(aOutput, aLength); + UtlCipher->ProcessFinalL(inp, outp); + CleanupStack::PopAndDestroy(); + + if ( !aEncr ) { + // + // Remove padding from decrypted data + // + TUint8 PaddingLth = *(aOutput + aLength - 1); + if ( PaddingLth < 9 ) + aLength -= (TInt)PaddingLth; // Ok padding count + else aLength = 0; + } + + return aLength; + +} + + +