ckutilities.c   [plain text]


/* Copyright (c) 1998 Apple Computer, Inc.  All rights reserved.
 *
 * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT
 * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE
 * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE COMPUTER, INC. AND THE
 * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE COMPUTER,
 * INC.  ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL
 * EXPOSE YOU TO LIABILITY.
 ***************************************************************************
 *
 * ckutilities.c - general C routines
 *
 * Revision History
 * ----------------
 * 10/06/98		ap
 *	Changed to compile with C++.
 * 08 Apr 98	Doug Mitchell at Apple
 *	Mods for variable size giantDigit.
 * 	Rewrote serializeGiant(), deserializeGiant() to conform to IEEE P1363.
 * 23 Mar 98	Doug Mitchell at Apple
 *	Added FR_WrongSignatureType, FR_BadKeyBlob to frtnStrings.
 *	Added initCryptKit().
 * 19 Jan 98	Doug Mitchell at Apple
 *	Added cStringToUc()
 * 09 Jan 98	Doug Mitchell at Apple
 *	Added non-FEE_DEBUG version of printGiantHex()
 * 27 Jan 97	Doug Mitchell at NeXT
 *	Addd serializeGiant(), deserializeGiant; Deleted data_to_giant()
 * 12 Dec 96	Doug Mitchell at NeXT
 *	Added byteRepTo{int,key,giant}().
 *  2 Aug 96	Doug Mitchell at NeXT
 *	Broke out from Blaine Garst's original NSCryptors.m
 */

#include "ckutilities.h"
#include "falloc.h"
#include "feeTypes.h"
#include "feeDebug.h"
#include "feeFunctions.h"
#include "byteRep.h"
#include "platform.h"
#include "curveParams.h"
#include <stdlib.h>
#ifdef	NeXT
#include <libc.h>
#include <stdio.h>
#include <signal.h>
#include <sgtty.h>
#endif	// NeXT

/*
 * feeReturn strings.
 */
typedef struct {
	feeReturn	frtn;
	const char	*frtnString;
} frtnItem;

static const frtnItem frtnStrings[] = {
#ifndef	NDEBUG
	{ FR_Success,				"Success"					},
	{ FR_BadPubKey,				"Bad Public Key"			},
	{ FR_BadPubKeyString,		"Bad Public Key String"		},
	{ FR_IncompatibleKey,		"Incompatible key format"	},
	{ FR_IllegalDepth,			"Illegal Depth"				},
	{ FR_BadUsageName,			"Bad Usage Name"			},
	{ FR_BadSignatureFormat, 	"Bad Signature Format"		},
	{ FR_InvalidSignature,		"Invalid Signature"			},
	{ FR_IllegalArg,			"Illegal Argument" 			},
	{ FR_BadCipherText,			"Bad Ciphertext Format"		},
	{ FR_Unimplemented,			"Unimplemented Function"	},
	{ FR_BadCipherFile,			"Bad CipherFile Format"		},
	{ FR_BadEnc64,				"Bad enc64 Format"			},
	{ FR_WrongSignatureType, 	"Wrong Signature Type"		},
	{ FR_BadKeyBlob,			"Bad Key Blob"				},
	{ FR_IllegalCurve,			"Bad curve type"			},
	{ FR_Internal,				"Internal Library Error"	},
	{ FR_Memory, 				"Out of Memory"				},
	{ FR_ShortPrivData,			"Insufficient Seed Data" 	},
#endif	/* NDEBUG */
	{ (feeReturn) 0,			NULL						},
};

/*
 * One-time only init of CryptKit library.
 */
void initCryptKit(void)
{
	#if		GIANTS_VIA_STACK
	curveParamsInitGiants();
	#endif
}

/*
 * Shutdown.
 */
void terminateCryptKit()
{
	#if		GIANTS_VIA_STACK
	freeGiantStacks();
	#endif
}

/*
 * Create a giant, initialized with specified char[] data.
 */
giant giant_with_data(const unsigned char *d, int len) {
    int numDigits = BYTES_TO_GIANT_DIGITS(len);
    giant result;

    result = newGiant(numDigits);
    deserializeGiant(d, result, len);
    return result;
}

/*
 * Obtain a malloc'd memory chunk init'd with specified giant's data.
 * Resulting bytes are portable. Size of malloc'd memory is always zero
 * mod GIANT_BYTES_PER_DIGIT.
 *
 * Calling this function for a giant obtained by giant_with_data() yields
 * the original data, with extra byte(s) of leading zeros if the original
 * was not zero mod GIANT_BYTES_PER_DIGIT.
 */
