/*
 * Copyright (c) 2003-2016
 * Distributed Systems Software.  All rights reserved.
 * See the file LICENSE for redistribution information.
 *
 * $Id: dacs_crypto.h 2912 2016-10-18 19:54:07Z brachman $
 */

#ifndef _DACS_CRYPTO_H_
#define _DACS_CRYPTO_H_

#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <openssl/md5.h>

#include "blake2.h"
#include "argon2.h"

/*
 * This list may be extended BUT DO NOT CHANGE THE MAPPING because
 * the digest algorithm numbers are stored with the hashed passwords.
 * If you change a mapping, you must also change your DACS password files
 * accordingly, otherwise you will invalidate passwords.
 */
typedef enum {
  PASSWD_ALG_CRYPT         =  0,
  PASSWD_ALG_MD5           =  1,
  PASSWD_ALG_SHA1          =  2,
  PASSWD_ALG_SHA224        =  3,
  PASSWD_ALG_SHA256        =  4,
  PASSWD_ALG_SHA384        =  5,
  PASSWD_ALG_SHA512        =  6,
  PASSWD_ALG_PBKDF2_SHA1   =  7,
  PASSWD_ALG_PBKDF2_SHA256 =  8,
  PASSWD_ALG_PBKDF2_SHA512 =  9,
  PASSWD_ALG_SCRYPT        = 10,
  PASSWD_ALG_PBKDF2        = 11,	/* Internal digest is parameterized. */
  PASSWD_ALG_SHA512t       = 12,
  PASSWD_ALG_SHA3_224      = 13,
  PASSWD_ALG_SHA3_256      = 14,
  PASSWD_ALG_SHA3_384      = 15,
  PASSWD_ALG_SHA3_512      = 16,
  PASSWD_ALG_SHA512_224    = 17,
  PASSWD_ALG_SHA512_256    = 18,
  PASSWD_ALG_BLAKE2        = 19,
  PASSWD_ALG_ARGON2        = 20,

  PASSWD_ALG_NONE   = 999
} Passwd_digest_alg;

/* All cryptographic hash functions. */
typedef enum {
  DIGEST_MD5           =  1,
  DIGEST_SHA           =  2,
  DIGEST_SHA1          =  3,
  DIGEST_SHA224        =  4,
  DIGEST_SHA256        =  5,
  DIGEST_SHA384        =  6,
  DIGEST_SHA512        =  7,
  DIGEST_SHA512_224    =  8,
  DIGEST_SHA512_256    =  9,
  DIGEST_SHA512t       = 10,
  DIGEST_SHA3_224      = 11,
  DIGEST_SHA3_256      = 12,
  DIGEST_SHA3_384      = 13,
  DIGEST_SHA3_512      = 14,
  DIGEST_PBKDF2        = 15,
  DIGEST_PBKDF2_SHA1   = 16,	/* count=16384, dklen=32 */
  DIGEST_PBKDF2_SHA256 = 17,	/* count=32768, dklen=32 */
  DIGEST_PBKDF2_SHA512 = 18,	/* count=32768, dklen=64 */
  DIGEST_SCRYPT        = 19,	/* N=131072, r=8, p=1, dklen=32 */
								/* or N=32768, r=8, p=8, dklen=64 */
  DIGEST_CRYPT         = 20,
  DIGEST_BLAKE2        = 21,
  DIGEST_ARGON2        = 22,
  DIGEST_INVALID       = -1
} Digest_alg;

/*
 * Define this to be the largest supported digest_size in digest_tab,
 * in bytes.
 * It is handy to have this available at compile time.
 * N.B. XXX When a new digest function is added, this may need to be updated.
 */
#define DIGEST_MAX_DIGEST_SIZE	64

#define BLAKE2_DEFAULT_DIGEST_SIZE	BLAKE2B_OUTBYTES
#define BLAKE2_HMAC_DIGEST_SIZE		BLAKE2B_OUTBYTES

