/*
 * Copyright 2009 Funambol, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id$ */

#include <base/util/utils.h>
#include "hash.h"

using namespace Funambol;

const char * NS_DM_Client::NS_Common::calculateHMAC(const char *username, const char *password, const char *b64nonce, const char *msg, int msg_len)
{
    char base64hmac[64];
    char base64msg[64];
    char base64up[64];

    char digest_hmac[16];
    char digest_msg[16];
    char digest_up[16];

    char cnonce[64];
    char token_up[512];
    char result[128];

//  H =
//  char* calculateMD5(const void* token, int len, char* wdigest)
//        calculateMD5() writes result into preallocated non-null wdigest
//
//  B64 =
//  int b64_encode(char *dest, void *src, int len)
//      return size of encoded msg

    // username:password
    memset(token_up, '\0', sizeof(token_up));
    sprintf(token_up, "%s:%s", username, password);

    // H(username:password)
    memset(digest_up, '\0', sizeof(digest_up));
    calculateMD5(token_up, strlen(token_up), digest_up);

    // B64(H(username:password)
    memset(base64up, '\0', sizeof(base64up));
    int length_b64up = b64_encode(base64up, digest_up, 16);

    // decode b64nonce
    memset(cnonce, '\0', sizeof(cnonce));
    strcpy(cnonce, b64nonce);
    int length_nonce = b64_decode(cnonce, cnonce);

    // H(message body)
    memset(digest_msg, '\0', sizeof(digest_msg));
    calculateMD5(msg, msg_len, digest_msg);
    // B64(H(message body))
    memset(base64msg, '\0', sizeof(base64msg));
    int length_b64msg = b64_encode(base64msg, digest_msg, 16);

    //  sprintf(result, "%s:%s:%s", base64up, cnonce, base64msg);
    // ---> H64(H(username:password)):nonce:B64(H(message body))  <---
    memset(result, '\0', sizeof(result));
    memcpy(result, base64up, length_b64up);
    memcpy(&result[length_b64up], ":", 1);
    memcpy(&result[length_b64up+1], cnonce, length_nonce);
    memcpy(&result[length_b64up+1+length_nonce], ":", 1);
    memcpy(&result[length_b64up+1+length_nonce+1], base64msg, length_b64msg);

    int length_result = length_b64up+1+length_nonce+1+length_b64msg;

    // H(B64(H(username:password)):nonce:B64(H(message body)))
    memset(digest_hmac, '\0', sizeof(digest_hmac));
    calculateMD5(result, length_result, digest_hmac);

    // encode to b64 HMAC result
    memset(base64hmac, '\0', sizeof(base64hmac));
    b64_encode(base64hmac, digest_hmac, 16);

    return Funambol::stringdup(base64hmac);
}

const char * NS_DM_Client::NS_Common::calculateF(const char *a, const char *b, const char *S)
{
    const size_t bufsize = 512;
    if (strlen(a) + strlen(b) + strlen(S) >= bufsize) return NULL;
    
    char buffer[bufsize];
    char digestmd5[16];
    char base64digest[64];

    memset(buffer, '\0', sizeof(buffer));
    strcat(buffer, a);
    strcat(buffer, b);
    strcat(buffer, S);

    memset(digestmd5, '\0', sizeof(digestmd5));
    calculateMD5(buffer, strlen(buffer), digestmd5);

    memset(base64digest, '\0', sizeof(base64digest));
    b64_encode(base64digest, digestmd5, 16);
    
    return Funambol::stringdup(base64digest);
}
