/* $Id: t_mpRSA508.c $ */

/******************** SHORT COPYRIGHT NOTICE**************************
This source code is part of the BigDigits multiple-precision
arithmetic library Version 2.1 originally written by David Ireland,
copyright (c) 2001-6 D.I. Management Services Pty Limited, all rights
reserved. It is provided "as is" with no warranties. You may use
this software under the terms of the full copyright notice
"bigdigitsCopyright.txt" that should have been included with this
library or can be obtained from <www.di-mgt.com.au/bigdigits.html>.
This notice must always be retained in any copy.
******************* END OF COPYRIGHT NOTICE***************************/
/*
	Last updated:
	$Date: 2006-08-23 11:13:00 $
	$Revision: 2.1.0 $
	$Author: dai $
*/

/* Test vector using BIGDIGITS to show RSA encryption 
and signature using 508-bit test vectors from 
"Some Examples of the PKCS Standards"
An RSA Laboratories Technical Note
Burton S. Kaliski Jr.
Revised November 1, 1993
*/

/* ---
From the document:-
In the example, the modulus n is the following 508-bit
integer:

n = 0a 66 79 1d c6 98 81 68 de 7a b7 74 19 bb 7f b0 c0 01 c6
27 10 27 00 75 14 29 42 e1 9a 8d 8c 51 d0 53 b3 e3 78 2a 1d
e5 dc 5a f4 eb e9 94 68 17 01 14 a1 df e6 7c dc 9a 9a f5 5d
65 56 20 bb ab

The public exponent e is F4 (65537):

e = 01 00 01

The private exponent d:

d = 01 23 c5 b6 1b a3 6e db 1d 36 79 90 41 99 a8 9e a8 0c 09
b9 12 2e 14 00 c0 9a dc f7 78 46 76 d0 1d 23 35 6a 7d 44 d6
bd 8b d5 0e 94 bf c7 23 fa 87 d8 86 2b 75 17 76 91 c1 1d 75
76 92 df 88 81

RSA encryption according to PKCS #1 has two general steps:
An encryption block is constructed from a block type, a
padding string, and the prefixed message digest; then the
encryption block is exponentiated with Test User 1's private
exponent.

The encryption block EB is the following 64-octet string:

00
01                                               block type
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff padding string
ff ff ff ff ff ff ff ff ff ff ff
00                                              00 separator
30 20
   30 0c                                     digestAlgorithm
      06 08 2a 86 48 86 f7 0d 02 02          algorithm = md2
      05 00                                parameters = NULL
   04 10                                              digest
      dc a9 ec f1 c1 5c 1b d2 66 af f9 c8 79 93 65 cd

i.e. the 64-octet string:
00 01 ff ff ff ff ff ff ff ff ff ff ff ff ff ff
ff ff ff ff ff ff ff ff ff ff ff ff ff 00 30 20
30 0c 06 08 2a 86 48 86 f7 0d 02 02 05 00 04 10
dc a9 ec f1 c1 5c 1b d2 66 af f9 c8 79 93 65 cd

The resulting encrypted message digest (the signature) is
the following 64-octet string:

06 db 36 cb 18 d3 47 5b 9c 01 db 3c 78 95 28 08
02 79 bb ae ff 2b 7d 55 8e d6 61 59 87 c8 51 86
3f 8a 6c 2c ff bc 89 c3 f7 5a 18 d9 6b 12 7c 71
7d 54 d0 d8 04 8d a8 a0 54 46 26 d1 7a 2a 8f be

*/

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "bigdigits.h"

#define MOD_SIZE 16	/* max 512-bits */


void pr_bytes(unsigned char *b, size_t nbytes)
{
	size_t i;

	for (i = 0; i < nbytes; i++)
	{
		if (i && (i % 16 == 0)) printf("\n");
		printf("%02x ", b[i]);
	}
	printf("\n");
}