unsigned char *mem_from_giant(giant g,
	unsigned *memLen)		/* RETURNED size of malloc'd region */
{
	unsigned char *cp;
	unsigned numDigits = (g->sign < 0) ? -g->sign : g->sign;

	*memLen = numDigits * GIANT_BYTES_PER_DIGIT;
	cp = (unsigned char*) fmalloc(*memLen);
	serializeGiant(g, cp, *memLen);
	return cp;
}

extern const char *feeReturnString(feeReturn frtn)
{
	const frtnItem *fi = frtnStrings;

	while(fi->frtnString) {
		if(fi->frtn == frtn) {
			return fi->frtnString;
		}
		fi++;
	}
	return "Unknown Status";
}

#if		FEE_DEBUG
void printGiant(const giant x)
{
	int i;

	printf("sign=%d cap=%d n[]=", x->sign, x->capacity);
	for(i=0; i<abs(x->sign); i++) {
		printf("%u:", x->n[i]);
	}
	printf("\n");
}

void printGiantHex(const giant x)
{
	int i;

	printf("sign=%d cap=%d n[]=", x->sign, x->capacity);
	for(i=0; i<abs(x->sign); i++) {
		printf("%x:", x->n[i]);
	}
	printf("\n");
}

/*
 * Print in the form
 *   sign=8 cap=16 n[]=29787 + 3452 * w^1 + 55260 * w^2  + ...
 */
void printGiantExp(const giant x)
{
	int i;
	int size = abs(x->sign);

	printf("sign=%d cap=%d n[]=", x->sign, x->capacity);
	for(i=0; i<size; i++) {
		printf("%u ", x->n[i]);
		if(i > 0) {
			printf("* w^%d ", i);
		}
		if(i<(size-1)) {
			printf("+ ");
		}
	}
	printf("\n");
}

void printKey(const key k)
{
	printf("  twist %d\n", k->twist);
	printf("  x: ");
	printGiant(k->x);
}

void printCurveParams(const curveParams *p)
{
	const char *pt;
	const char *ct;
	
	switch(p->primeType) {
	    case FPT_Mersenne:
	    	pt = "FPT_Mersenne";
		break;
	    case FPT_FEE:
	    	pt = "FPT_FEE";
		break;
	    case FPT_General:
	    	pt = "FPT_General";
		break;
	    default:
	    	pt = "UNKNOWN!";
		break;
	}
	switch(p->curveType) {
		case FCT_Montgomery:
			ct = "FCT_Montgomery";
			break;
		case FCT_Weierstrass:
			ct = "FCT_Weierstrass";
			break;
		case FCT_General:
			ct = "FCT_General";
			break;
	    default:
	    	ct = "UNKNOWN!";
			break;
	}
	printf("  q %d   k %d   primeType %s  curveType %s\n",
		p->q, p->k, pt, ct);
	printf("  minBytes %d  maxDigits %d\n", p->minBytes, p->maxDigits);
	printf("  a           : ");
	printGiant(p->a);
	printf("  b           : ");
	printGiant(p->b);
	printf("  c           : ");
	printGiant(p->c);
	printf("  basePrime   : ");
	printGiant(p->basePrime);
	printf("  x1Plus      : ");
	printGiant(p->x1Plus);
	printf("  x1Minus     : ");
	printGiant(p->x1Minus);
	printf("  cOrderPlus  : ");
	printGiant(p->cOrderPlus);
	printf("  cOrderMinus : ");
	printGiant(p->cOrderMinus);
	printf("  x1OrderPlus : ");
	printGiant(p->x1OrderPlus);
	printf("  x1OrderMinus: ");
	printGiant(p->x1OrderMinus);
}
#else
void printGiant(const giant x) {}
void printGiantHex(const giant x) {}
void printGiantExp(const giant x) {}
void printKey(const key k) {}
void printCurveParams(const curveParams *p) {}

#endif	/* FEE_DEBUG */

#if	defined(NeXT) && !defined(WIN32)

