/*

  sshcrypti.h
  
  Author: Mika Kojo <mkojo@ssh.fi>

  Copyright (C) 1996,1997 SSH Communications Security Oy, Espoo, Finland
  All rights reserved.

  Created: Mon Jun 30 14:15:05 1997 [mkojo]

  Definitions for internal use only.

  */

/*
 * $Id: sshcrypti.h,v 1.21.2.1 2000/03/10 18:37:51 sjl Exp $
 * $Log: sshcrypti.h,v $
 * $EndLog$
 */

#ifndef SSHCRYPTI_H
#define SSHCRYPTI_H

#include "sshcrypt.h"

/* Some generally handy definitions, which bear no general meaning outside
   some particular context. */

typedef unsigned int SshCryptoType;
#define SSH_CRYPTO_TYPE_PUBLIC_KEY     1
#define SSH_CRYPTO_TYPE_PRIVATE_KEY    2
#define SSH_CRYPTO_TYPE_PK_GROUP       4 
#define SSH_CRYPTO_TYPE_CIPHER         8
#define SSH_CRYPTO_TYPE_HASH           16
#define SSH_CRYPTO_TYPE_MAC            32
#define SSH_CRYPTO_TYPE_SECRET_SHARING 64

/* The main purpose for these definitions, is to allow easier usage of
   commonly needed methods. That is, we don't need to rewrite all this
   information everywhere.

   Currently hash functions should be defined in their header files, and
   other functions in their code files. However, if need arises this
   can be changed quickly. 
   */

/* Definition structure for hash functions. That is, by using this
   structure crypto library transparently is able to use "any"
   hash functions. */
typedef struct
{
  const char *name;
  const char *asn1_oid;
  unsigned char iso_identifier;
  size_t digest_length;
  size_t input_block_length;
  size_t (*ctxsize)(void);
  void (*reset_context)(void *context);
  void (*update)(void *context, const unsigned char *buf, size_t len);
  void (*final)(void *context, unsigned char *digest);
} SshHashDef;

/* Redundancy generation functions. */

typedef enum
{
  SSH_RGF_OK,
  SSH_RGF_OP_FAILED,
  SSH_RGF_OP_INCOMPLETE
} SshRGFStatus;

#define SSH_RGF_HASH_UPDATE_FUNC(func_name)                                   \
void func_name (SshRGFHash hash, \
                const unsigned char *data, size_t data_len)

#define SSH_RGF_HASH_FREE_FUNC(func_name) \
void func_name (SshRGFHash hash)
/* The RGF hash function free. */
typedef void (*SshRGFHashFree)(SshRGFHash hash);
/* The RGF hash function update. */
typedef void (*SshRGFHashUpdate)(SshRGFHash hash,
                                 const unsigned char *data, size_t data_len);

typedef struct
{
  /* Signature redundancy generation functions need to be able to handle
     arbitrary length message to be signed. That is we need to have a
     similar architecture to hash functions. */

  SshRGFHashFree     rgf_hash_free;
  SshRGFHashUpdate   rgf_hash_update;

  void *context;
} SshRGFHashDef;

#define SSH_RGF_HASH_ALLOCATE_FUNC(func_name) \
SshRGFHash  func_name (const SshRGFHashDef *def, const void *context)

/* The RGF hash function allocation. */
typedef SshRGFHash (*SshRGFHashAllocate)(const SshRGFHashDef *def,
                                         const void *context);

#define SSH_RGF_ENCRYPT_FUNC(func_name)                                       \
SshRGFStatus func_name (const unsigned char *msg,                             \
                        size_t msg_len,                                       \
                        const void *context,                                  \
                        unsigned char *output_msg,                            \
                        size_t output_msg_len)

#define SSH_RGF_DECRYPT_FUNC(func_name)                                       \
SshRGFStatus func_name (const unsigned char *decrypted_msg,                   \
                        size_t          decrypted_msg_len,                    \
                        size_t          max_output_msg_len,                   \
                        const void     *context,                              \
                        unsigned char **output_msg,                           \
                        size_t         *output_msg_len)
     
#define SSH_RGF_SIGN_FUNC(func_name)                                          \
SshRGFStatus func_name (SshRGFHash        hash,                               \
                        unsigned char *output_msg,                            \
                        size_t         output_msg_len)

