/**
 * \file ctr_drbg.h
 * \brief CTR_DRBG AES-256 implementation according to SP800-90A.
 * \author Dmytro Podgornyi (d.podgornyi@samsung.com)
 * \version 0.1
 * \date Created Sep 04, 2013
 * \par In Samsung Ukraine R&D Center (SURC) under a contract between
 * \par LLC "Samsung Electronics Ukraine Company" (Kiev, Ukraine) and
 * \par "Samsung Elecrtronics Co", Ltd (Seoul, Republic of Korea)
 * \par Copyright: (c) Samsung Electronics Co, Ltd 2012. All rights reserved.
 **/

#ifndef __CTR_DRBG_H_INCLUDED__
#define __CTR_DRBG_H_INCLUDED__

#include <stdint.h>

/* Configuration */
/* CTR_DRBG implementation without derivation function */
/* #define CTR_DRBG_WITHOUT_DF */
/* Use heap (malloc) for big buffers */
/* #define CTR_DRBG_DYNAMIC_BUFFERS */

/* Parameters for AES-256. See SP800-90A.pdf p.49 */
#define CTR_DRBG_OUTLEN 128
#define CTR_DRBG_KEYLEN 256
#define CTR_DRBG_SEEDLEN (CTR_DRBG_OUTLEN + CTR_DRBG_KEYLEN)
#define CTR_DRBG_RESEED_INTERVAL (1ULL << 48)
#define CTR_DRBG_MAX_BITS (1 << 19)

#if (CTR_DRBG_OUTLEN % 8 != 0 || CTR_DRBG_KEYLEN % 8 != 0)
#    error "CTR_DRBG_OUTLEN and CTR_DRBG_KEYLEN must be multiple of 8"
#endif
#define CTR_DRBG_OUTLEN_BYTES (CTR_DRBG_OUTLEN / 8)
#define CTR_DRBG_KEYLEN_BYTES (CTR_DRBG_KEYLEN / 8)
#define CTR_DRBG_SEEDLEN_BYTES (CTR_DRBG_SEEDLEN / 8)

#define CTR_DRBG_MAX_SECURITY_STRENGTH 256

#ifdef CTR_DRBG_WITHOUT_DF
#define CTR_DRBG_MIN_ENTROPY CTR_DRBG_SEEDLEN_BYTES
#define CTR_DRBG_MAX_ENTROPY CTR_DRBG_SEEDLEN_BYTES
#define CTR_DRBG_MAX_PERSONAL CTR_DRBG_SEEDLEN_BYTES
#define CTR_DRBG_MAX_ADDITIONAL CTR_DRBG_SEEDLEN_BYTES
#define CTR_DRBG_MIN_NONCE 0		/* not used */
#define CTR_DRBG_MAX_NONCE 0xffffffffU	/* not used */
#else  /* CTR_DRBG_WITHOUT_DF */
#define CTR_DRBG_MIN_ENTROPY (ctx->security_strength / 8)
#define CTR_DRBG_MAX_ENTROPY 0xffffffffU - 1
#define CTR_DRBG_MAX_PERSONAL 0xffffffffU - 1
#define CTR_DRBG_MAX_ADDITIONAL 0xffffffffU - 1
#define CTR_DRBG_MIN_NONCE (ctx->security_strength / 16)
#define CTR_DRBG_MAX_NONCE 0xffffffffU - 1
#endif /* CTR_DRBG_WITHOUT_DF */

/* Error codes */
#define DRBG_NO_ERROR		 0
#define DRBG_E_RESEED_NEEDED	-1
#define DRBG_E_WRONG_DATA	-2
#define DRBG_E_AES_KEY		-3
#define DRBG_E_TOO_LOW		-4
#define DRBG_E_TOO_BIG		-5

struct ctr_drbg_state_t
{
	uint8_t v[CTR_DRBG_OUTLEN_BYTES];
	uint8_t key[CTR_DRBG_KEYLEN_BYTES];
	uint64_t reseed_counter;

	int security_strength;
};

typedef struct ctr_drbg_state_t CTR_DRBG_CTX;

int CTR_DRBG_Instantiate(CTR_DRBG_CTX *ctx,
	const uint8_t *entropy_input,
	uint32_t entropy_input_len,
	const uint8_t *nonce,
	uint32_t nonce_len,
	const uint8_t *personalization_string,
	uint32_t personalization_string_len,
	int security_strength);

int CTR_DRBG_Reseed(CTR_DRBG_CTX *ctx,
	const uint8_t *entropy_input,
	uint32_t entropy_input_len,
	const uint8_t *additional_input,
	uint32_t additional_input_len);

int CTR_DRBG_Generate(CTR_DRBG_CTX *ctx,
	uint8_t *out, uint32_t bits,
	const uint8_t *additional_input,
	uint32_t additional_input_len);

/* Application can save CTR_DRBG_CTX to a storage (serialization), then
 * restore (deserialization) and continue use it for CTR_DRBG_Generate().
 */
int CTR_DRBG_Serialization(CTR_DRBG_CTX *ctx, uint8_t *out, uint32_t *out_len);
int CTR_DRBG_Deserialization(CTR_DRBG_CTX *ctx, const uint8_t *data, uint32_t len);

/* Size of serialized context */
#define CTR_DRBG_CTX_RAW_SIZE \
	(CTR_DRBG_OUTLEN_BYTES + CTR_DRBG_KEYLEN_BYTES + \
	 sizeof(((CTR_DRBG_CTX *)0)->reseed_counter) + 14)

#endif /* __CTR_DRBG_H_INCLUDED__ */
