/*	$CoreSDI: mkprim.c,v 1.2 2001/12/12 20:35:02 claudio Exp $	*/

/*
 *   Copyright (c) 2000, 2001, Core SDI S.A., Argentina
 *   All rights reserved
 *  
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
 *   are met:
 *  
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *   3. Neither name of the Core SDI S.A. nor the names of its contributors
 *      may be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *  
 *   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 *   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 *   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 *   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * This program prints on standard output a prime number and a generator.
 * Author: Claudio Castiglia <claudio@core-sdi.com>
 *
 * Compiles with:
 *   cc mkprim.c -o mkprim -lcrypto
 */

#include <sys/types.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/bn.h>
#include <openssl/err.h>

#define NUM_BITS	2048


void
print(char *name, unsigned char *p, size_t size)
{
	size_t i;

	printf ("\nstatic const unsigned char %s[] = {\n\t", name);
	for (i = 1; i <= size; i++) {
		printf("0x%02X", p[i-1]);
		if (i < size && i % 8 == 0)
			printf(",\n\t");
		else if (i < size)
			printf(", ");
	}

	printf("\n};\n");
}


int
main()
{
	BN_CTX		ctx;
	BIGNUM		g, p, tmp;
	unsigned char 	str[2048];
	size_t		size;

	ERR_load_crypto_strings();

	BN_CTX_init(&ctx);
	BN_init(&g);
	BN_init(&p);
	BN_init(&tmp);

	printf("Making a %d bits prime number, please wait...\n", NUM_BITS);

	if (BN_generate_prime(&p, NUM_BITS, 1, NULL, NULL, NULL, NULL) == NULL)
		err(-1, "BN_generate_rpime: %s.",
		    ERR_error_string(ERR_get_error(), NULL));

	/* Calculate generator as g = (p * 2 / 3) % p */
	printf("Making a %d bits generator number, please wait...\n", NUM_BITS);
	if (BN_copy(&tmp, &p) == NULL || !BN_mul_word(&tmp, (BN_ULONG)2))
		err(-1, "BN_mul_word: %s.",
		    ERR_error_string(ERR_get_error(), NULL));

	BN_div_word(&tmp, (BN_ULONG)3);
	if (!BN_mod(&g, &tmp, &p, &ctx))
		err(-1, "BN_mod: %s.", ERR_error_string(ERR_get_error(), NULL));

	printf("Verifing prime...");
	if (BN_is_prime(&p, BN_prime_checks_for_size(NUM_BITS),
	    NULL, &ctx, NULL) != 1)
		err(-1, "Number generated not prime!!");

	size = BN_bn2bin(&p, str);
	print("prime", str, size);

	size = BN_bn2bin(&g, str);
	print("generator", str, size);

	BN_free(&g);
	BN_free(&p);
	BN_free(&tmp);
	BN_CTX_free(&ctx);

	ERR_free_strings();

	return (0);
}