#define SSH_RGF_VERIFY_FUNC(func_name)                                        \
SshRGFStatus func_name (SshRGFHash   hash,                                    \
                        const unsigned char *decrypted_signature,             \
                        size_t decrypted_signature_len,                       \
                        size_t               max_output_msg_len,              \
                        unsigned char      **output_msg,                      \
                        size_t              *output_msg_len)

#define SSH_RGF_CTX_FREE_FUNC(func_name)                                      \
void func_name (const void *context)
     
/* The RGF encryption and decryption functions. */
typedef SshRGFStatus (*SshRGFEncrypt)(const unsigned char *msg,
                                      size_t         msg_len,
                                      const void    *context,
                                      unsigned char *output_msg,
                                      size_t         output_msg_len);
typedef SshRGFStatus (*SshRGFDecrypt)(const unsigned char *decrypted_msg,
                                      size_t          decrypted_msg_len,
                                      size_t          max_output_msg_len,
                                      const void     *context,
                                      unsigned char **output_msg,
                                      size_t         *output_msg_len);

/* Remark. Some cryptosystems make use only of the SshRGFSign, and
   it should perhaps be written so as to have a suggested output_msg_len
   and it should return a variably allocated output_msg. This would
   make life a bit nicer for e.g. DSS. */

/* The RGF signature and verification functions. */
typedef SshRGFStatus (*SshRGFSign)(SshRGFHash     hash,
                                   unsigned char *output_msg,
                                   size_t         output_msg_len);
typedef SshRGFStatus (*SshRGFVerify)(SshRGFHash   hash,
                                     const unsigned char *decrypted_signature,
                                     size_t decrypted_signature_len,
                                     size_t               max_output_msg_len,
                                     unsigned char      **output_msg,
                                     size_t              *output_msg_len);

typedef void (*SshRGFCtxFree)(const void *context);

/* The RGF hash function context. This structure can be created only by
   the RGF function "rgf_hash_allocate" and can be freed only by
   "rgf_sign" and "rgf_verify". */
struct SshRGFHashRec
{
  /* The hash definition. */
  const SshRGFHashDef *def;
  
  /* The state context. */
  void          *context;

  /* Context space for the caller context. */
  const void    *caller_context;
};

typedef struct
{
  /* The unique name of this RGF for purposes of allocation. It this
     definition is given by caller to the cryptolibrary then this name
     shall not be used and may be set to NULL. */
  const char *name;

  /* Creating the redundancy. */

  /* Encryption and decryption redundancy generation functions. */
  
  SshRGFEncrypt rgf_encrypt;
  SshRGFDecrypt rgf_decrypt;
  
  SshRGFSign    rgf_sign;
  SshRGFVerify  rgf_verify;

  /* The cleaning routine. This function is not necessarily needed if
     the context points to a static data structure. */
  SshRGFCtxFree rgf_ctx_free;

  SshRGFHashAllocate rgf_hash_allocate;
  /* The definition of the "hash" function for the RGF. */
  const SshRGFHashDef *hash_def;
  
  /* The context that is used needed by the routines. */
  const void *context;
} SshRGFDef;

/* Definition structure for cipher functions. */
typedef struct
{
  const char *name;
  /* Block length is 1 for stream ciphers. */
  size_t block_length;
  /* Key length is 0 if supports any length. XXX this is adequate for
     most uses but possibly not suitable always. Might be better to have
     some fixed sized versions of the cipher, rather than variable length
     key version. */
  size_t key_length;
  size_t (*ctxsize)(void);
  /* Basic initialization without explicit key checks. */
  Boolean (*init)(void *context, const unsigned char *key,
                  size_t keylen, Boolean for_encryption);
  /* Initialization with key checks. */
  Boolean (*init_with_check)(void *context, const unsigned char *key,
                             size_t keylen, Boolean for_encryption);
  void (*transform)(void *context, unsigned char *dest,
                    const unsigned char *src, size_t len,
                    unsigned char *iv);
} SshCipherDef;

/* Definition structure for mac functions. */
typedef struct
{
  const char *name;
  size_t digest_length;
  /* Some mac functions need to allocate space of variable length, this
     will indicate it. */
  Boolean allocate_key;
  /* Indicate which hash function to use. This should be generic enough
     for all our needs. But if not, then add more options. */
  const SshHashDef *hash_def;
  size_t (*ctxsize)(const SshHashDef *hash_def);
  void (*init)(void *context, const unsigned char *key, size_t keylen,
               const SshHashDef *hash_def);
  void (*start)(void *context);
  void (*update)(void *context, const unsigned char *buf,
                 size_t len);
  void (*final)(void *context, unsigned char *digest);
  void (*mac_of_buffer)(void *context, const unsigned char *buf,
                        size_t len, unsigned char *digest);
} SshMacDef;