/*
 * RFC 2104
 * http://www.w3.org/2000/09/xmldsig#hmac-sha1
 * http://www.rsasecurity.com/rsalabs/pkcs/schemas/pkcs-5#hmac-sha-224
 * http://www.rsasecurity.com/rsalabs/pkcs/schemas/pkcs-5#hmac-sha-256
 * http://www.rsasecurity.com/rsalabs/pkcs/schemas/pkcs-5#hmac-sha-384
 * http://www.rsasecurity.com/rsalabs/pkcs/schemas/pkcs-5#hmac-sha-512
 */
typedef struct Digest_tab {
  const char *name;				/* Canonical name. */
  Digest_alg alg;				/* Unique internal digest algorithm ID. */
  unsigned int block_size;		/* Internal block size, in bytes. */
  unsigned int digest_size;		/* Digest (output) size, in bytes. */
  Passwd_digest_alg passwd_alg;	/* Unique external algorithm ID. */
  const char *arg_spec;			/* List of parameter names, or NULL. */
  const EVP_MD *evp;			/* Only if OpenSSL. */
  unsigned int flags;			/* Implementation and purpose descriptors. */
} Digest_tab;

typedef struct Pbkdf2_desc {
  Digest_alg alg;
  unsigned int count;
  unsigned int dklen;
} Pbkdf2_desc;

typedef struct Scrypt_desc {
  uint64_t N;
  unsigned int r;
  unsigned int p;
  unsigned int dklen;
} Scrypt_desc;

typedef struct Sha512t_desc {
  unsigned int t;
} Sha512t_desc;

typedef struct Argon2_desc {
  Argon2_type type;
  uint32_t lanes;
  uint32_t m_cost;
  uint32_t outlen;
  uint32_t t_cost;
  uint32_t version;
  uint8_t *ad;
  unsigned int adlen;
  uint8_t *salt;
  unsigned int saltlen;
} Argon2_desc;

/*
 * A parsed digest descriptor.  See crypto_parse_digest_desc().
 */
typedef struct Digest_desc {
  char *desc;					/* Original specification of the digest. */
  Digest_tab *dt;				/* Algorithm description. */
  char *formatted_desc;			/* Formatted digest specification. */
  union {						/* Parsed-out digest parameters. */
	Pbkdf2_desc pbkdf2;
	Scrypt_desc scrypt;
	Sha512t_desc sha512t;
	Argon2_desc argon2;
  } u;
} Digest_desc;  

enum {
  SHA3_MAX_PERMUTATION_SIZE = 25,
  SHA3_MAX_RATE_IN_QWORDS   = 24,
  SHA3_NUMBER_OF_ROUNDS     = 24,
  SHA3_MAX_DIGEST_SIZE      = (512 / 8)
};

/* Context for a SHA-3 family hash function. */
typedef struct SHA3_ctx {
  Digest_tab *dt;
  unsigned int rate;
  size_t digest_bits;							/* Output length, in bits. */
  uint64_t hash[SHA3_MAX_PERMUTATION_SIZE]; 	/* State: 1600 bits. */
  uint64_t message[SHA3_MAX_RATE_IN_QWORDS];	/* 1536-bits for leftovers. */
  unsigned int rest;							/* Bytes in message[]. */
  unsigned int block_size;						/* Message block size. */
  unsigned int bit_padding;
} SHA3_ctx;

typedef struct Blake2_ctx {
  char *key;					/* An optional key, as in HMAC. */
  unsigned int key_len;
  Blake2b_state blake2_state;
} Blake2_ctx;

typedef struct Digest_ctx {
  Digest_tab *dt;
  int sha512_t;					/* If this is SHA512/t, the value of t. */
  union {
	EVP_MD_CTX *evp_ctx;
	SHA3_ctx sha3_ctx;
	Blake2_ctx blake2_ctx;
  } u;
} Digest_ctx;

/* Implementation identifiers. */
#define DIGEST_NONE			0x00		/* No implementation. */
#define DIGEST_DACS			0x01		/* Implemented by DACS. */
#define DIGEST_OPENSSL		0x02		/* Implemented by OpenSSL. */
#define DIGEST_SYSTEM		0x03		/* Provided by operating system. */

