X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_cryptkit/lib/byteRep.c?ds=inline diff --git a/Security/libsecurity_cryptkit/lib/byteRep.c b/Security/libsecurity_cryptkit/lib/byteRep.c new file mode 100644 index 00000000..f24f6d80 --- /dev/null +++ b/Security/libsecurity_cryptkit/lib/byteRep.c @@ -0,0 +1,476 @@ +/* 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; +}