/* SSH public key methods, that are visible through the generic interface,
   are defined here. Motivation for this system is to support
   both discrete logarithm (dl) and integer factorization (if) based
   systems with equal ease.

   We represent a public key cryptosystem with

   key types:

     which stand for the underlying operation. For example, with
     RSA (if-modn) we have a different key type than with
     Diffie-Hellman (dl-modp). Note that key types are the highest
     structure of the public key cryptosystem. Also a public/private/group
     must be of some key type (although not neccessary either of dl-modp or
     if-modn).

     Currently supported key types are:

       if-modn
       dl-modp
       ec-modp
       ec-gf2n

     it is also possible to add e.g.

       lu-modp (Lucas functions over finite field (mod p))

     Key types are defined as large structures containing few function
     pointers. This style is used in all algorithm definitions here.


   schemes:

     which stand for some specific method or algorithm. Such as
     RSA or Diffie-Hellman. Note that there are possibly many variations
     of one algorithm, thus exact naming of an algorithm is a must. And
     obviously all algorithms must have unique name.

     We have divided schemes into various scheme types:

       sign    = signature schemes
       encrypt = encryption schemes
       dh      = diffie-hellman schemes (there seems to be just one)
       ...

     basic criteria is to divide into smallest possible operation, allowing
     us to handle scheme types separately.

     Following algorithms are supported (as an example):

       if-modn{sign{rsa-pkcs1-md5},encrypt{rsa-pkcs1-none}},
       dl-modp{sign{dsa-nist-sha1}}

     Naming format is

       key-type{scheme-type{algorithm-name},...}

     which can be listed in a comma separated list. Functions that handle
     this name tree can be found in namelist.h.

     Schemes are defined as large structures (of many different types)
     containing few function pointers. Currently defined scheme types are

       SshPkSignature
       SshPkEncryption
       SshPkDiffieHellman
       SshPkUnifiedDiffieHellman

     more should be added in future. Clearly adding more scheme types
     is possible, although not very easy. We see no need to add many
     new scheme types although following have been considered

       SshPkOneWayAuthentication
       SshPkTwoWayAuthentication
       SshPkMenezedQuVanstoneProtocol

     (although those might not be the actual names to be used.)


   actions:

     in attempt to make this file atleast partially readable actions have
     been introduced. These contain information of scheme types and
     "actions" allowed to be performed in generation of keys/groups.


   */

/* Following flag is used with actions to indicate that

     - action is to be ignored.
     - action can be used to extract or place information into
       keys structures.
     - indicate that action leads to scheme information.
     - optimization.
     - indicates that action leads to no further information.
     - defines for which type (private/public/group) should this
       action be used.

   */

typedef unsigned int SshPkFlag;
#define SSH_PK_FLAG_IGNORE       0
#define SSH_PK_FLAG_SPECIAL      1
#define SSH_PK_FLAG_SCHEME       2
#define SSH_PK_FLAG_LIST         4
#define SSH_PK_FLAG_KEY_TYPE     8
#define SSH_PK_FLAG_WRAPPED      16
#define SSH_PK_FLAG_PRIVATE_KEY  32
#define SSH_PK_FLAG_PUBLIC_KEY   64
#define SSH_PK_FLAG_PK_GROUP     128

/* Schemes thought to be supported in future. We might want
   to leave something out or implement others. */

typedef enum
{
  /* Invalid scheme */
  SSH_PK_SCHEME_NONE,

  /* Valid schemes */
  SSH_PK_SCHEME_SIGN,
  SSH_PK_SCHEME_ENCRYPT,
  SSH_PK_SCHEME_DH,
  /* SSH_PK_SCHEME_UDH, */
  SSH_PK_SCHEME_OWA,
  SSH_PK_SCHEME_TWA,
  SSH_PK_SCHEME_MQV
} SshPkSchemeFlag;


/* Here we define a simple name, that can be used to indicate that a
   name like
     dl-modp{mymethod}
   is also valid. This is expanded to
     dl-modp{mymethod{plain}}
   and thus you need to name your actual scheme as plain within you
   group of many methods. If you don't want to do that, you just have
   to bear with
     dl-modp{mymethod{myname}}. */
