/* -----------------------------------------------------------------------
 *
 * Copyright (c) 2008 EURL Cryptographie Ingénierie et Conseil <ecctk@cryptograph-ic.com>, AIX-NOULETTE, FRANCE
 *
 * Termes :
 *
 * L'utilisation et/ou la redistribution de ce code (avec ou sans modification),
 * ainsi que de tous les composants du produit (librairies, documentation, exemples, ...)
 * est soumise aux termes de la licence qui vous est attribuée par son auteur.
 *
 * -----------------------------------------------------------------------
 */

#include <stdlib.h>
#include <stdio.h>

#include <include/ecctk-prototype.h>
#include <include/ecctk-ecc.h>

#define MAX_KEY_PAIR	4

s2byte key_agreement()
{
	s2byte	ret		= -1,
			i,
			key_pair_number;

	/* set key agreement algorithm
	 */
	s2byte	algo	= ECCTK_ECC_ALGO_MQVKA;

	/* set input/output file name
	 */
	s1byte	*kpubfile[MAX_KEY_PAIR] = { "public_key_file1",  "public_key_file2",
										"public_key_file3",  "public_key_file4"},
			*kprvfile[MAX_KEY_PAIR] = { "private_key_file1", "private_key_file2",
										"private_key_file3", "private_key_file4"};

	/* key agreement context
	 */
	KA_CTX	*ka1 = NULL,
			*ka2 = NULL;

	/* public key context
	 */
	KPUB_CTX	*kpub[MAX_KEY_PAIR] = {NULL, NULL, NULL, NULL};

	/* private key context
	 */
	KPRV_CTX	*kprv[MAX_KEY_PAIR] = {NULL, NULL, NULL, NULL};

	/* read public and private key
	 * number depend of KA algorithm
	 */
	switch (algo)
	{
	case ECCTK_ECC_ALGO_DHKA:
		key_pair_number = 2;
		break;
	case ECCTK_ECC_ALGO_MQVKA:
		key_pair_number = 4;
		break;
	default:
		fprintf(stderr, "Unknown key agreement algorithm\n");
		return EXIT_FAILURE;
	}

	/* Initialize value for all curve in memory
	 */
	ret = InitializeEcctkAll();
	if (ret != ECCTK_ECC_NO_ERROR)
	{
		fprintf(stderr, "InitializeEcctkAll failed (%d)\n", ret);
		return EXIT_FAILURE;
	}

	/* read key pair values on file
	 * all private key are not password-protected
	 */
	for (i = 0; i < key_pair_number; i++)
	{
		kpub[i] = ReadFileKpubCtx(kpubfile[i]);
		if (kpub[i] == NULL)
		{
			fprintf(stderr, "Read public key on %s failed\n", kpubfile[i]);
			goto kaend;
		}

		kprv[i] = ReadFileKprvCtx(kprvfile[i]);
		if (kprv[i] == NULL)
		{
			fprintf(stderr, "Read private key on %s failed\n", kprvfile[i]);
			goto kaend;
		}
	}

	switch (algo)
	{
		case ECCTK_ECC_ALGO_DHKA:
			ka1 = CreateDHKeyAgreement(kpub[0], kprv[1], NULL);
			if (ka1 == NULL)
			{
				fprintf(stderr, "Create first key agreement value failed\n");
				goto kaend;
			}

			ka2 = CreateDHKeyAgreement(kpub[1], kprv[0], NULL);
			if (ka2 == NULL)
			{
				fprintf(stderr, "Create second key agreement value failed\n");
				goto kaend;
			}
			break;

		case ECCTK_ECC_ALGO_MQVKA:
			ka1 = CreateMQVKeyAgreement(kprv[0], kprv[1], kpub[1], kpub[2], kpub[3], NULL, NULL);
			if (ka1 == NULL)
			{
				fprintf(stderr, "Create first key agreement value failed\n");
				goto kaend;
			}
		
			ka2 = CreateMQVKeyAgreement(kprv[2], kprv[3], kpub[3], kpub[0], kpub[1], NULL, NULL);
			if (ka2 == NULL)
			{
				fprintf(stderr, "Create second key agreement value failed\n");
				goto kaend;
			}
			break;
	}

	ret = VerifyKeyAgreement(ka1, ka2);
	if (ret != ECCTK_ECC_NO_ERROR)
	{
		fprintf(stderr, "Verify Key Agreement failed (Error : %d)\n", ret);
		ret = EXIT_FAILURE;
	}
	else
	{
		fprintf(stderr, "Verify Key Agreement success\n");
		ret = EXIT_SUCCESS;
	}

kaend:
	if (ka1 != NULL)
		KaCtxFree(ka1);

	if (ka2 != NULL)
		KaCtxFree(ka2);

	/* free context
	 */
	for(i = 0; i < key_pair_number; i++)
	{
		if (kpub[i] != NULL)
			KpubCtxFree(kpub[i]);

		if (kprv[i] != NULL)
			KprvCtxFree(kprv[i]);
	}

	/* remove value for all curve in memory
	 */
	FreeEcctkAll();

	return ret;
}