/* Bit flags to describe a hash function or key derivation function. */
#define DIGEST_USE_PASSWD		0x010		/* DACS passwords. */
#define DIGEST_USE_HMAC			0x020		/* With HMAC. */
#define DIGEST_USE_SIGN			0x040		/* Sign via EVP_DigestInit. */
#define DIGEST_USE_PBKDF2		0x080		/* With PBKDF2. */
#define DIGEST_USE_SCRYPT       0x100		/* With scrypt. */
#define DIGEST_USE_PARAMS		0x200		/* Requires parameters. */
#define DIGEST_USE_VARLEN		0x400		/* Makes variable length digest. */

static inline int
digest_implementation(unsigned int flags)
{

  return(flags & 0x0f);
}

static inline int
digest_usage(unsigned int flags)
{

  return(flags & 0xff0);
}

static inline int
digest_is_sha2(Digest_tab *dt)
{

  if (dt->alg == DIGEST_SHA224 || dt->alg == DIGEST_SHA256
	  || dt->alg == DIGEST_SHA384 || dt->alg == DIGEST_SHA512)
	return(1);

  return(0);
}

static inline int
digest_is_sha512_ext(Digest_tab *dt)
{

  if (dt->alg == DIGEST_SHA512_224 || dt->alg == DIGEST_SHA512_256
	  || dt->alg == DIGEST_SHA512t)
	return(1);

  return(0);
}

static inline int
digest_is_sha3(Digest_tab *dt)
{

  if (dt->alg == DIGEST_SHA3_224 || dt->alg == DIGEST_SHA3_256
	  || dt->alg == DIGEST_SHA3_384 || dt->alg == DIGEST_SHA3_512)
	return(1);

  return(0);
}

static inline int
digest_is_passwd_alg(Digest_tab *dt)
{

  if (digest_usage(dt->flags) & DIGEST_USE_PASSWD)
	return(1);

  return(0);
}

typedef enum {
  CRYPTO_SYMMETRIC_ENCRYPT = 0,
  CRYPTO_SYMMETRIC_DECRYPT = 1,
  CRYPTO_PKI_ENCRYPT       = 2,
  CRYPTO_PKI_DECRYPT       = 3
} Crypto_function;

/*
 * Do not change these unless you understand exactly how they are used.
 */
enum {
  CRYPTO_DIGEST_MD5_BYTE_LENGTH   = (128 / 8),
  CRYPTO_DIGEST_SHA1_BYTE_LENGTH  = (160 / 8),
  CRYPTO_HMAC_KEY_LENGTH          = CRYPTO_DIGEST_SHA1_BYTE_LENGTH,
  CRYPTO_HMAC_BYTE_LENGTH         = CRYPTO_DIGEST_SHA1_BYTE_LENGTH,
  /*
   * This selects the method to use for generating IVs for encryption.
   * See crypto.c:make_iv()
   */
  CRYPTO_USE_RANDOMIZED_IV		    = 0
};

/* The digest algorithm to use with encryption of credentials etc. */
#ifndef CRYPTO_HMAC_DIGEST_ALG_NAME
#define CRYPTO_HMAC_DIGEST_ALG_NAME	"SHA1"
#endif

/* The digest algorithm to use to uniquely identify credentials. */
#ifndef CRYPTO_DIGEST_ALG_NAME
#define CRYPTO_DIGEST_ALG_NAME	"SHA1"
#endif

/* The cipher to use for credentials etc. */
#ifndef CRYPTO_CRYPT_ALG_NAME
#define CRYPTO_CRYPT_ALG_NAME	"AES-128-CFB"
#endif

/* The cipher to use for creating an IV - see crypto.c:make_iv() */
#ifndef CRYPTO_IV_CIPHER_NAME
#define CRYPTO_IV_CIPHER_NAME	"AES-128-CFB"
#endif

/* XXX changes to these may require code modification. */
#define CRYPTO_RANDOMIZED_DIGEST_NAME	"SHA1"
#define CRYPTO_SIGNATURE_DIGEST_NAME	"SHA1"