int main(void)
{
	DIGIT_T n[MOD_SIZE], e[MOD_SIZE], d[MOD_SIZE];
	DIGIT_T  s[MOD_SIZE], m[MOD_SIZE], m1[MOD_SIZE], s1[MOD_SIZE];
	size_t nbytes;
	char decimal[MOD_SIZE*4];

	/* Data in big-endian byte format:- 
	*/
	unsigned char nn[] = {
		0x0A, 0x66, 0x79, 0x1D, 0xC6, 0x98, 0x81, 0x68, 
		0xDE, 0x7A, 0xB7, 0x74, 0x19, 0xBB, 0x7F, 0xB0, 
		0xC0, 0x01, 0xC6, 0x27, 0x10, 0x27, 0x00, 0x75, 
		0x14, 0x29, 0x42, 0xE1, 0x9A, 0x8D, 0x8C, 0x51, 
		0xD0, 0x53, 0xB3, 0xE3, 0x78, 0x2A, 0x1D, 0xE5, 
		0xDC, 0x5A, 0xF4, 0xEB, 0xE9, 0x94, 0x68, 0x17, 
		0x01, 0x14, 0xA1, 0xDF, 0xE6, 0x7C, 0xDC, 0x9A, 
		0x9A, 0xF5, 0x5D, 0x65, 0x56, 0x20, 0xBB, 0xAB,
	};

	unsigned char ee[] = { 0x01, 0x00, 0x01 };

	unsigned char dd[] = {
		0x01, 0x23, 0xC5, 0xB6, 0x1B, 0xA3, 0x6E, 0xDB, 
		0x1D, 0x36, 0x79, 0x90, 0x41, 0x99, 0xA8, 0x9E, 
		0xA8, 0x0C, 0x09, 0xB9, 0x12, 0x2E, 0x14, 0x00, 
		0xC0, 0x9A, 0xDC, 0xF7, 0x78, 0x46, 0x76, 0xD0, 
		0x1D, 0x23, 0x35, 0x6A, 0x7D, 0x44, 0xD6, 0xBD, 
		0x8B, 0xD5, 0x0E, 0x94, 0xBF, 0xC7, 0x23, 0xFA, 
		0x87, 0xD8, 0x86, 0x2B, 0x75, 0x17, 0x76, 0x91, 
		0xC1, 0x1D, 0x75, 0x76, 0x92, 0xDF, 0x88, 0x81,
	};

	unsigned char mm[] = {
		0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x30, 0x20, 
		0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 
		0xF7, 0x0D, 0x02, 0x02, 0x05, 0x00, 0x04, 0x10, 
		0xDC, 0xA9, 0xEC, 0xF1, 0xC1, 0x5C, 0x1B, 0xD2, 
		0x66, 0xAF, 0xF9, 0xC8, 0x79, 0x93, 0x65, 0xCD,
	};

	unsigned char ss[] = {
		0x06, 0xDB, 0x36, 0xCB, 0x18, 0xD3, 0x47, 0x5B, 
		0x9C, 0x01, 0xDB, 0x3C, 0x78, 0x95, 0x28, 0x08, 
		0x02, 0x79, 0xBB, 0xAE, 0xFF, 0x2B, 0x7D, 0x55, 
		0x8E, 0xD6, 0x61, 0x59, 0x87, 0xC8, 0x51, 0x86, 
		0x3F, 0x8A, 0x6C, 0x2C, 0xFF, 0xBC, 0x89, 0xC3, 
		0xF7, 0x5A, 0x18, 0xD9, 0x6B, 0x12, 0x7C, 0x71, 
		0x7D, 0x54, 0xD0, 0xD8, 0x04, 0x8D, 0xA8, 0xA0, 
		0x54, 0x46, 0x26, 0xD1, 0x7A, 0x2A, 0x8F, 0xBE,
	};

	printf("Test BIGDIGITS using 508-bit RSA key from 'Some Examples of the PKCS Standards'\n");

	/* Convert bytes to BIGDIGITS */
	mpConvFromOctets(n, MOD_SIZE, nn, sizeof(nn));
	mpConvFromOctets(e, MOD_SIZE, ee, sizeof(ee));
	mpConvFromOctets(d, MOD_SIZE, dd, sizeof(dd));
	mpConvFromOctets(m, MOD_SIZE, mm, sizeof(mm));
	mpConvFromOctets(s1, MOD_SIZE, ss, sizeof(ss));


	printf("n ="); mpPrintNL(n, MOD_SIZE);
	printf("e ="); mpPrintNL(e, MOD_SIZE);
	printf("d ="); mpPrintNL(d, MOD_SIZE);
	printf("m ="); mpPrintNL(m, MOD_SIZE);

	/* Sign, i.e. Encrypt with private key, s = m^d mod n */
	mpModExp(s, m, d, n, MOD_SIZE);

	printf("s ="); mpPrintNL(s, MOD_SIZE);

	/* Did we get the same answer as expected? */
	if (!mpEqual(s1, s, MOD_SIZE))
		printf("<= ERROR - no match\n");
	else
		printf("<= OK\n");
	assert(mpEqual(s1, s, MOD_SIZE));

	/* Verify, i.e. Decrypt with public key m' = s^e mod n */
	mpModExp(m1, s, e, n, MOD_SIZE);

	printf("m'="); mpPrintNL(m1, MOD_SIZE);

	/* Check that we got back where we started */
	if (!mpEqual(m1, m, MOD_SIZE)) 
		printf("<= ERROR - no match\n");
	else
		printf("<= OK\n");
	assert(mpEqual(m1, m, MOD_SIZE));

	/* Now convert back to octets (bytes) */
	memset(mm, 0, sizeof(mm)); 
	nbytes = mpConvToOctets(m, MOD_SIZE, mm, sizeof(mm));
	printf("%d non-zero bytes converted from m:\n", nbytes);
	pr_bytes(mm, sizeof(mm));

	memset(ee, 0, sizeof(ee)); 
	nbytes = mpConvToOctets(e, MOD_SIZE, ee, sizeof(ee));
	printf("%d non-zero bytes converted from e:\n", nbytes);
	pr_bytes(ee, sizeof(ee));

	/* Do a conversion to decimal */
	nbytes = mpConvToDecimal(e, MOD_SIZE, decimal, sizeof(decimal));
	printf("%d non-zero decimal digits converted from e:\n", nbytes);
	printf("%s\n", decimal);
	assert(strcmp(decimal, "65537") == 0);

	printf("OK, successfully completed tests.\n");

	return 0;
}