#define SSH_PK_USUAL_NAME "plain"

/* Action definitions.

   Action, as a term, is here used to mean one object in an "action list".
   Action can be used to either just flag some general operation, or to
   start-up a function with arguments from vararg list. Further the
   action can be tied together for "action-list" which can used for
   a more appropriately doing lots of things.

   Current implementation assumes of action lists:

   * includes init and make functions, currently these will be found
     not in action lists but in key type definitions. These are used
     to create the temporary context where inputs will be
     stacked. Then when vararg list is fully traversed, make is
     invoked to generate a context which will be included to private
     keys and pk groups.

   * scheme lists, these are included into action lists to "ease"
     maintaining.

   * special operations, which use those temporary contexts, add
     information to the context gotten from vararg list.

 */

/* The action functions (get/put). These format argument decides how
   the vararg list at ap is processed. The function return a string
   describing what the function did. The return is a string containing
   characters:

     `b' boolean,
     `c' character,
     `s' short, `i' integer, `l' long or
     `p' pointer.

   indicating what kind of data the function did process from the
   argument list. E.g. "bpip" as return value indicates the function
   processed four arguments, in order boolean, pointer, integer,
   pointer. */

/* PUT function reads from ap and fills in the private key type
   specific context (for example prime value can be set using
   this function). */
typedef char * (*SshPkActionPut)(void *context,
                                 va_list ap,
                                 void *input_context,
                                 SshPkFormat format);

/* GET function fills into the varible pointed by va_arg(ap) the value
   specified by format from key specific context. */
typedef char * (*SshPkActionGet)(void *context,
                                 va_list ap,
                                 void **output_context,
                                 SshPkFormat format);

typedef struct
{
  /* Generic information about this action. */

  /* Type of this action. */
  SshPkFormat format;
  /* Name of this action if scheme type. */
  const char *scheme_class;
  /* Flags to define what this action contains and where to use it. */
  SshPkFlag flags;

  /* Scheme information */
  SshPkSchemeFlag scheme_flag;
  /* Regrettably we are forced to use void's here. Thus care should be
     exercised in writing actions. */
  size_t type_size;
  const void *type;

  /* Action functions. Functions to put and take information form
     contexts.

     Main idea is, as explained before, in generating either private key
     or pk group, to generate a temporary context to where action_put
     can add information. This function will not be used elsewhere.

     action_get on the otherhand will work with the actual
     private/public/group contexts. That is it is allowed to take out
     even "secret" information.
     */
  SshPkActionPut action_put;
  SshPkActionGet action_get;

} SshPkAction;

/* Header for all scheme structures. Casts to this will be performed while
   seeking and calling special initialization routines (if present). */

typedef struct
{
  /* Unique name (among same scheme types). */

  const char *name;

  /* Special init function, called if not set to NULL. Main purpose is
     to tell the action_make routine (found in key type definitions)
     that such and such scheme will probably use it. However, not all
     schemes need to have this function, only if parameters that are
     to be generated should be of certain form. Such an example is DSA
     signature method, which needs (to be compatible with the
     standard) parameters of some predefined form.

     However, using this isn't all neccessary and action_make should use
     this information only if no other specific parameter or key
     generation information has been given. Also action_make should
     do something even if no scheme given any specific information (e.g.
     use some default values).  */
  void (*action_scheme)(void *context);
} SshPkGen;

/* Following structure definitions are based on observation that the group
   (or parameters) of the field where public key method works should be
   the basis (or lowest) of public key and private key structures. Although
   here we've done it the easy way and have them all in same.

   But nevertheless, over group we can build cryptosystem having private and
   public keys. Over these keys we can hopefully build schemes, and these
   schemes can be divided in to many classes.

   Here we've chosen to represent also all key exchange
   schemes as "schemes". This might not be always the best way, but some
   times, like with diffie-hellman and some other basic schemes this
   is quite nice.

   The structure here used to represent public key methods is for ease
   of maintaining, which is of very importance, ease of adding new
   schemes, reasonable efficiency. Probably this way we cannot
   represent all methods, but atleast those that are the most
   obvious.
   */

/* Scheme structure definition.

   NOTE! All following structures MUST start with const char *name, this
   is assumed in the following code. */

/* Signature schemes */

