+/* Copyright (c) 1998,2011-2012,2014 Apple 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, INC. AND THE
+ * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE,
+ * 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 at Apple
+ * Mods for variable size giantDigit.
+ * Rewrote serializeGiant(), deserializeGiant() to conform to IEEE P1363.
+ * 23 Mar 98 at Apple
+ * Added FR_WrongSignatureType, FR_BadKeyBlob to frtnStrings.
+ * Added initCryptKit().
+ * 19 Jan 98 at Apple
+ * Added cStringToUc()
+ * 09 Jan 98 at Apple
+ * Added non-FEE_DEBUG version of printGiantHex()
+ * 27 Jan 97 at NeXT
+ * Addd serializeGiant(), deserializeGiant; Deleted data_to_giant()
+ * 12 Dec 96 at NeXT
+ * Added byteRepTo{int,key,giant}().
+ * 2 Aug 96 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(void)
+{
+ #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);
+}
+