/* 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 #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; }