typedef struct
{
  /* Names can contain any ascii characters but ",{}" which are used to
     separate them in namelists. All signature algorithm names should
     be unique.
     */

  const char *name;

  void (*action_scheme)(void *context);

  /* RGF to use with this scheme. */

  const SshRGFDef *rgf_def;

  /* Maximum lengths for signature output/input. */
  size_t (*private_key_max_signature_input_len)(const void *private_key);
  size_t
  (*private_key_max_signature_output_len)(const void *private_key);

  Boolean (*public_key_verify)(const void *public_key,
                               const unsigned char *signature,
                               size_t signature_len,
                               SshRGFHash hash, 
                               const SshRGFDef *rgf_def);

  SshOperationHandle (*public_key_verify_async)(const void *public_key,
                                                const unsigned char *signature,
                                                size_t signature_len,
                                                SshRGFHash hash, 
                                                const SshRGFDef *rgf_def,
                                                SshPublicKeyVerifyCB callback,
                                                void *context);


  Boolean (*private_key_sign)(const void *private_key,
                              SshRGFHash hash,
                              unsigned char *signature_buffer,
                              size_t signature_buffer_len,
                              size_t *signature_length_return,
                              const SshRGFDef *rgf_def);

  SshOperationHandle (*private_key_sign_async)(const void *private_key,
                                               SshRGFHash hash,
                                               const SshRGFDef *rgf_def,
                                               SshPrivateKeySignCB callback,
                                               void *context);
} SshPkSignature;

/* Encryption schemes */

typedef struct
{
  /* Encryption scheme names should be unique and follow if possible
     our naming policy. */

  const char *name;

  void (*action_scheme)(void *context);

  /* RGF for padding and redundancy. */

  const SshRGFDef *rgf_def;

  /* Decryption input/output maximum buffer lengths. */
  size_t (*private_key_max_decrypt_input_len)(const void *private_key);
  size_t (*private_key_max_decrypt_output_len)(const void *private_key);

  /* Private key decryption. */
  Boolean (*private_key_decrypt)(const void *private_key,
                                 const unsigned char *ciphertext,
                                 size_t ciphertext_len,
                                 unsigned char *plaintext_buffer,
                                 size_t plaintext_buffer_len,
                                 size_t *plaintext_length_return,
                                 const SshRGFDef *rgf_def);

  /* Private key decrypt async. */
  SshOperationHandle (*private_key_decrypt_async)(const void *private_key,
                                                  const unsigned char
                                                  *ciphertext,
                                                  size_t ciphertext_len,
                                                  const SshRGFDef *rgf_def,
                                                  SshPrivateKeyDecryptCB
                                                  callback,
                                                  void *context);

  /* Maximum encryption output/input buffer lengths. */
  size_t (*public_key_max_encrypt_input_len)(const void *public_key);
  size_t (*public_key_max_encrypt_output_len)(const void *public_key);

  /* Encryption with the public key. */
  Boolean (*public_key_encrypt)(const void *public_key,
                                const unsigned char *plaintext,
                                size_t plaintext_len,
                                unsigned char *ciphertext_buffer,
                                size_t ciphertext_buffer_len,
                                size_t *ciphertext_len_return,
                                const SshRGFDef *hash_def);

  SshOperationHandle (*public_key_encrypt_async)
       (const void *public_key,
        const unsigned char *plaintext,
        size_t plaintext_len,
        const SshRGFDef *rgf_def,
        SshPublicKeyEncryptCB callback,
        void *context);

  /* Private key encrypt */
  Boolean (*private_key_encrypt)(const void *private_key,
                                 const unsigned char *data,
                                 size_t data_len,
                                 unsigned char *ciphertext_buffer, 
                                 size_t ciphertext_buffer_len,
                                 size_t *ciphertext_len_return);

  SshOperationHandle (*private_key_encrypt_async)(const void *private_key,
                                                  const unsigned char *data,
                                                  size_t data_len,
                                                  SshPrivateKeyEncryptCB
                                                  callback,
                                                  void *context);

  /* Public key decrypt */
  Boolean (*public_key_decrypt)(const void *public_key,
                                const unsigned char *ciphertext,
                                size_t ciphertext_len,
                                unsigned char *plaintext_buffer,
                                size_t plaintext_buffer_len,
                                size_t *plaintext_length_return);
                                      
  SshOperationHandle (*public_key_decrypt_async)(const void *public_key,
                                                 const unsigned char
                                                 *ciphertext,
                                                 size_t ciphertext_len,
                                                 SshPublicKeyDecryptCB
                                                 callback,
                                                 void *context);
} SshPkEncryption;

