/*

  silchmac.h

  Author: Pekka Riikonen <priikone@silcnet.org>

  Copyright (C) 1999 - 2006 Pekka Riikonen

  The contents of this file are subject to one of the Licenses specified 
  in the COPYING file;  You may not use this file except in compliance 
  with the License.

  The software distributed under the License is distributed on an "AS IS"
  basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
  KIND, either expressed or implied.  See the COPYING file for more
  information.

*/

#ifndef SILCHMAC_H
#define SILCHMAC_H

/****h* silccrypt/SILC HMAC Interface
 *
 * DESCRIPTION
 *
 *    This is the interface for HMAC, or the keyed hash values, that are
 *    used for packet and message authentication.  These routines uses
 *    already implemented hash functions from the SilcHashAPI. These
 *    routines were created according to RFC 2104.
 *
 ***/

/****s* silccrypt/SilcHMACAPI/SilcHmac
 *
 * NAME
 *
 *    typedef struct SilcHmacStruct *SilcHmac;
 *
 * DESCRIPTION
 *
 *    This context is the actual HMAC context and is allocated
 *    by silc_hmac_alloc and given as argument usually to all
 *    silc_hmac_* functions.  It is freed by the silc_hmac_free
 *    function.
 *
 ***/
typedef struct SilcHmacStruct *SilcHmac;

/****s* silccrypt/SilcHMACAPI/SilcHmacObject
 *
 * NAME
 *
 *    typedef struct { ... } SilcHmacObject;
 *
 * DESCRIPTION
 *
 *    This structure represents one HMAC.  The HMAC's name and the
 *    MAC length is defined in the structure.  This structure is
 *    then given as argument to the silc_hmac_register.  That function
 *    is used to register all HMACs into SILC.  They can be then
 *    allocated by the name found in this structure by calling the
 *    silc_hmac_alloc.
 *
 ***/
typedef struct {
  char *name;
  SilcUInt32 len;
} SilcHmacObject;

/* Marks for all hmacs. This can be used in silc_hmac_unregister
   to unregister all hmacs at once. */
#define SILC_ALL_HMACS ((SilcHmacObject *)1)

/* Default hmacs for silc_hmac_register_default(). */
extern DLLAPI const SilcHmacObject silc_default_hmacs[];

/* Default HMAC in the SILC protocol */
#define SILC_DEFAULT_HMAC "hmac-sha1-96"

/* Prototypes */

/****f* silccrypt/SilcHMACAPI/silc_hmac_register
 *
 * SYNOPSIS
 *
 *    SilcBool silc_hmac_register(const SilcHmacObject *hmac);
 *
 * DESCRIPTION
 *
 *    Registers a new HMAC into the SILC. This function is used at the
 *    initialization of the SILC.  All registered HMACs should be
 *    unregistered with silc_hmac_unregister.  The `hmac' includes the
 *    name of the HMAC and the length of the MAC.  Usually this
 *    function is not called directly.  Instead, application can call
 *    the silc_hmac_register_default to register all default HMACs
 *    that are builtin the sources.  Returns FALSE on error.
 *
 ***/
SilcBool silc_hmac_register(const SilcHmacObject *hmac);

/****f* silccrypt/SilcHMACAPI/silc_hmac_unregister
 *
 * SYNOPSIS
 *
 *    SilcBool silc_hmac_unregister(SilcHmacObject *hmac);
 *
 * DESCRIPTION
 *
 *    Unregister a HMAC from SILC by the HMAC structure `hmac'.  This
 *    should be called for all registered HMAC's.  Returns FALSE on
 *    error.
 *
 ***/
SilcBool silc_hmac_unregister(SilcHmacObject *hmac);

/****f* silccrypt/SilcHMACAPI/silc_hmac_register_default
 *
 * SYNOPSIS
 *
 *    SilcBool silc_hmac_register_default(void);
 *
 * DESCRIPTION
 *
 *    Registers all default HMACs into the SILC.  These are the HMACs
 *    that are builtin in the sources.  See the list of default HMACs
 *    in the silchmac.c source file.  The application may use this
 *    to register default HMACs if specific HMAC in any specific order
 *    is not wanted (application's configuration usually may decide
 *    the order of the registration, in which case this should not be
 *    used).
 *
 ***/
SilcBool silc_hmac_register_default(void);

/****f* silccrypt/SilcHMACAPI/silc_hmac_unregister_all
 *
 * SYNOPSIS
 *
 *    SilcBool silc_hmac_unregister_all(void);
 *
 * DESCRIPTION
 *
 *    Unregisters all registered HMACs.
 *
 ***/
SilcBool silc_hmac_unregister_all(void);

/****f* silccrypt/SilcHMACAPI/silc_hmac_alloc
 *
 * SYNOPSIS
 *
 *    SilcBool silc_hmac_alloc(const char *name, SilcHash hash,
 *                         SilcHmac *new_hmac);
 *
 * DESCRIPTION
 *
 *    Allocates a new SilcHmac object of name of `name'.  The `hash' may
 *    be provided as argument.  If provided it is used as the hash function
 *    of the HMAC.  If it is NULL then the hash function is allocated and
 *    the name of the hash algorithm is derived from the `name'.  Returns
 *    FALSE if such HMAC does not exist.
 *
 ***/
