/*
                                  NETWOX
                             Network toolbox
                Copyright(c) 1999-2005 Laurent Constantin
                                  -----

  Main server    : http://www.laurentconstantin.com/
  Backup servers : http://go.to/laurentconstantin/
                   http://laurentconstantin.est-la.com/
                   http://laurentconstantin.free.fr/
                   http://membres.lycos.fr/lauconstantin/
  [my current email address is on the web servers]

                                  -----
  This file is part of Netwox.

  Netwox is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  version 2 as published by the Free Software Foundation.

  Netwox is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  General Public License for more details (http://www.gnu.org/).

------------------------------------------------------------------------
*/

/*-------------------------------------------------------------*/
#include "../netwox.h"

/*-------------------------------------------------------------*/
netwib_err netwox_hmacmd_keys_init(netwox_mdversion mdversion,
                                   netwib_constbuf *pkey,
                                   netwox_hmacmd_keys *pkeys)
{
  netwib_byte keyblockarray[NETWOX_HMACMD_B];
  netwib_data data, data2;
  netwib_uint32 datasize;

  pkeys->mdversion = mdversion;

  datasize = netwib__buf_ref_data_size(pkey);
  if (datasize <= NETWOX_HMACMD_B) {
    netwib_c_memcpy(keyblockarray, netwib__buf_ref_data_ptr(pkey), datasize);
    netwib_c_memset(keyblockarray+datasize, 0, NETWOX_HMACMD_B-datasize);
  } else {
    netwib_buf keyblock;
    netwib_er(netwib_buf_init_ext_arrayempty(keyblockarray, NETWOX_HMACMD_B,
                                             &keyblock));
    netwib_er(netwox_md_compute(mdversion, pkey, &keyblock));
  }

  data = pkeys->ki;
  data2 = keyblockarray;
  datasize = NETWOX_HMACMD_B;
  while(datasize--) {
    *data++ = (netwib_byte)((*data2++) ^ 0x36);
  }

  data = pkeys->ko;
  data2 = keyblockarray;
  datasize = NETWOX_HMACMD_B;
  while(datasize--) {
    *data++ = (netwib_byte)((*data2++) ^ 0x5C);
  }

  return(NETWIB_ERR_OK);
}

/*-------------------------------------------------------------*/
netwib_err netwox_hmacmd_compute(netwox_hmacmd_keys *pkeys,
                                 netwib_constbuf *pbuf,
                                 netwib_buf *phmacmd)
{
  netwib_byte array[NETWOX_HMACMD_HASH_LEN];
  netwib_buf buf, key;
  netwox_md_context ctx;

  netwib_er(netwox_md_init(pkeys->mdversion, &ctx));
  netwib_er(netwib_buf_init_ext_arrayfilled(pkeys->ki, NETWOX_HMACMD_B, &key));
  netwib_er(netwox_md_update(&ctx, &key));
  netwib_er(netwox_md_update(&ctx, pbuf));
  netwib_er(netwib_buf_init_ext_arrayempty(array, sizeof(array), &buf));
  netwib_er(netwox_md_final(&ctx, &buf));

  netwib_er(netwox_md_init(pkeys->mdversion, &ctx));
  netwib_er(netwib_buf_init_ext_arrayfilled(pkeys->ko, NETWOX_HMACMD_B, &key));
  netwib_er(netwox_md_update(&ctx, &key));
  netwib_er(netwox_md_update(&ctx, &buf));
  netwib_er(netwox_md_final(&ctx, phmacmd));

  return(NETWIB_ERR_OK);
}

/*-------------------------------------------------------------*/
static netwib_err netwox_priv_hmacmd_test(netwox_mdversion mdversion,
                                          netwib_conststring mixedkey,
                                          netwib_conststring mixeddata,
                                          netwib_conststring hexawanted)
{
  netwib_buf key, data, md;
  netwox_hmacmd_keys keys;

  netwib_er(netwib_buf_init_mallocdefault(&key));
  netwib_er(netwox_buf_append_strmixed(mixedkey, &key));
  netwib_er(netwox_hmacmd_keys_init(mdversion, &key, &keys));

  netwib_er(netwib_buf_init_mallocdefault(&data));
  netwib_er(netwox_buf_append_strmixed(mixeddata, &data));

  netwib_er(netwib_buf_init_mallocdefault(&md));
  netwib_er(netwox_hmacmd_compute(&keys, &data, &md));
  netwib_er(netwox_buf_check_strmixed(&md, hexawanted));

  netwib_er(netwib_buf_close(&md));
  netwib_er(netwib_buf_close(&data));
  netwib_er(netwib_buf_close(&key));

  return(NETWIB_ERR_OK);
}
#define netwox_priv_hmacmd4_test(key,str,strwanted) netwox_priv_hmacmd_test(NETWOX_MDVERSION_4,key,str,strwanted)
#define netwox_priv_hmacmd5_test(key,str,strwanted) netwox_priv_hmacmd_test(NETWOX_MDVERSION_5,key,str,strwanted)
netwib_err netwox_hmacmd_test(netwox_mdversion mdversion)
{
  if (mdversion == NETWOX_MDVERSION_4) {
    netwib_er(netwox_priv_hmacmd4_test("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "'Hi There'", "90a79458f58f437e21f169cdba283da6"));
    netwib_er(netwox_priv_hmacmd4_test("'Jefe'", "'what do ya want for nothing?'", "be192c588a8e914d8a59b474a828128f"));
    netwib_er(netwox_priv_hmacmd4_test("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "75e5fb6e71ca6dcdd9fca269a9a3cd9c"));
  } else if (mdversion == NETWOX_MDVERSION_5) {
    /* rfc test suite */
    netwib_er(netwox_priv_hmacmd5_test("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "'Hi There'", "9294727a3638bb1c13f48ef8158bfc9d"));
    netwib_er(netwox_priv_hmacmd5_test("'Jefe'", "'what do ya want for nothing?'", "750c783e6ab0b503eaa86e310a5db738"));
    netwib_er(netwox_priv_hmacmd5_test("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "56be34521d144c88dbb8c733f0e8b3f6"));
  } else {
    return(NETWOX_ERR_INTERNALERROR);
  }

  return(NETWIB_ERR_OK);
}