/* Diffie-Hellman */

typedef struct
{
  /* Diffie-Hellman type name. */
  const char *name;

  void (*action_scheme)(void *context);

  /* Diffie-Hellman internal interface definitions */

  size_t (*diffie_hellman_exchange_max_length)(const void *pk_group);
  size_t (*diffie_hellman_secret_value_max_length)(const void *pk_group);

  Boolean (*diffie_hellman_setup)(void *pk_group,
                                  void **dh_extra,
                                  unsigned char *exchange_buffer,
                                  size_t exchange_buffer_length,
                                  size_t *return_length);
  
  SshOperationHandle (*diffie_hellman_setup_async)(void *pk_group,
                                                  SshPkGroupDHSetup callback,
                                                  void *context);

  Boolean (*diffie_hellman_agree)(void *pk_group,
                                  void *dh_extra,
                                  unsigned char *exchange_buffer,
                                  size_t exchange_buffer_length,
                                  unsigned char *secret_value_buffer,
                                  size_t secret_value_buffer_length,
                                  size_t *return_length);
  
  
  SshOperationHandle
  (*diffie_hellman_agree_async)(void *pk_group,
                                void *dh_extra,
                                unsigned char *exchange_buffer,
                                size_t exchange_buffer_length,
                                SshPkGroupDHAgree callback,
                                void *context);
  
  /* Unified Diffie-Hellman protocol as suggested by
     Don Johnson at P1363 meeting May 15-16 1997. */

  /* Diffie-Hellman hides within Unified approach! */
  size_t (*udh_secret_value_max_length)(const void *pk_group);
  Boolean (*udh_agree)(const void *public_key,
                       const void *private_key,
                       void *dh_extra,
                       unsigned char *exchange_buffer,
                       size_t exchange_length,
                       unsigned char *secret_value_buffer,
                       size_t secret_value_length,
                       size_t *return_length);
  SshOperationHandle
  (*udh_agree_async)(const void *pubilc_key,
                     const void *private_key,
                     void *dh_extra,
                     unsigned char *exchange_buffer,
                     size_t exchange_length,
                     SshPkGroupDHAgree callback,
                     void *context);
  
} SshPkDiffieHellman;

#if 0
/* These are just some proposed additions for future. */

/* One way authentication schemes */

typedef struct
{
  /* One-Way Authenticated key exchange protocol, is designed for SSH. Here
     are few variations. Names aren't standardized, so use any name that is
     unique. */
  const char *name;
  void (*action_scheme)(void *context);

  /* OWA interface. Needs just few functions. */

} SshPkOneWayAuth;


/* Menezes-Qu-Vanstone protocol */

typedef struct
{
  const char *name;
  void (*action_scheme)(void *context);

} SshPkMQV;

/* Two way authentication schemes */

typedef struct
{
  /* Two-Way authenticated key exchange protocol, is extended OWA. Few
     variations should exist. Names should be just unique. */
  const char *name;
  void (*action_scheme)(void *context);
  
} SshPkTwoWayAuth;

/* More schemes? */
#endif

/* General main key type structure. This structure defines the most important
   part, the handling of internal key/group contexts. */