/* RFC 7539. */
enum {
  CHACHA_ROUNDS         = 20,	/* Recommended number of rounds for security. */
  CHACHA_MIN_KEY_LENGTH = 16,
  CHACHA_NONCE_LENGTH   = 12,
  CHACHA_COUNTER_LENGTH = 8,
  CHACHA_BLOCK_LENGTH   = 64
};

typedef struct Chacha_ctx {
  uint32_t input[16];
} Chacha_ctx;

typedef struct Hmac_handle {
  char *digest_name;
  Digest_alg alg;
  unsigned int block_size;
  unsigned int hmac_size;
  unsigned char *hmac_key_ipad;
  unsigned char *hmac_key_opad;
  Digest_ctx *ctx;
} Hmac_handle;

typedef struct Cipher_handle {
  Crypto_function func;
  char *cipher_name;
  EVP_CIPHER_CTX *ctx;
} Cipher_handle;

typedef struct PKI_session_keys {
  char *cipher_name;
  int nkeys;
  unsigned char **ek;
  int *ekl;
  EVP_PKEY **pubk;
} PKI_session_keys;

typedef struct Rng_state {
  unsigned int *V;
  unsigned int *C;
  int reseed_counter;
  int security_strength;
  int prediction_resistance_flag;
} Rng_state;