SilcBool silc_hmac_alloc(const char *name, SilcHash hash, SilcHmac *new_hmac);

/****f* silccrypt/SilcHMACAPI/silc_hmac_free
 *
 * SYNOPSIS
 *
 *    void silc_hmac_free(SilcHmac hmac);
 *
 * DESCRIPTION
 *
 *    Frees the allocated HMAC context.  The key that may have been set
 *    with the silc_hmac_set_key is also destroyed.
 *
 ***/
void silc_hmac_free(SilcHmac hmac);

/****f* silccrypt/SilcHMACAPI/silc_hmac_is_supported
 *
 * SYNOPSIS
 *
 *    SilcBool silc_hmac_is_supported(const char *name);
 *
 * DESCRIPTION
 *
 *    Returns TRUE if the HMAC indicated by the `name' exists.
 *
 ***/
SilcBool silc_hmac_is_supported(const char *name);

/****f* silccrypt/SilcHMACAPI/silc_hmac_get_supported
 *
 * SYNOPSIS
 *
 *    char *silc_hmac_get_supported(void);
 *
 * DESCRIPTION
 *
 *    Returns comma (`,') separated list of registered HMACs.  This is
 *    used for example when sending supported HMAC list during the SILC
 *    Key Exchange protocol (SKE).  The caller must free the returned
 *    pointer.
 *
 ***/
char *silc_hmac_get_supported(void);

/****f* silccrypt/SilcHMACAPI/silc_hmac_len
 *
 * SYNOPSIS
 *
 *    SilcUInt32 silc_hmac_len(SilcHmac hmac);
 *
 * DESCRIPTION
 *
 *    Returns the length of the MAC that the HMAC will produce.
 *
 ***/
SilcUInt32 silc_hmac_len(SilcHmac hmac);

/****f* silccrypt/SilcHMACAPI/silc_hmac_get_hash
 *
 * SYNOPSIS
 *
 *    SilcHash silc_hmac_get_hash(SilcHmac hmac);
 *
 * DESCRIPTION
 *
 *    Returns the SilcHash context that has been associated with the
 *    HMAC context.  The caller must not free the returned context.
 *
 ***/
SilcHash silc_hmac_get_hash(SilcHmac hmac);

/****f* silccrypt/SilcHMACAPI/silc_hmac_get_name
 *
 * SYNOPSIS
 *
 *    const char *silc_hmac_get_name(SilcHmac hmac);
 *
 * DESCRIPTION
 *
 *    Returns the name of the HMAC context.
 *
 ***/
const char *silc_hmac_get_name(SilcHmac hmac);

/****f* silccrypt/SilcHMACAPI/silc_hmac_set_key
 *
 * SYNOPSIS
 *
 *    void silc_hmac_set_key(SilcHmac hmac, const unsigned char *key,
 *                           SilcUInt32 key_len);
 *
 * DESCRIPTION
 *
 *    Sets the key to be used in the HMAC operation.  This must be set
 *    before calling silc_hmac_make or silc_hmac_final functions.  If
 *    you do not want to set the key you can still produce a MAC by
 *    calling the silc_hmac_make_with_key where you give the key as
 *    argument.  Usually application still wants to set the key.
 *
 ***/
void silc_hmac_set_key(SilcHmac hmac, const unsigned char *key,
		       SilcUInt32 key_len);

/****f* silccrypt/SilcHMACAPI/silc_hmac_get_key
 *
 * SYNOPSIS
 *
 *    const unsigned char *
 *    silc_hmac_get_key(SilcHmac hmac, SilcUInt32 *key_len);
 *
 * DESCRIPTION
 *
 *    Returns the key data from the `hmac' set with silc_hamc_set_key.
 *    The caller must not free the returned pointer.
 *
 ***/
const unsigned char *silc_hmac_get_key(SilcHmac hmac, SilcUInt32 *key_len);

/****f* silccrypt/SilcHMACAPI/silc_hmac_make
 *
 * SYNOPSIS
 *
 *    void silc_hmac_make(SilcHmac hmac, unsigned char *data,
 *                        SilcUInt32 data_len, unsigned char *return_hash,
 *                        SilcUInt32 *return_len);
 *
 * DESCRIPTION
 *
 *    Computes a MAC from a data buffer indicated by the `data' of the
 *    length of `data_len'.  The returned MAC is copied into the
 *    `return_hash' pointer which must be at least the size of the
 *    value silc_hmac_len returns.  The returned length is still
 *    returned to `return_len'.
 *
 ***/
void silc_hmac_make(SilcHmac hmac, unsigned char *data,
		    SilcUInt32 data_len, unsigned char *return_hash,
		    SilcUInt32 *return_len);