void getpassword(const char *prompt, char *pbuf)
{
        struct sgttyb ttyb;
        int flags;
        register char *p;
        register int c;
        FILE *fi;
        void (*sig)(int);

        if ((fi = fdopen(open("/dev/tty", 2, 0), "r")) == NULL)
                fi = stdin;
        else
                setbuf(fi, (char *)NULL);
        sig = signal(SIGINT, SIG_IGN);
        ioctl(fileno(fi), TIOCGETP, &ttyb);
        flags = ttyb.sg_flags;
        ttyb.sg_flags &= ~ECHO;
        ioctl(fileno(fi), TIOCSETP, &ttyb);
        fprintf(stderr, "%s", prompt); fflush(stderr);
        for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) {
                if (p < &pbuf[PHRASELEN-1])
                        *p++ = c;
        }
        *p = '\0';
        fprintf(stderr, "\n"); fflush(stderr);
        ttyb.sg_flags = flags;
        ioctl(fileno(fi), TIOCSETP, &ttyb);
        (void)signal(SIGINT, sig);
        if (fi != stdin)
                fclose(fi);
}
#endif	// NeXT

/*
 * serialize, deserialize giants's n[] to/from byte stream.
 * First byte of byte stream is the MS byte of the resulting giant,
 * regardless of the size of giantDigit.
 *
 * No assumption is made about the alignment of cp.
 *
 * As of 7 Apr 1998, these routines are in compliance with IEEE P1363,
 * section 5.5.1, for the representation of a large integer as a byte
 * stream.
 */
void serializeGiant(giant g,
	unsigned char *cp,
	unsigned numBytes)
{
	unsigned	digitDex;
	unsigned 	numDigits = BYTES_TO_GIANT_DIGITS(numBytes);
	giantDigit 	digit;
	unsigned char 	*ptr;
	unsigned	digitByte;
	int 		size = abs(g->sign);

	if(numBytes == 0) {
		return;
	}
	if(numBytes > (g->capacity * GIANT_BYTES_PER_DIGIT)) {
		CKRaise("serializeGiant: CAPACITY EXCEEDED!\n");
	}

	/*
	 * note we might be asked to write more than the valid number
	 * if bytes in the giant in the case if truncated sign due to
	 * zero M.S. digit(s)....
	 */

	/*
	 * zero out unused digits so we can infer sign during deserialize
	 */
	for(digitDex=size; digitDex<numDigits; digitDex++) {
		g->n[digitDex] = 0;
	}

	/*
	 * Emit bytes starting from l.s. byte. L.s. byte of the outgoing
	 * data stream is *last*. L.s. digit of giant's digits is *first*.
	 */
	digitDex = 0;
	ptr = &cp[numBytes - 1];
	do {
	    /* one loop per giant digit */
	    digit = g->n[digitDex++];
	    for(digitByte=0; digitByte<GIANT_BYTES_PER_DIGIT; digitByte++) {
	        /* one loop per byte in the digit */
	    	*ptr-- = (unsigned char)digit;
			if(--numBytes == 0) {
				break;
			}
			digit >>= 8;
	    }
	} while(numBytes != 0);

}

/*
 * Resulting sign here is always positive; leading zeroes are reflected
 * in an altered g->sign.
 */
void deserializeGiant(const unsigned char *cp,
	giant g,
	unsigned numBytes)
{
	unsigned 		numDigits;
	giantDigit 		digit;
	int				digitDex;
	unsigned		digitByte;
	const unsigned char 	*ptr;

	if(numBytes == 0) {
		g->sign = 0;
		return;
	}
	numDigits = (numBytes + GIANT_BYTES_PER_DIGIT - 1) /
			GIANT_BYTES_PER_DIGIT;
	if(numBytes > (g->capacity * GIANT_BYTES_PER_DIGIT)) {
		CKRaise("deserializeGiant: CAPACITY EXCEEDED!\n");
	}

	/*
	 * Start at l.s. byte. That's the end of the cp[] array and
	 * the beginning of the giantDigit array.
	 */
	digitDex = 0;
	ptr = &cp[numBytes - 1];
	do {
	    /* one loop per digit */
	    digit = 0;
	    for(digitByte=0; digitByte<GIANT_BYTES_PER_DIGIT; digitByte++) {
	        /* one loop per byte in the digit */
		digit |= (*ptr-- << (8 * digitByte));
		/* FIXME - shouldn't we update g->n before this break? */
		if(--numBytes == 0) {
		    break;
		}
	    }
	    g->n[digitDex++] = digit;
	} while (numBytes != 0);

	/*
	 * Infer sign from non-zero n[] elements
	 */
	g->sign = numDigits;
	gtrimSign(g);
}