#ifdef __cplusplus
extern "C" {
#endif

extern int debug_crypto;

/* Misc */
extern int crypto_init(void);
extern char *crypto_digest_list(void);
extern void crypto_log_error(void);
extern Ds *crypto_cert_thumbprint(char *stripped_cert, char **fmt);
extern void crypto_show_digest_info(FILE *ofp, const char *digest_name);
extern char *crypto_parse_digest_name(const char *digest_name, Kwv **kwv_args);

extern Ds *pem_cert_strip_str(char *str);
extern Ds *pem_cert_strip(Ds *ds);
extern Ds *pem_cert_thumbprint(char *cert);
extern char *pem_cert_thumbprint_fmt(Ds *tp);
extern char *pem_cert_thumbprint_fmt_str(char *cert);
extern Ds *pem_cert_load_stripped(char *certfile);
extern RSA *pem_load_private_key(char *keyfile, char *passphrase);
extern RSA *pem_load_private_key_from_buf(char *buf, int buflen,
										  char *passphrase);
extern char *pem_from_evp_pub_pkey(EVP_PKEY *public_key);
extern char *pem_from_evp_priv_pkey(EVP_PKEY *private_key);
extern Ds *pem_make_cert(char *enc_cert_str);

extern Ds *sha1(unsigned char *buf, size_t buflen);
extern Ds *sha256(unsigned char *buf, size_t buflen);

/* Message Digests */
extern void crypto_keccak_init(SHA3_ctx *ctx, unsigned bits);
extern Digest_tab *crypto_lookup_hmac_digest_by_size(unsigned int size);
extern Digest_tab *crypto_lookup_hmac_digest_by_name(const char *digest_name);
extern unsigned int crypto_lookup_digest_size(const char *digest_name);
extern Digest_desc *crypto_parse_digest_desc(const char *digest_desc);
extern Digest_desc *
	crypto_lookup_passwd_digest_desc_by_name(const char *digest_name);
extern Passwd_digest_alg
	crypto_lookup_passwd_digest_algorithm(const char *digest_name);
extern Digest_tab *
	crypto_lookup_passwd_digest_by_algorithm(Passwd_digest_alg alg);
extern Digest_tab *crypto_lookup_digest_by_name(const char *digest_name);
extern Digest_tab *crypto_lookup_digest_by_algorithm(Digest_alg alg);
extern const char *crypto_lookup_digest_name_by_algorithm(Digest_alg alg);
extern char *crypto_digest_make_desc(Digest_desc *dd);

extern unsigned char *crypto_digest(const char *digest_name, const void *input,
									size_t input_len,
									unsigned char *output,
									unsigned int *output_len, ...);
extern Digest_ctx *crypto_digest_open(const char *digest_name, ...);
extern Digest_ctx *crypto_digest_open_dd(Digest_desc *dd);
extern Digest_ctx *crypto_digest_open_x(const char *digest_name, va_list ap);

extern void crypto_digest_hash(Digest_ctx *ctx, const void *input,
							   size_t input_len);
extern unsigned char *crypto_digest_close(Digest_ctx *ctx,
										  unsigned char *output,
										  unsigned int *output_len);

extern const EVP_CIPHER *crypto_cipher_methodbyname(char *name);

extern SHA3_ctx *sha3_init(Digest_alg alg, SHA3_ctx *octx,
						   unsigned int *digest_size);
extern SHA3_ctx *sha3_init_by_name(const char *digest_name, SHA3_ctx *octx,
								   unsigned int *digest_size);
extern int sha3(Digest_alg alg, const unsigned char *msg, int msglen,
				unsigned char *result, unsigned int *digest_size);
extern int sha3_by_name(const char *digest_name, const unsigned char *msg,
						int msglen, unsigned char *result,
						unsigned int *digest_size);
extern int sha3_bits(Digest_alg alg, const unsigned char *msg, size_t nbits,
					 unsigned char *result, unsigned int *digest_size);
extern void sha3_update(SHA3_ctx *ctx, const unsigned char* msg, size_t size);
extern void sha3_update_bits(SHA3_ctx *ctx, const unsigned char *msg,
							 size_t nbits);
extern void sha3_final(SHA3_ctx *ctx, unsigned char* result);

/* PKI Signing and Verifying */
extern Digest_ctx *crypto_sign_open(const char *digest_name);
extern int crypto_sign_update(Digest_ctx *ctx, unsigned char *buf,
							  unsigned int len);
extern unsigned char *crypto_sign_close(Digest_ctx *ctx,
										unsigned char *sign_buf,
										unsigned int *sign_len,
										EVP_PKEY *private_key);
extern unsigned char *crypto_sign(char *digest_name, unsigned char *buf,
								  unsigned int len,
								  unsigned char **sign_buf,
								  unsigned int *sign_len,
								  EVP_PKEY *private_key);

extern Digest_ctx *crypto_signv_open(char *digest_name);
extern int crypto_signv_update(Digest_ctx *ctx, unsigned char *buf,
							   unsigned int len);
extern int crypto_signv_close(Digest_ctx *ctx, unsigned char *sign_buf,
							  unsigned int sign_len, EVP_PKEY *public_key);
extern int crypto_signv(char *digest_name, unsigned char *buf,
						unsigned int len, unsigned char *sign_buf,
						unsigned int sign_len, EVP_PKEY *public_key);
extern Ds *crypto_sign_buf(Ds *data, RSA *priv_key);
extern Ds *crypto_sign_buf_len(Ds *data, RSA *priv_key,
							   unsigned int max_datalen);

/* Keyed Message Digests */
extern Hmac_handle *crypto_hmac_open(const char *digest_name, unsigned char *key,
									 unsigned int keylen);
extern void crypto_hmac_hash(Hmac_handle *conf, unsigned char *str,
							 unsigned int len);
extern unsigned char *crypto_hmac_close(Hmac_handle *conf,
										unsigned char *hmac_buf,
										unsigned int *hmac_len);
extern unsigned char *crypto_hmac(const char *digest_name,
								  unsigned char *key, unsigned int klen,
								  unsigned char *value, unsigned int vlen,
								  unsigned char **hmac, unsigned int *hlen);

/* Random material */
extern int crypto_randomize_buffer(unsigned char *buf, unsigned int len);
extern int crypto_random_uint(unsigned int lo, unsigned int hi,
							  unsigned int *uint);
extern unsigned char *crypto_make_random_buffer(unsigned int len);
extern char *crypto_make_random_string(char *prefix, int nbytes);
extern char *crypto_make_random_string_from_spec(char *tr_spec, int nbytes,
												 int cflag);
extern char *crypto_make_random_string_from_template(char *template);
extern char *crypto_make_random_a64(char *prefix, int nbytes);
extern void crypto_make_randomized_from_passphrase(unsigned char *pp,
												   unsigned int pplen,
												   unsigned int needed,
												   unsigned char **rbuf);
/* Key Derivation */
extern unsigned char *crypto_pbkdf2(unsigned char *pwd, int pwdlen,
									unsigned char *salt, int saltlen,
									char *algname,
									unsigned int count, unsigned int dklen);
extern unsigned char *crypto_kdf(unsigned char *pwd, int pwdlen,
								 unsigned char *salt, int saltlen, char *algname,
								 unsigned int count, unsigned int nbits);
extern unsigned char *crypto_scrypt(unsigned char *passwd,
									unsigned int passwdlen,
									unsigned char *salt, unsigned int saltlen,
									uint64_t n, uint32_t r, uint32_t p,
									unsigned int dklen);
extern unsigned char *crypto_hkdf_extract(unsigned char *ikm,
										  unsigned int ikmlen,
										  unsigned char *salt, int saltlen,
										  char *digest_name,
										  unsigned char **hkdfbuf,
										  unsigned int *hkdfbuf_len);
extern unsigned char *crypto_hkdf_expand(unsigned char *prk, unsigned int prklen,
										 unsigned char *info,
										 unsigned int infolen,
										 unsigned int need, char *digest_name);
extern unsigned char *crypto_hkdf(unsigned char *ikm, unsigned int ikmlen,
								  unsigned char *salt, unsigned int saltlen,
								  unsigned char *info, unsigned int infolen,
								  unsigned int need, char *digest_name);

/* Encryption/Decryption */
extern void crypto_set_padding(int enable);
extern int crypto_cipher_key_length(char *cipher_name, unsigned int *len);
extern int crypto_cipher_iv_length(char *cipher_name, unsigned int *len);
extern unsigned char *crypto_encipher(Crypto_function func, char *cipher,
									  unsigned char *key, unsigned char **ivp,
									  PKI_session_keys *sk,
									  unsigned char *input, int input_len,
									  unsigned char *output, int *output_len);
extern unsigned char *crypto_decipher(Crypto_function func, char *cipher,
									  unsigned char *key, unsigned char **ivp,
									  PKI_session_keys *sk,
									  unsigned char *input, int input_len,
									  unsigned char *output, int *output_len);
struct Crypt_keys;
extern unsigned int crypto_encrypt_string(struct Crypt_keys *keys,
										  unsigned char *plaintext,
										  unsigned int len,
										  unsigned char **encrypted);
extern int crypto_decrypt_string(struct Crypt_keys *keys,
								 unsigned char *encrypted,
								 unsigned int len, unsigned char **plaintext,
								 unsigned int *plaintext_length);
extern char *crypt_md5(const char *pw, const char *salt);
extern void crypt_md5_magic(char *new_magic);

extern void chacha_init(Chacha_ctx *ctx, const uint8_t *key,
						const uint8_t *nonce, uint32_t counter);
extern void chacha_cipher(Chacha_ctx *ctx, const uint8_t *message,
						  uint8_t *output, uint32_t nrounds, uint32_t nbytes);
extern void chacha_cipher_message(const uint8_t *message, uint8_t *output,
								  uint32_t nrounds, uint32_t nbytes,
								  const uint8_t *key, const uint8_t *nonce,
								  uint32_t counter);


/* PKI Encryption/Decryption */
extern char *crypto_pki_encrypt(char *cipher_name, EVP_PKEY *key,
								unsigned char *input, int input_len,
								char *digest_name, EVP_PKEY *sign_key);
extern unsigned char *crypto_pki_decrypt(EVP_PKEY *key, char *input,
										 int *output_len);

/* Deterministic Random Bit Generators */
extern Rng_state *rng_init(char *seed);
extern Rng_state *rng_reinit(char *new_seed, Rng_state *state);
extern int rng_generate(Rng_state *state, unsigned char *buf, size_t len);
extern char *rng_generate_string(Rng_state *state, char *prefix, size_t len);
extern void rng_end(Rng_state *state);

#ifdef __cplusplus
}
#endif

#endif