/****f* silccrypt/SilcHMACAPI/silc_hmac_make_with_key
 *
 * SYNOPSIS
 *
 *    void silc_hmac_make_with_key(SilcHmac hmac, unsigned char *data,
 *                                 SilcUInt32 data_len,
 *                                 unsigned char *key, SilcUInt32 key_len,
 *                                 unsigned char *return_hash,
 *                                 SilcUInt32 *return_len);
 *
 * DESCRIPTION
 *
 *    Same as the silc_hmac_make but takes the key for the HMAC as
 *    argument.  If this is used the key that may have been set by calling
 *    silc_hmac_set_key is ignored.
 *
 ***/
void silc_hmac_make_with_key(SilcHmac hmac, unsigned char *data,
			     SilcUInt32 data_len,
			     unsigned char *key, SilcUInt32 key_len,
			     unsigned char *return_hash,
			     SilcUInt32 *return_len);

/****f* silccrypt/SilcHMACAPI/silc_hmac_make_truncated
 *
 * SYNOPSIS
 *
 *    void silc_hmac_make_truncated(SilcHmac hmac,
 *                                  unsigned char *data,
 *                                  SilcUInt32 data_len,
 *                                  SilcUInt32 truncated_len,
 *                                  unsigned char *return_hash);
 *
 * DESCRIPTION
 *
 *    Same as the silc_hmac_make except that the returned MAC is
 *    truncated to the length indicated by the `truncated_len'.  Some
 *    special applications may need this function.  The `return_hash'
 *    must be at least the size of `truncated_len'.
 *
 * NOTES
 *
 *    For security reasons, one should not truncate to less than half
 *    of the length of the true MAC lenght.  However, since this routine
 *    may be used to non-critical applications this allows these dangerous
 *    truncations.
 *
 ***/
void silc_hmac_make_truncated(SilcHmac hmac,
			      unsigned char *data,
			      SilcUInt32 data_len,
			      SilcUInt32 truncated_len,
			      unsigned char *return_hash);

/****f* silccrypt/SilcHMACAPI/silc_hmac_init
 *
 * SYNOPSIS
 *
 *    void silc_hmac_init(SilcHmac hmac);
 *
 * DESCRIPTION
 *
 *    Sometimes calling the silc_hmac_make might not be the most
 *    optimal case of doing MACs.  If you have a lot of different data
 *    that you need to put together for computing a MAC you may either
 *    put them into a buffer and compute the MAC from the buffer by
 *    calling the silc_hmac_make, or you can use the silc_hmac_init,
 *    silc_hmac_update and silc_hmac_final to do the MAC.  This function
 *    prepares the allocated HMAC context for this kind of MAC
 *    computation.  The caller must have been called the function
 *    silc_hmac_set_key before calling this function.  To add the
 *    data to be used in the MAC computation call the silc_hmac_update
 *    function.
 *
 ***/
void silc_hmac_init(SilcHmac hmac);

/****f* silccrypt/SilcHMACAPI/silc_hmac_init_with_key
 *
 * SYNOPSIS
 *
 *    void silc_hmac_init_with_key(SilcHmac hmac, const unsigned char *key,
 *                                 SilcUInt32 key_len);
 *
 * DESCRIPTION
 *
 *    Same as silc_hmac_init but initializes with specific key.  The
 *    key that may have been set with silc_hmac_set_key is ignored.
 *
 ***/
void silc_hmac_init_with_key(SilcHmac hmac, const unsigned char *key,
			     SilcUInt32 key_len);

/****f* silccrypt/SilcHMACAPI/silc_hmac_update
 *
 * SYNOPSIS
 *
 *    void silc_hmac_update(SilcHmac hmac, const unsigned char *data,
 *                          SilcUInt32 data_len);
 *
 * DESCRIPTION
 *
 *    This function may be called to add data to be used in the MAC
 *    computation.  This can be called multiple times to add data from
 *    many sources before actually performing the HMAC.  Once you've
 *    added all the data you need you can call the silc_hmac_final to
 *    actually produce the MAC.
 *
 * EXAMPLE
 *
 *    unsigned char mac[20];
 *    SilcUInt32 mac_len;
 *
 *    silc_hmac_init(hmac);
 *    silc_hmac_update(hmac, data, data_len);
 *    silc_hmac_update(hmac, more_data, more_data_len);
 *    silc_hmac_final(hmac, mac, &mac_len);
 *
 ***/
void silc_hmac_update(SilcHmac hmac, const unsigned char *data,
		      SilcUInt32 data_len);

/****f* silccrypt/SilcHMACAPI/silc_hmac_final
 *
 * SYNOPSIS
 *
 *    void silc_hmac_final(SilcHmac hmac, unsigned char *return_hash,
 *                         SilcUInt32 *return_len);
 *
 * DESCRIPTION
 *
 *    This function is used to produce the final MAC from the data
 *    that has been added to the HMAC context by calling the
 *    silc_hmac_update function.  The MAC is copied in to the
 *    `return_hash' pointer which must be at least the size that
 *    the silc_hmac_len returns.  The length of the MAC is still
 *    returned into `return_len'.
 *
 ***/
void silc_hmac_final(SilcHmac hmac, unsigned char *return_hash,
		     SilcUInt32 *return_len);

#endif
