+/* Copyright (c) 1998,2011,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.
+ ***************************************************************************
+ *
+ * byteRep.c - FEE portable byte representation support
+ *
+ * Revision History
+ * ----------------
+ * 10/06/98 ap
+ * Changed to compile with C++.
+ * 18 Apr 98 at Apple
+ * Mods for variable size giantDigit.
+ * 20 Jan 98 at Apple
+ * Added curve param fields for CURVE_PARAM_VERSION 2.
+ * 17 Jul 97 at Apple
+ * Added signature routines.
+ * 9 Jan 97 at NeXT
+ * Split off from utilities.c
+ */
+
+#include "byteRep.h"
+#include "feeTypes.h"
+#include "curveParams.h"
+#include "giantIntegers.h"
+#include "elliptic.h"
+#include "falloc.h"
+#include "ckutilities.h"
+#include "feeDebug.h"
+#include <stdlib.h>
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif /* NULL */
+
+/*
+ * Support for portable bytestream representation of keys and signatures.
+ * Platform and endianness independent; format shared with JavaFEE
+ * implementation.
+ */
+
+/*
+ * Some handy macros.
+ */
+#define ENC_BYTE(n, b, bytes) \
+ *b++ = n; \
+ bytes++;
+
+#define ENC_INT(n, b, bytes, i) \
+ i = intToByteRep(n, b); \
+ bytes += i; \
+ b += i;
+
+#define ENC_GIANT(g, b, bytes, i) \
+ i = giantToByteRep(g, b); \
+ bytes += i; \
+ b += i;
+
+#define DEC_BYTE(n, b, blen, bytes) \
+ n = *b++; \
+ bytes++; \
+ blen--;
+
+#define DEC_INT(n, b, blen, bytes) \
+ n = byteRepToInt(b); \
+ b += sizeof(int); \
+ bytes += sizeof(int); \
+ blen -= gLen;
+
+#define DEC_GIANT(g, b, blen, glen, bytes, out) \
+ g = byteRepToGiant(b, blen, &glen); \
+ if(g == NULL) { \
+ goto out; \
+ } \
+ b += glen; \
+ bytes += glen; \
+ blen -= gLen;
+
+
+
+
+/*
+ * The routines which convert various types to byte reps return the number
+ * of bytes written to the output stream.
+ */
+int intToByteRep(int i, unsigned char *buf)
+{
+ *buf++ = (unsigned char)((i >> 24) & 0xff);
+ *buf++ = (unsigned char)((i >> 16) & 0xff);
+ *buf++ = (unsigned char)((i >> 8) & 0xff);
+ *buf = (unsigned char)(i & 0xff);
+ return 4;
+}
+
+int shortToByteRep(short s, unsigned char *buf)
+{
+ *buf++ = (unsigned char)((s >> 8) & 0xff);
+ *buf = (unsigned char)(s & 0xff);
+ return 2;
+}
+
+/*
+ * 7 Apr 1998 : leading int is now the number of bytes in the giant's
+ * giantDigits array. This value is signed.
+ */
+int giantToByteRep(giant g, unsigned char *buf)
+{
+ int numBytes = g->sign * GIANT_BYTES_PER_DIGIT;
+ unsigned aNumBytes = abs(numBytes);
+
+ CKASSERT(g != NULL);
+ intToByteRep(numBytes, buf);
+ buf += sizeof(int);
+ serializeGiant(g, buf, aNumBytes);
+ return (sizeof(int) + aNumBytes);
+}
+
+int keyToByteRep(key k, unsigned char *buf)
+{
+ int numBytes = 0;
+ int i;
+
+ CKASSERT(k != NULL);
+ ENC_GIANT(k->x, buf, numBytes, i);
+
+ /* only write y for plus curve */
+ if(k->twist == CURVE_PLUS) {
+ CKASSERT(k->y != NULL);
+ ENC_GIANT(k->y, buf, numBytes, i);
+ }
+ return numBytes;
+}
+
+#define CURVE_PARAM_VERSION 3
+#define CURVE_PARAM_VERSION_MIN 3
+
+int curveParamsToByteRep(curveParams *cp, unsigned char *buf)
+{
+ int numBytes = 0;
+ int i;
+
+ CKASSERT(cp != NULL);
+ ENC_INT(CURVE_PARAM_VERSION, buf, numBytes, i);
+ ENC_INT(CURVE_PARAM_VERSION_MIN, buf, numBytes, i);
+ ENC_BYTE(cp->primeType, buf, numBytes);
+ ENC_BYTE(cp->curveType, buf, numBytes);
+ ENC_INT(cp->q, buf, numBytes, i);
+ ENC_INT(cp->k, buf, numBytes, i);
+ ENC_INT(cp->m, buf, numBytes, i);
+ ENC_INT(0, buf, numBytes, i); // spare
+
+ ENC_GIANT(cp->a, buf, numBytes, i);
+ ENC_GIANT(cp->b, buf, numBytes, i);
+ ENC_GIANT(cp->c, buf, numBytes, i);
+ ENC_GIANT(cp->x1Plus, buf, numBytes, i);
+ ENC_GIANT(cp->x1Minus, buf, numBytes, i);
+ ENC_GIANT(cp->cOrderPlus, buf, numBytes, i);
+ ENC_GIANT(cp->cOrderMinus, buf, numBytes, i);
+ ENC_GIANT(cp->x1OrderPlus, buf, numBytes, i);
+ ENC_GIANT(cp->x1OrderMinus, buf, numBytes, i);
+ if(cp->primeType == FPT_General) {
+ ENC_GIANT(cp->basePrime, buf, numBytes, i);
+ }
+ return numBytes;
+}
+
+int sigToByteRep(int magic,
+ int version,
+ int minVersion,
+ giant g0,
+ giant g1,
+ unsigned char *buf)
+{
+ int numBytes = 0;
+ int i;
+
+ ENC_INT(magic, buf, numBytes, i);
+ ENC_INT(version, buf, numBytes, i);
+ ENC_INT(minVersion, buf, numBytes, i);
+ ENC_INT(0, buf, numBytes, i); // spare
+ ENC_GIANT(g0, buf, numBytes, i);
+ ENC_GIANT(g1, buf, numBytes, i);
+
+ return numBytes;
+}
+
+
+/*
+ * return the size of various data types' byte representations.
+ */
+int lengthOfByteRepGiant(giant g)
+{
+ CKASSERT(g != NULL);
+ return sizeof(int) + (GIANT_BYTES_PER_DIGIT * abs(g->sign));
+}
+
+int lengthOfByteRepKey(key k)
+{
+ int len = lengthOfByteRepGiant(k->x);
+
+ CKASSERT(k != NULL);
+ if(k->twist == CURVE_PLUS) {
+ CKASSERT(k->y != NULL);
+ len += lengthOfByteRepGiant(k->y);
+ }
+ return len;
+}
+
+int lengthOfByteRepCurveParams(curveParams *cp)
+{
+ int length;
+
+ CKASSERT(cp != NULL);
+ length = (6 * sizeof(int)) + // ver, minVers, q, k, m, spare
+ 2 + // primeType + curveType
+ lengthOfByteRepGiant(cp->a) +
+ lengthOfByteRepGiant(cp->b) +
+ lengthOfByteRepGiant(cp->c) +
+ lengthOfByteRepGiant(cp->x1Plus) +
+ lengthOfByteRepGiant(cp->x1Minus) +
+ lengthOfByteRepGiant(cp->cOrderPlus) +
+ lengthOfByteRepGiant(cp->cOrderMinus) +
+ lengthOfByteRepGiant(cp->x1OrderPlus) +
+ lengthOfByteRepGiant(cp->x1OrderMinus);
+ if(cp->primeType == FPT_General) {
+ length += lengthOfByteRepGiant(cp->basePrime);
+ }
+ return length;
+}
+
+int lengthOfByteRepSig(giant g0,
+ giant g1)
+{
+ int length = (4 * sizeof(int)) + // magic, version, minVersion,
+ // spare
+ lengthOfByteRepGiant(g0) +
+ lengthOfByteRepGiant(g1);
+ return length;
+}
+
+/*
+ * Routine to cons up various types from a byte rep stream.
+ */
+int byteRepToInt(const unsigned char *buf) {
+ int result;
+
+ result = (((int)buf[0] << 24) & 0xff000000) |
+ (((int)buf[1] << 16) & 0x00ff0000) |
+ (((int)buf[2] << 8) & 0xff00) |
+ (((int)buf[3]) & 0xff);
+ return result;
+}
+
+unsigned short byteRepToShort(const unsigned char *buf) {
+ unsigned short result;
+
+ result = (((unsigned short)buf[0] << 8) & 0xff00) |
+ (((unsigned short)buf[1]) & 0xff);
+ return result;
+}
+
+/*
+ * Probably need byteRepToShortArray...
+ */
+
+/*
+ * byte rep stream to giant. Returns NULL on error; returns number of bytes
+ * of *buf snarfed in *giantLen if successful.
+ *
+ * 7 Apr 1998 : leading int is now the number of bytes in the giant's
+ * giantDigits array. This value is signed.
+ */
+giant byteRepToGiant(const unsigned char *buf,
+ unsigned bufLen,
+ unsigned *giantLen)
+{
+ giant g;
+ int numDigits;
+ int numBytes; // signed!
+ unsigned aNumBytes;
+
+ if(bufLen < sizeof(int)) {
+ return (giant)NULL;
+ }
+ numBytes = byteRepToInt(buf);
+ aNumBytes = abs(numBytes);
+ numDigits = BYTES_TO_GIANT_DIGITS(aNumBytes);
+ buf += sizeof(int);
+ bufLen -= sizeof(int);
+ if(numDigits > MAX_DIGITS) {
+ return (giant)NULL;
+ }
+
+ if(bufLen < aNumBytes) {
+ return (giant)NULL;
+ }
+
+ /* 9 Apr 1998 - sign = 0 means no following n[] bytes in the
+ * byteRep. We do need to alloc one digit, in this case, though...
+ * Note that the giantstruct has one implicit digit in n[].
+ */
+ if(aNumBytes == 0) {
+ g = (giant)fmalloc(sizeof(giantstruct));
+ g->capacity = 1;
+ }
+ else {
+ g = (giant)fmalloc(sizeof(giantstruct) +
+ aNumBytes - GIANT_BYTES_PER_DIGIT);
+ g->capacity = numDigits;
+ }
+ deserializeGiant(buf, g, aNumBytes);
+
+ /* deserializeGiant always cooks up positive giant; sign is
+ * properly trimmed to handle trailing (M.S.) zeroes. */
+ if(numBytes < 0) {
+ g->sign = -g->sign;
+ }
+ *giantLen = sizeof(int) + aNumBytes;
+ return g;
+
+}
+
+/*
+ * Convert a byte stream (and some other parameters) into a
+ * keystruct.
+ * Returns NULL on error; returns number of bytes of *buf snarfed in
+ * *keyLen if successful.
+ */
+key byteRepToKey(const unsigned char *buf,
+ unsigned bufLen,
+ int twist,
+ curveParams *cp,
+ unsigned *keyLen) // returned
+{
+ key k;
+ giant x;
+ giant y;
+ unsigned gLen;
+ unsigned totalLen;
+
+ x = byteRepToGiant(buf, bufLen, &gLen);
+ if(x == NULL) {
+ return NULL;
+ }
+ bufLen -= gLen;
+ buf += gLen;
+ totalLen = gLen;
+ if(twist == CURVE_PLUS) {
+ /* this also contains y */
+ y = byteRepToGiant(buf, bufLen, &gLen);
+ if(y == NULL) {
+ freeGiant(x);
+ return NULL;
+ }
+ totalLen += gLen;
+ }
+ else {
+ /* minus curve, y is not used */
+ y = newGiant(1);
+ int_to_giant(0, y);
+ }
+ k = (key)fmalloc(sizeof(keystruct));
+ k->twist = twist;
+ k->cp = cp;
+ k->x = x;
+ k->y = y;
+ *keyLen = totalLen;
+ return k;
+}
+
+curveParams *byteRepToCurveParams(const unsigned char *buf,
+ unsigned bufLen,
+ unsigned *cpLen)
+{
+ curveParams *cp;
+ unsigned gLen = 0;
+ int version;
+ int minVersion;
+ int spare;
+ int bytes = 0;
+
+ if(bufLen < (5 * sizeof(int))) { // ver, minVers, q, k, spare
+ return NULL;
+ }
+ cp = newCurveParams();
+
+ DEC_INT(version, buf, bufLen, bytes);
+ DEC_INT(minVersion, buf, bufLen, bytes);
+ if(minVersion > CURVE_PARAM_VERSION) {
+ /*
+ * Can't parse this; things have changed too much between
+ * this version of the code and the time this curveParams
+ * was written.
+ */
+ goto abort;
+ }
+
+ DEC_BYTE(cp->primeType, buf, bufLen, bytes);
+ DEC_BYTE(cp->curveType, buf, bufLen, bytes);
+ DEC_INT(cp->q, buf, bufLen, bytes);
+ DEC_INT(cp->k, buf, bufLen, bytes);
+ DEC_INT(cp->m, buf, bufLen, bytes);
+ DEC_INT(spare, buf, bufLen, bytes);
+
+ DEC_GIANT(cp->a, buf, bufLen, gLen, bytes, abort);
+ DEC_GIANT(cp->b, buf, bufLen, gLen, bytes, abort);
+ DEC_GIANT(cp->c, buf, bufLen, gLen, bytes, abort);
+ DEC_GIANT(cp->x1Plus, buf, bufLen, gLen, bytes, abort);
+ DEC_GIANT(cp->x1Minus, buf, bufLen, gLen, bytes, abort);
+ DEC_GIANT(cp->cOrderPlus, buf, bufLen, gLen, bytes, abort);
+ DEC_GIANT(cp->cOrderMinus, buf, bufLen, gLen, bytes, abort);
+ DEC_GIANT(cp->x1OrderPlus, buf, bufLen, gLen, bytes, abort);
+ DEC_GIANT(cp->x1OrderMinus, buf, bufLen, gLen, bytes, abort);
+
+ /*
+ * basePrime only present in byte rep for PT_GENERAL
+ */
+ if(cp->primeType == FPT_General) {
+ DEC_GIANT(cp->basePrime, buf, bufLen, gLen, bytes, abort);
+ }
+
+ /* remaining fields inferred */
+ curveParamsInferFields(cp);
+ allocRecipGiants(cp);
+
+ *cpLen = bytes;
+ return cp;
+
+abort:
+ freeCurveParams(cp);
+ return NULL;
+}
+
+/*
+ * Returns 0 if bad format, e.g., if minVersion of sig is > than codeVersion.
+ */
+int byteRepToSig(const unsigned char *buf,
+ unsigned bufLen,
+ int codeVersion,
+ int *sigMagic, // RETURNED
+ int *sigVersion, // RETURNED
+ int *sigMinVersion, // RETURNED
+ giant *g0, // alloc'd & RETURNED
+ giant *g1) // alloc'd & RETURNED
+{
+ unsigned gLen = 0;
+ int spare;
+ int bytes = 0;
+
+ if(bufLen < (4 * sizeof(int))) { // magic, version, minVersion,
+ // spare
+ return 0;
+ }
+ DEC_INT(*sigMagic, buf, bufLen, bytes);
+ DEC_INT(*sigVersion, buf, bufLen, bytes);
+ DEC_INT(*sigMinVersion, buf, bufLen, bytes);
+ if(*sigMinVersion > codeVersion) {
+ return 0;
+ }
+ DEC_INT(spare, buf, bufLen, bytes);
+ // deleted 2/20/01 DEC_INT(*signerLen, buf, bufLen, bytes);
+ // deleted 2/20/01 *signer = byteRepToUnichars(buf, *signerLen);
+ // deleted 2/20/01 buf += (2 * *signerLen);
+ // deleted 2/20/01 bufLen -= (2 * *signerLen);
+ DEC_GIANT(*g0, buf, bufLen, gLen, bytes, abort);
+ DEC_GIANT(*g1, buf, bufLen, gLen, bytes, abort);
+
+ return 1;
+abort:
+ return 0;
+}