typedef struct
{
  /* Name for key. Keys are named/typed as follows:

       if-modn    for RSA etc.
       dl-modp    for DSA, ElGamal etc.
       ec-modp    for ECDSA, ECElGamal etc.
       ec-gf2n    for ECDSA, etc.
     */
  const char *name;

  /* Special actions, for key management. I.e. things like inserting
     parameters, fixing exponent etc. */
  const SshPkAction *action_list;

  /* Group functions */

  /* Initialization and make. */
  void *(*pk_group_action_init)(void);
  void *(*pk_group_action_make)(void *context);
  void (*pk_group_action_free)(void *context);

  Boolean (*pk_group_import)(const unsigned char *buf,
                             size_t length,
                             void **pk_group);
  Boolean (*pk_group_export)(const void *pk_group,
                             unsigned char **buf,
                             size_t *length_return);
  void (*pk_group_free)(void *pk_group);
  void (*pk_group_copy)(void *op_src, void **op_dest);
  char *(*pk_group_get_predefined_groups)(void);

  /* Precomputation routine. */
  void (*pk_group_precompute)(void *context);
  
  /* Randomizer handling. */
  unsigned int (*pk_group_count_randomizers)(void *pk_group);
  Boolean (*pk_group_generate_randomizer)(void *pk_group);
  Boolean (*pk_group_export_randomizer)(void *pk_group,
                                        unsigned char **buf,
                                        size_t *length_return);
  Boolean (*pk_group_import_randomizer)(void *pk_group,
                                        unsigned char *buf,
                                        size_t length);

  /* Key functions */

  /* Initialization (definition) and make. Note that it makes no
     sense in generating new public key so we don't give random state
     here. */
  void *(*public_key_action_init)(void);
  void *(*public_key_action_make)(void *context);
  void (*public_key_action_free)(void *context);

  /* Public key blob import and export function interfaces. */
  Boolean (*public_key_import)(const unsigned char *buf,
                               size_t len,
                               void **public_key);
  Boolean (*public_key_export)(const void *public_key,
                               unsigned char **buf,
                               size_t *length_return);
  /* Removal of public key from memory. */
  void (*public_key_free)(void *public_key);

  void (*public_key_copy)(void *op_src, void **op_dest);

  void (*public_key_derive_pk_group)(void *public_key,
                                     void **pk_group);

  /* Precomputation routine. */
  void (*public_key_precompute)(void *context);


  /* Private key action initialization and key generation routines. */
  void *(*private_key_action_init)(void);
  void *(*private_key_action_make)(void *context);
  void (*private_key_action_free)(void *context);

  /* Import and export of private key blobs. */
  Boolean (*private_key_import)(const unsigned char *buf,
                                size_t len,
                                void **private_key);
  Boolean (*private_key_export)(const void *private_key,
                                unsigned char **buf,
                                size_t *length_return);
  /* Removal of the private key from memory. */
  void (*private_key_free)(void *private_key);
  /* Deriving public key from private key. */
  void (*private_key_derive_public_key)(const void *private_key,
                                        void **public_key);

  void (*private_key_copy)(void *op_src, void **op_dest);

  void (*private_key_derive_pk_group)(void *private_key,
                                      void **pk_group);
  /* Precomputation routine. */
  void (*private_key_precompute)(void *context);
  
  /* More to come... */
} SshPkType;

/* Context that contain all information especially needed in
   the generic code. */

struct SshPkGroupRec
{
  /* General information (which are supported with just parameters) */
  const SshPkType *type;

  /* Scheme supported. */
  const SshPkDiffieHellman *diffie_hellman;

  /* Special parameter information / key dependend */
  void *context;
};

struct SshPublicKeyRec
{
  /* General information */
  const SshPkType *type;

  /* Schemes */
  const SshPkSignature *signature;
  const SshPkEncryption *encryption;
  const SshPkDiffieHellman *diffie_hellman;
  
  /* Special information / key dependend */
  void *context;
};

struct SshPrivateKeyRec
{
  /* General information */
  const SshPkType *type;

  /* Schemes */
  SshPkSignature *signature;
  SshPkEncryption *encryption;
  const SshPkDiffieHellman *diffie_hellman;

  /* Special information / key dependend */
  void *context;
};

/* End of public key defines. */

/* Function prototypes that are used internally. */

#ifdef SSHDIST_CRYPT_GENHASH

DLLEXPORT SshHash DLLCALLCONV
ssh_hash_allocate_internal(const SshHashDef *hash_def);

const SshHashDef *ssh_hash_get_definition_internal(const SshHash hash);

#endif /* SSHDIST_CRYPT_GENHASH */

/* Expansion from a passphrase into a key. */

void ssh_hash_expand_key_internal(unsigned char *buffer, size_t buffer_len,
                                  const unsigned char *ps, size_t ps_len,
                                  unsigned char *magic, size_t magic_len,
                                  const SshHashDef *hash);

/* Maximum of provider slots, must be larger than the number of default
   providers. Current there exists only 4 default software slots. It is
   assumed that SSH modules will not add more than 200 other providers.
   */
#define SSH_PK_TYPE_MAX_SLOTS 256

/* Register a public key provider. */
DLLEXPORT SshCryptoStatus DLLCALLCONV
ssh_pk_provider_register(const SshPkType *type);

#endif /* SSHCRYPTI_H */
