--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linklayerprotocols/pppnif/SPPP/mschap2.cpp Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,826 @@
+// 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:
+// Extensions, Version 2 (MS-CHAP-V2) - RFC 2759, except the
+// authenticator-controlled authentication retry mechanisms and the
+// password changing mechanisms - this is in accordance with the
+// requirements.
+//
+//
+
+/**
+ @file
+ @brief Source file for the implementation of Microsoft PPP CHAP
+ @internalComponent
+*/
+
+#include "mschap2.h"
+#include "MSCHAP.H"
+
+// using SHA-1
+#include <hash.h>
+
+// using DES
+#include <symmetric.h>
+
+// using random
+#include <random.h>
+// using MD4
+#include "MD4.H"
+#include "PPPConfig.h"
+
+
+CPppMsChap2::CPppMsChap2()
+/**
+ Constructor.
+ @internalComponent
+*/
+ : iResponseValue(KPppMsChap2ResponseValueSize),
+ iAuthenticatorResponse(KPppMsChap2AuthenticatorResponseSize)
+ {
+ }
+
+
+CPppMsChap2::~CPppMsChap2()
+/**
+ Destructor.
+ @internalComponent
+*/
+ {
+#ifdef _UNICODE
+ delete iUserName;
+#endif
+ }
+
+void CPppMsChap2::InitL(CPppLcp* aLcp)
+/**
+ @copydoc CPppChap::InitL(CPppLcp*)
+ @see CPppChap::InitL(CPppLcp*)
+ @internalComponent
+*/
+ {
+ CPppChap::InitL(aLcp);
+ }
+
+
+void CPppMsChap2::CheckChallengePacketL(RMBufPacket& aPacket)
+/**
+ @copydoc CPppChap::CheckChallengePacketL(RMBufPacket&)
+ @copydoc CPppChap::CheckChallengePacketL(RMBufPacket&)
+ @internalComponent
+*/
+ {
+ __ASSERT_ALWAYS(aPacket.Length() >= KPppChapCodeFieldSize +
+ KPppChapIdFieldSize +
+ KPppChapLengthFieldSize +
+ KPppChapValueSizeFieldSize +
+ KPppMsChap2AuthenticatorChallengeSize,
+ User::Leave(KErrUnderflow));
+
+ __ASSERT_ALWAYS(*(aPacket.First()->Ptr() +
+ KPppChapCodeFieldSize +
+ KPppChapIdFieldSize +
+ KPppChapLengthFieldSize) ==
+ KPppMsChap2AuthenticatorChallengeSize,
+ User::Leave(KErrOverflow));
+ }
+
+
+void CPppMsChap2::MakeResponseL(TUint8 /*aChallengeId*/,
+ const TDesC8& aChallengeValue,
+ TPtrC8& aResponseValue,
+ TPtrC8& aResponseName)
+/**
+ @copydoc CPppChap::MakeResponseL(TUint8,const TDesC8&,TPtrC8&,TPtrC8&)
+ @see CPppChap::MakeResponseL(TUint8,const TDesC8&,TPtrC8&,TPtrC8&)
+ @internalComponent
+*/
+ {
+ ASSERT(aChallengeValue.Length() ==
+ KPppMsChap2AuthenticatorChallengeSize);
+
+ TPtr8 peerChallenge(const_cast<TUint8*>(iResponseValue.Ptr()),
+ KPppMsChap2PeerChallengeSize,
+ KPppMsChap2PeerChallengeSize);
+ GeneratePeerChallengeL(peerChallenge);
+
+// The NT username shall be char and not be longer than
+// KPppMsChapMaxNTUserNameLength
+ const CCredentialsConfig* credentials = iPppLcp->GetCredentials();
+ const TDesC& username = credentials->GetUserName();
+ __ASSERT_ALWAYS(username.Length() <=
+ KPppMsChapMaxNTUserNameLength,
+ User::Leave(KErrTooBig));
+
+// The NT password shall be Unicode and not be longer than
+// KPppMsChapMaxNTPasswordLength
+ const TDesC& password = credentials->GetPassword();
+ __ASSERT_ALWAYS(password.Length() <=
+ KPppMsChapMaxNTPasswordLength,
+ User::Leave(KErrTooBig));
+
+#ifdef _UNICODE
+// The MS-CHAP-V2 routines require the username to be represented as
+// 0-to-256-char (RFC 2759), so convert the username.
+ delete iUserName;
+ iUserName = 0;
+ iUserName = HBufC8::NewL(username.Length());
+ iUserName->Des().Copy(username);
+ aResponseName.Set(*iUserName);
+
+ TPtrC16 uniPassword(password);
+#else //! _UNICODE
+ aResponseName.Set(username);
+
+// The MS-CHAP-V2 routines require the password to be represented as
+// 0-to-256-unicode-char (RFC 2759), so convert the password to
+// Unicode.
+ HBufC16& uniPassword = *HBufC16::NewLC(password.Length());
+ uniPassword.Des().Copy(password);
+#endif //! _UNICODE
+
+ TPtr8 ntResponse(const_cast<TUint8*>(iResponseValue.Ptr()) +
+ KPppMsChap2PeerChallengeSize +
+ KPppMsChap2ResponseReservedSize,
+ KPppMsChap2NTResponseSize,
+ KPppMsChap2NTResponseSize);
+
+ GenerateNTResponseL(aChallengeValue,
+ peerChallenge,
+ aResponseName,
+ uniPassword,
+ ntResponse);
+
+ aResponseValue.Set(iResponseValue);
+
+ GenerateAuthenticatorResponseL(uniPassword,
+ ntResponse,
+ peerChallenge,
+ aChallengeValue,
+ aResponseName,
+ iAuthenticatorResponse);
+
+#ifndef _UNICODE
+ CleanupStack::PopAndDestroy(&uniPassword);
+#endif //! _UNICODE
+
+ ASSERT(aResponseValue.Length() == KPppMsChap2ResponseValueSize);
+ ASSERT(aResponseName.Length() >= KPppChapMinNameSize &&
+ aResponseName.Length() <= KPppMsChapMaxNTUserNameLength);
+ }
+
+
+void CPppMsChap2::SuccessL(RMBufPacket& aPacket)
+/**
+ @copydoc CPppChap::SuccessL(RMBufPacket&)
+ @see CPppChap::SuccessL(RMBufPacket&)
+ @internalComponent
+*/
+ {
+ __ASSERT_ALWAYS(aPacket.Length() >= KPppChapCodeFieldSize +
+ KPppChapIdFieldSize +
+ KPppChapLengthFieldSize +
+ KPppMsChap2AuthenticatorResponseSize,
+ User::Leave(KErrUnderflow));
+
+// check the id
+ if (!CheckIdentifier(aPacket))
+ User::Leave(KErrGeneral);
+
+// no more retries
+ TimerCancel();
+
+ // Read the length of the MS-CHAP-V2 Failure packet and compute
+ // the length of the CHAP Message field and go past the CHAP Code
+ // field, the CHAP Identifier field and the CHAP Length field, in
+ // order to read the CHAP Message field.
+
+ TPtrC8 authResponse(aPacket.First()->Ptr() +
+ KPppChapCodeFieldSize +
+ KPppChapIdFieldSize +
+ KPppChapLengthFieldSize,
+ KPppMsChap2AuthenticatorResponseSize);
+
+// TPtrC8 message(ptr + KPppChapCodeFieldSize + KPppChapIdFieldSize + KPppChapLengthFieldSize + KPppMsChap2AuthenticatorResponseSize + 3, BigEndian::Get16(ptr + KPppChapCodeFieldSize + KPppChapIdFieldSize) - KPppChapCodeFieldSize - KPppChapIdFieldSize - KPppChapLengthFieldSize - KPppMsChap2AuthenticatorResponseSize - 3);
+
+ if (authResponse!=iAuthenticatorResponse)
+ DoFail(KErrIfAuthenticationFailure);
+ else
+ DoSucceed();
+ }
+
+
+void CPppMsChap2::FailureL(RMBufPacket& aPacket)
+/**
+ @copydoc CPppChap::FailureL(RMBufPacket&)
+ @see CPppChap::FailureL(RMBufPacket&)
+ @internalComponent
+*/
+ {
+ __ASSERT_ALWAYS(aPacket.Length() >= KPppChapCodeFieldSize +
+ KPppChapIdFieldSize +
+ KPppChapLengthFieldSize +
+ KPppMsChap2AuthenticatorChallengeSize*2
+ + 2,
+ User::Leave(KErrUnderflow));
+
+// check the id
+ if (!CheckIdentifier(aPacket))
+ User::Leave(KErrGeneral);
+
+ TimerCancel();
+
+#ifndef _DEBUG
+
+// The authenticator-controlled authentication retry mechanisms and
+// the password changing mechanisms have not been implemented in this
+// release - this is in accordance with the project requirements.
+// Consequently simply fail.
+
+ DoFail(KErrIfAuthenticationFailure);
+
+#else // _DEBUG
+
+// Read the length of the MS-CHAP-V2 Failure packet and compute the
+// length of the CHAP Message field and go past the CHAP Code field,
+// the CHAP Identifier field and the CHAP Length field, in order to
+// read the CHAP Message field
+ TPtrC8 failureMessage(aPacket.First()->Ptr() +
+ KPppChapCodeFieldSize +
+ KPppChapIdFieldSize +
+ KPppChapLengthFieldSize,
+ aPacket.Length() -
+ KPppChapCodeFieldSize -
+ KPppChapIdFieldSize -
+ KPppChapLengthFieldSize);
+
+ if (failureMessage.Length()==0)
+ {
+ DoFail(KErrIfAuthenticationFailure);
+ return;
+ }
+
+ TUint msChapError;
+ TUint8 isRetryAllowed;
+ TUint8 passwordProtoVersion;
+ TPtrC8 message;
+ TInt sysError=KErrIfAuthenticationFailure;
+
+ ProcessFailureMessageL(failureMessage,
+ msChapError,
+ isRetryAllowed,
+ iChallengeRef,
+ passwordProtoVersion,
+ message);
+
+ sysError=TranslateMsChapError(msChapError);
+
+// The code only handles KPppMsChapAuthenticationFailure, and no other
+// MS-CHAP specific errors. In particular, this code does not handle
+// KPppMsChapErrorPasswordExpired, since the password changing
+// mechanisms have not been implemented in this release - this is in
+// accordance with the project requirements.
+ if (msChapError != KPppMsChapAuthenticationFailure)
+ {
+ DoFail(sysError);
+ return;
+ }
+
+ if (!isRetryAllowed)
+ {
+ DoFail(sysError);
+ return;
+ }
+
+// The authenticator-controlled authentication retry mechanisms and
+// the password changing mechanisms have not been implemented in this
+// release - this is in accordance with the project requirements.
+// Consequently simply fail.
+ DoFail(sysError);
+
+#endif // _DEBUG
+ }
+
+
+inline void CPppMsChap2::ProcessFailureMessageL(
+ const TDesC8& aFailureMessage,
+ TUint& aErrorCode,
+ TUint8& aRetryFlag,
+ TDes8& aAuthChallenge,
+ TUint8& aPasswordProtoVersion,
+ TPtrC8& aMessage)
+/**
+ Processes a MS-CHAP-V2 Failure Message.
+ @param aFailureMessage [in] A MS-CHAP-V2 Failure Message. The
+ Failure Message needs to be in the format specified in RFC 2759:
+ "E=eeeeeeeeee R=r C=cccccccccccccccccccccccccccccccc V=vvvvvvvvvv
+ M=<msg>".
+ @param aErrorCode [out] The MS-CHAP-V2 Failure error code.
+ @param aRetryFlag [out] The retry flag. The flag will be set to
+ "1" if a retry is allowed, and "0" if not. When the authenticator
+ sets this flag to "1" it disables short timeouts, expecting the
+ peer to prompt the user for new credentials and resubmit the
+ response.
+ @param aAuthChallenge [out] The new Authenticator Challenge Value.
+ @param aPasswordProtoVersion [out] The password changing protocol
+ supported by the peer.
+ @param aMessage [out] A failure text message.
+ @internalComponent
+*/
+ {
+ ASSERT(aAuthChallenge.Length() ==
+ KPppMsChap2AuthenticatorChallengeSize);
+
+ TLex8 input(aFailureMessage);
+
+ if (input.Get() != 'E')
+ User::Leave(KErrGeneral);
+
+ if (input.Get() != '=')
+ User::Leave(KErrGeneral);
+
+
+// RFC 2759: ""eeeeeeeeee" is the ASCII representation of a decimal
+// error code (need not be 10 digits) corresponding to one of those
+// listed below, though implementations should deal with codes not on
+// this list gracefully."
+
+
+ TInt ret;
+ if ((ret = input.Val(aErrorCode))!=KErrNone)
+ if (ret!= KErrOverflow)
+ User::Leave(KErrGeneral);
+ else
+// Gracefully handle unusually large, yet valid, MS-CHAP-V2 specific
+// error code values. This code only handles the MS-CHAP-V2 specific
+// error code values specified in RFC 2759.
+ aErrorCode=0;
+
+ input.SkipSpace();
+
+ if (input.Get() != 'R')
+ User::Leave(KErrGeneral);
+
+ if (input.Get() != '=')
+ User::Leave(KErrGeneral);
+
+ if (input.Val(aRetryFlag, EDecimal)!=KErrNone)
+ User::Leave(KErrGeneral);
+
+ input.SkipSpace();
+
+ if (input.Get() != 'C')
+ User::Leave(KErrGeneral);
+
+ if (input.Get() != '=')
+ User::Leave(KErrGeneral);
+
+ TPtrC8 token(input.NextToken());
+// This field is 32 hexadecimal digits representing an ASCII
+// representation of a new challenge value. Each octet is represented
+// in 2 hexadecimal digits.
+ if (token.Length() != KPppMsChap2AuthenticatorChallengeSize*2)
+ User::Leave(KErrGeneral);
+
+ TLex8 lex;
+ TUint8 octet;
+ TUint8* pChallengeOctet =
+ const_cast<TUint8*>(aAuthChallenge.Ptr());
+ TUint8 i = 0;
+ do
+ {
+ lex.Assign(token.Mid(i*2, 2));
+ if (lex.Val(octet, EHex) != KErrNone)
+ User::Leave(KErrGeneral);
+
+ *(pChallengeOctet + i) = octet;
+ }
+ while (++i < KPppMsChap2AuthenticatorChallengeSize);
+
+ input.SkipSpace();
+
+ if (input.Get() != 'V')
+ User::Leave(KErrGeneral);
+
+ if (input.Get() != '=')
+ User::Leave(KErrGeneral);
+
+
+// RFC 2759: "The "vvvvvvvvvv" is the ASCII representation of a
+// decimal version code (need not be 10 digits) indicating the
+// password changing protocol version supported on the server. For
+// MS-CHAP-V2, this value SHOULD always be 3."
+
+
+ if ((ret = input.Val(aPasswordProtoVersion, EDecimal)) !=
+ KErrNone)
+ if (ret != KErrOverflow)
+ User::Leave(KErrGeneral);
+ else
+// Gracefully handle unusually large, yet valid, password changing
+// protocol version values. This code only handles the password
+// changing protocol version values specified in RFC 2759.
+ aPasswordProtoVersion=0;
+
+ input.SkipSpace();
+
+ switch (input.Get())
+ {
+ case 'M':
+ if (input.Get() != '=')
+ User::Leave(KErrGeneral);
+
+ aMessage.Set(input.NextToken());
+ break;
+
+ case 0:
+ break;
+
+ default:
+ User::Leave(KErrGeneral);
+ }
+
+ ASSERT(aAuthChallenge.Length() ==
+ KPppMsChap2AuthenticatorChallengeSize);
+ }
+
+
+TInt CPppMsChap2::TranslateMsChapError(TUint aMsChapError)
+/**
+ Translates a MS-CHAP-V2 error code into a Symbian OS PPP NIF
+ specific error code.
+ @param aMsChapError A MS-CHAP-V2 error code.
+ @return The Symbian OS PPP NIF specific error code corresponding to
+ the MS-CHAP error code.
+ @internalComponent
+*/
+ {
+ return CPppMsChap::TranslateMsChapError(aMsChapError);
+ }
+
+
+inline void CPppMsChap2::RetryPasswordL()
+/**
+ Retries the authentication.
+ @internalComponent
+*/
+ {
+ ++iCurrentId;
+
+ iResponseRetryCount = 0;
+ RespondL();
+ }
+
+
+inline void CPppMsChap2::GeneratePeerChallengeL(TDes8& aChallenge)
+/**
+ Generates a MS-CHAP-V2 Peer Challenge.
+ @param aChallenge [out] A MS-CHAP-V2 Peer Challenge (16 octets).
+ @internalComponent
+*/
+ {
+ TRandom::RandomL(aChallenge);
+ }
+
+inline void CPppMsChap2::GenerateNTResponseL(
+ const TDesC8& aAuthenticatorChallenge,
+ const TDesC8& aPeerChallenge,
+ const TDesC8& aUserName,
+ const TDesC16& aPassword,
+ TDes8& aResponse)
+/**
+ Generates a MS-CHAP-V2 NT-Response.
+ @param aAuthenticatorChallenge [in] The MS-CHAP-V2 authenticator
+ challenge (16 octets).
+ @param aPeerChallenge [in] The MS-CHAP-V2 peer challenge (16
+ octets).
+ @param aUserName [in] The Microsoft Windows NT username (0 to 256
+ char).
+ @param aPassword [in] The Microsoft Windows NT password (0 to 256
+ unicode char).
+ @param aResponse [out] The MS-CHAP-V2 Challenge Response,
+ NT-Response (24 octets).
+ @note This function implements the GenerateNTResponse routine
+ specified in RFC 2759.
+ @internalComponent
+*/
+ {
+ ASSERT(aAuthenticatorChallenge.Length() ==
+ KPppMsChap2AuthenticatorChallengeSize);
+ ASSERT(aPeerChallenge.Length() ==
+ KPppMsChap2PeerChallengeSize);
+ ASSERT(aUserName.Length() <= KPppMsChapMaxNTUserNameLength);
+ ASSERT(aPassword.Length() <= KPppMsChapMaxNTPasswordLength);
+ ASSERT(aResponse.Length() == KPppMsChap2NTResponseSize);
+
+ HBufC8* challengeHashBuf =
+ HBufC8::NewMaxLC(KPppMsChap2ChallengeHashSize);
+ TPtr8 challengeHash(challengeHashBuf->Des());
+ ChallengeHashL(aPeerChallenge,
+ aAuthenticatorChallenge,
+ aUserName,
+ challengeHash);
+
+ HBufC8* paddedPasswordHashBuf =
+ HBufC8::NewLC(KPppMsChap2PaddedHashSize);
+ TPtr8 paddablePasswordHash(paddedPasswordHashBuf->Des());
+
+ paddablePasswordHash.SetLength(KPppMsChap2HashSize);
+ NtPasswordHashL(aPassword, paddablePasswordHash);
+
+ ChallengeResponseL(challengeHash,
+ paddablePasswordHash,
+ aResponse);
+
+ CleanupStack::PopAndDestroy(paddedPasswordHashBuf);
+ CleanupStack::PopAndDestroy(challengeHashBuf);
+
+ ASSERT(aResponse.Length()==KPppMsChap2NTResponseSize);
+ }
+
+
+void CPppMsChap2::ChallengeHashL(const TDesC8& aPeerChallenge,
+ const TDesC8& aAuthenticatorChallenge,
+ const TDesC8& aUserName,
+ TDes8& aChallengeHash)
+/**
+ Computes the hash of the Peer Challenge, Authenticator Challenge
+ and username using SHA-1.
+ @param aPeerChallenge [in] The Peer Challenge (16 octets).
+ @param aAuthenticatorChallenge [in] The Authenticator Challenge (16
+ octets).
+ @param aUserName [in] The Microsoft Windows NT username (0 to 256
+ char).
+ @param aChallengeHash [out] The hash of the peer challenge,
+ authenticator challenge and username, computed using SHA-1 (8
+ octets).
+ @note This function implements the ChallengeHash routine specified
+ in RFC 2759.
+ @internalComponent
+*/
+ {
+ ASSERT(aPeerChallenge.Length() ==
+ KPppMsChap2PeerChallengeSize);
+ ASSERT(aAuthenticatorChallenge.Length() ==
+ KPppMsChap2AuthenticatorChallengeSize);
+ ASSERT(aUserName.Length() <= KPppMsChapMaxNTUserNameLength);
+ ASSERT(aChallengeHash.Length()==KPppMsChap2ChallengeHashSize);
+
+ CSHA1* sha1 = CSHA1::NewL();
+ CleanupStack::PushL(sha1);
+
+// RFC 2759: "Only the user name (as presented by the peer and
+// excluding any prepended domain name)"
+ TPtrC8 userName(aUserName);
+ TInt i = aUserName.Locate('\\');
+ if (i >= 0 && i < userName.Length() - 1)
+ userName.Set(aUserName.Mid(i + 1));
+ else if (i >= userName.Length() - 1)
+ User::Leave(KErrGeneral);
+
+
+ sha1->Update(aPeerChallenge);
+ sha1->Update(aAuthenticatorChallenge);
+
+ aChallengeHash.Copy(sha1->Final(userName).Ptr(),
+ KPppMsChap2ChallengeHashSize);
+
+
+ CleanupStack::PopAndDestroy(sha1);
+
+ ASSERT(aChallengeHash.Length()==KPppMsChap2ChallengeHashSize);
+ }
+
+
+void CPppMsChap2::NtPasswordHashL(const TDesC16& aPassword,
+ TDes8& aPasswordHash)
+/**
+ Computes the hash of the Microsoft Windows NT password using MD4.
+ @param aPassword [in] The Microsoft Windows NT password (0 to 256
+ Unicode char).
+ @param aPasswordHash [out] The MD4 hash of the Microsoft Windows NT
+ password (16 octets).
+ @note This function implements the NtPasswordHash routine specified
+ in RFC 2759.
+ @internalComponent
+*/
+ {
+ ASSERT(aPassword.Length() <= KPppMsChapMaxNTPasswordLength);
+ ASSERT(aPasswordHash.Length()==KPppMsChap2HashSize);
+
+// The following code does not use the Symbian Security subsystem
+// components, because they do not provide a MD4 implementation yet.
+// This is a provisional solution until the Symbian Security subsystem
+// components will provide a MD4 implementation.
+
+ CMd4* md4 = CMd4::NewL();
+ CleanupStack::PushL(md4);
+
+
+// The following code assumes that the data in TDesC16 descriptors is
+// stored in little endian byte order, which is currently a
+// characteristic of Symbian OS, so the reinterpret_cast is assumed to
+// be safe here.
+ md4->Input(TPtrC8(reinterpret_cast<const TUint8*>(
+ aPassword.Ptr()),
+ aPassword.Length()*2));
+ md4->Output(aPasswordHash);
+
+ CleanupStack::PopAndDestroy(md4);
+
+ ASSERT(aPasswordHash.Length()==KPppMsChap2HashSize);
+ }
+
+
+inline void CPppMsChap2::ChallengeResponseL(
+ const TDesC8& aChallengeHash,
+ TDes8& aPaddablePasswordHash,
+ TDes8& aResponse)
+/**
+ Computes the challenge response using DES.
+ @param aChallengeHash [in] The hash of the peer challenge,
+ authenticator challenge and username, computed using SHA-1 (8
+ octets).
+ @param aPaddablePasswordHash [in/out] The hash of the password in a
+ paddable buffer (16 octets in buffer with at least 21 octets
+ maximum length).
+ @param aResponse [out] The challenge response (24 octets).
+ @note This function implements the ChallengeResponse routine
+ specified in RFC 2759.
+ @internalComponent
+*/
+ {
+ CPppMsChap::ChallengeResponseL(aChallengeHash,
+ aPaddablePasswordHash,
+ aResponse);
+ }
+
+
+void CPppMsChap2::DesEncryptL(const TDesC8& aClear,
+ const TDesC8& aKey,
+ TDes8& aCypher)
+/**
+ Encrypts a plaintext into a ciphertext using the DES encryption
+ algorithm in ECB mode.
+ @param aClear [in] A plaintext (8 octets).
+ @param aKey [in] A key (7 octets).
+ @param aCypher [out] The ciphertext (8 octets).
+ @note This function implements the DesEncrypt routine specified in
+ RFC 2759.
+ @internalComponent
+*/
+ {
+ CPppMsChap::DesEncryptL(aClear, aKey, aCypher);
+ }
+
+
+inline void CPppMsChap2::HashNtPasswordHashL(
+ const TDesC8& aPasswordHash,
+ TDes8& aPasswordHashHash)
+/**
+ Computes the hash of the hash of the Microsoft Windows NT password
+ using MD4.
+ @param aPasswordHash [in] The hash of the Microsoft Windows NT
+ password (16 octets).
+ @param aPasswordHashHash [out] The hash of the hash of the
+ Microsoft Windows NT password, computed using MD4 (16 octets).
+ @note This function implements the HashNtPasswordHash routine
+ specified in RFC 2759.
+ @internalComponent
+*/
+ {
+ ASSERT(aPasswordHash.Length()==KPppMsChap2HashSize);
+ ASSERT(aPasswordHashHash.Length()==KPppMsChap2HashSize);
+
+ CMd4* md4 = CMd4::NewL();
+ CleanupStack::PushL(md4);
+
+// aPasswordHashHash.Copy(md4.Final(aPasswordHash));
+
+ md4->Input(aPasswordHash);
+ md4->Output(aPasswordHashHash);
+
+ CleanupStack::PopAndDestroy(md4);
+
+ ASSERT(aPasswordHashHash.Length()==KPppMsChap2HashSize);
+ }
+
+
+inline void CPppMsChap2::GenerateAuthenticatorResponseL(
+ const TDesC16& aPassword,
+ const TDesC8& aNTResponse,
+ const TDesC8& aPeerChallenge,
+ const TDesC8& aAuthenticatorChallenge,
+ const TDesC8& aUserName,
+ TDes8& aAuthenticatorResponse)
+/**
+ Generates the expected MS-CHAP-V2 Authenticator Response Value.
+ @param aPassword [in] The Microsoft Windows NT password (0 to 256
+ Unicode char).
+ @param aNTResponse [in] The MS-CHAP-V2 NT-Response (24 octets).
+ @param aPeerChallenge [in] The Peer Challenge (16 octets).
+ @param aAuthenticatorChallenge [in] The Authenticator Challenge (16
+ octets).
+ @param aUserName [in] The Microsoft Windows NT username (0 to 256
+ char).
+ @param aAuthenticatorResponse [out] The expected MS-CHAP-V2
+ Authenticator Response Value encoded in the format
+ "S=<auth_string>" as specified in RFC 2759 (42 octets).
+ @note This function implements the GenerateAuthenticatorResponse
+ routine specified in RFC 2759.
+ @internalComponent
+*/
+ {
+ ASSERT(aPassword.Length()<=KPppMsChapMaxNTPasswordLength);
+ ASSERT(aNTResponse.Length() == KPppMsChap2NTResponseSize);
+ ASSERT(aPeerChallenge.Length() ==
+ KPppMsChap2PeerChallengeSize);
+ ASSERT(aAuthenticatorChallenge.Length() ==
+ KPppMsChap2AuthenticatorChallengeSize);
+ ASSERT(aUserName.Length()<=KPppMsChapMaxNTUserNameLength);
+ ASSERT(aAuthenticatorResponse.Length() ==
+ KPppMsChap2AuthenticatorResponseSize);
+
+ HBufC8* passwordHashBuf=HBufC8::NewMaxLC(KPppMsChap2HashSize);
+ TPtr8 passwordHash(passwordHashBuf->Des());
+
+ NtPasswordHashL(aPassword, passwordHash);
+
+ HashNtPasswordHashL(passwordHash, passwordHash);
+
+ CSHA1* sha1 = CSHA1::NewL();
+ CleanupStack::PushL(sha1);
+
+// A magic string literal specified in RFC 2759 used in reponse
+// generation by the GenerateAuthenticatorResponse routine for SHA-1
+// encryption.
+ _LIT8(KMagic1, "Magic server to client signing constant");
+
+
+ sha1->Update(passwordHash);
+ sha1->Update(aNTResponse);
+ TPtrC8 hash(sha1->Final(KMagic1));
+
+
+ HBufC8* challengeHashBuf =
+ HBufC8::NewMaxLC(KPppMsChap2ChallengeHashSize);
+ TPtr8 challengeHash(challengeHashBuf->Des());
+ ChallengeHashL(aPeerChallenge,
+ aAuthenticatorChallenge,
+ aUserName,
+ challengeHash);
+
+// Another magic string literal specified in RFC 2759 used in reponse
+// generation by the GenerateAuthenticatorResponse routine for SHA-1
+// encryption.
+ _LIT8(KMagic2, "Pad to make it do more than one iteration");
+
+
+ sha1->Update(hash);
+ sha1->Update(challengeHash);
+ const TUint8* pHash = sha1->Final(KMagic2).Ptr();
+
+
+ _LIT8(KFormat,
+ "S=%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X"
+ "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X");
+ aAuthenticatorResponse.Format(KFormat,
+ *pHash,
+ *(pHash + 1),
+ *(pHash + 2),
+ *(pHash + 3),
+ *(pHash + 4),
+ *(pHash + 5),
+ *(pHash + 6),
+ *(pHash + 7),
+ *(pHash + 8),
+ *(pHash + 9),
+ *(pHash + 10),
+ *(pHash + 11),
+ *(pHash + 12),
+ *(pHash + 13),
+ *(pHash + 14),
+ *(pHash + 15),
+ *(pHash + 16),
+ *(pHash + 17),
+ *(pHash + 18),
+ *(pHash + 19));
+
+ CleanupStack::PopAndDestroy(challengeHashBuf);
+
+ CleanupStack::PopAndDestroy(sha1);
+ CleanupStack::PopAndDestroy(passwordHashBuf);
+
+ ASSERT(aAuthenticatorResponse.Length() ==
+ KPppMsChap2AuthenticatorResponseSize);
+ }