/*
* Copyright (c) 2002-2005 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:        
*
*/








// INCLUDE FILES
#include <SenXmlUtils.h>

#include "senidwsfcrammd5saslmechanism.h"
#include "msensaslmessage.h"

#include <flogger.h>

namespace
    {
    _LIT8(KCrammd5, "CRAM-MD5");
    }

// Create instance of concrete ECOM interface implementation
CSenIdWsfCrammd5SaslMechanism* CSenIdWsfCrammd5SaslMechanism::NewL(
                                    MSenCoreServiceManager& aServiceManager)
    {
    CSenIdWsfCrammd5SaslMechanism* pNew =
                        CSenIdWsfCrammd5SaslMechanism::NewLC(aServiceManager);
    CleanupStack::Pop();
    return pNew;
    }

CSenIdWsfCrammd5SaslMechanism*
            CSenIdWsfCrammd5SaslMechanism::NewLC(
                                    MSenCoreServiceManager& aServiceManager)
    {
    CSenIdWsfCrammd5SaslMechanism* pNew =
                new (ELeave) CSenIdWsfCrammd5SaslMechanism(aServiceManager);
    CleanupStack::PushL(pNew);
    return pNew;
    }

CSenIdWsfCrammd5SaslMechanism::CSenIdWsfCrammd5SaslMechanism(
                                    MSenCoreServiceManager& aServiceManager)
:CSenIdWsfPlainSaslMechanism(aServiceManager)
    {
    }

CSenIdWsfCrammd5SaslMechanism::~CSenIdWsfCrammd5SaslMechanism()
    {
    }

const TDesC8& CSenIdWsfCrammd5SaslMechanism::Name()
    {
    return KCrammd5();
    }

TInt CSenIdWsfCrammd5SaslMechanism::HandleResponseL(
                                                MSenSaslMessage& aResponse,
                                                MSenSaslMessage& aNewRequest
    )
    {
    const TInt KPasswordMinLength = 64;

    TInt retVal = KErrNone;

    TPtrC8 authzId = ipAccount->AuthzID();
    TPtrC8 authnId = ipAccount->AdvisoryAuthnID();
    if (authnId == KNullDesC8)
        {
        authnId.Set(authzId);
        }

    // Get challenge
    TPtrC8 theChallengeDataBase64 = aResponse.Data();

    HBufC8* pChallengeData = // push pChallengeData;
        iServiceManager.DecodeFromBase64LC(theChallengeDataBase64);
    if (pChallengeData->Length() == 0)
        {
        iServiceManager.Log()->Write(_L(
        "ERROR: CSenIdWsfCrammd5SaslMechanism::HandleResponseL \
        challenge date length = 0"));
        User::Leave(KErrArgument);
        }

    // Create MD5 hash generator
    CMD5* pMd5Gen = CMD5::NewL();
    CleanupStack::PushL(pMd5Gen);

    // The password is the shared secret
    // transform password
    TPtrC8 password(KNullDesC8);
    if(ipPassword)
        {
        password.Set(ipPassword->Des());
        }

    HBufC8* pPassword8 = TransformL(password);
    CleanupStack::PushL(pPassword8);

    if (pPassword8->Length() <= KPasswordMinLength)
        {
        // Pad with 0 bytes
        pPassword8 = pPassword8->ReAllocL(KPasswordMinLength);
        CleanupStack::Pop();    // Replace pwd on cleanup stack,
                                // might have changed(!)
        CleanupStack::PushL(pPassword8);
        pPassword8->Des().AppendFill(TChar(0),
                                    KPasswordMinLength - pPassword8->Length());
        }
    else
        {
        // Password is longer than 64 bytes, replace pwd with MD5 hash
        HBufC8* pPasswordHash = pMd5Gen->Hash(*pPassword8).AllocL();
        CleanupStack::PopAndDestroy(); // pPassword8;
        pPassword8 = pPasswordHash;
        CleanupStack::PushL(pPassword8);
        }

    // Create HMAC generator
    CHMAC* pHmacGen = CHMAC::NewL(*pPassword8, pMd5Gen); // takes ownership of
                                                         // pMd5Gen AND makes
                                                         // use of pPassword8
    CleanupStack::PopAndDestroy(); // pPassword8
    CleanupStack::Pop(); // pMd5Gen


    CleanupStack::PushL(pHmacGen); // push

    // Calculate hash
    TPtrC8 ptrHash = pHmacGen->Hash(*pChallengeData);
    if (ptrHash.Length() > 0)
        {
        _LIT8(KSpace," ");
        HBufC8 *pResponseData8 = HBufC8::NewLC(
            authnId.Length() + 1 + ptrHash.Length() * 2); // push pData8
        TPtr8 ptrResponseData8 = pResponseData8->Des();

        ptrResponseData8.Append(authnId);
        ptrResponseData8.Append(KSpace);//CodeScannerWarning

        // ptrHash needs to be converted to a lowercase hex value
        for (TInt i = 0; i < ptrHash.Length(); i++)
            {
            ptrResponseData8.AppendNumFixedWidth(ptrHash[i], EHex, 2);
            }

        retVal = aNewRequest.ConstructRequestFromL(KCrammd5, ptrResponseData8);

        CleanupStack::PopAndDestroy();  // pResponseData8;
        }

    CleanupStack::PopAndDestroy(); // pHmacGen


    CleanupStack::PopAndDestroy(); // pChallengeData;
    return retVal;
    }

// End of File
