iBoot/lib/pki/libGiants/giantExternal.c

192 lines
4.6 KiB
C

/* Copyright (c) 2005-2007 Apple Inc. All Rights Reserved. */
/*
* giantExternal.c - convert between giant integer and external representation
*
* Created Aug. 5 2005 by Doug Mitchell.
*/
#include <libGiants/giantTypes.h>
#include <libGiants/giantExternal.h>
#include <libGiants/giantDebug.h>
#include <stdlib.h>
/*
* Precalculate actual size in bytes needed to serialize a given giant.
*/
gi_uint16 serializeGiantBytes(const giant g)
{
gi_size numDigits, numZeros, digitByte;
giantDigit digit;
gtrimSign(g);
numDigits = g->sign;
if(numDigits == 0) {
return 0;
}
/* Count the number of leading 0 bytes in the m.s. digit. */
numZeros = 0;
digit = g->n[numDigits - 1];
for(digitByte=0; digitByte<GIANT_BYTES_PER_DIGIT; digitByte++) {
/* one loop per byte in the digit */
gi_uint8 byte = (gi_uint8)digit;
digit >>= 8;
if (byte) {
numZeros = 0;
} else {
numZeros++;
}
}
return (numDigits * GIANT_BYTES_PER_DIGIT) - numZeros;
}
/*
* Serialize, deserialize giants's n[] to/from byte stream.
* First byte of byte stream is the m.s. byte of the resulting giant,
* regardless of the size of giantDigit.
*
* No assumption is made about the alignment of cp.
*
* The numBytes argument indicates the space available on input;
* on return it indicates the actual number of bytes written.
*/
GIReturn serializeGiant(
const giant g,
gi_uint8 *cp,
gi_uint16 *numBytes) /* IN/OUT */
{
gi_size digitDex, numDigits, digitByte, totalBytes, bytesLeft;
gi_uint8 *currCp;
giantDigit digit;
GI_CHECK_SP("serializeGiant");
if((g == NULL) || (cp == NULL) || (numBytes == NULL)) {
return GR_IllegalArg;
}
totalBytes = serializeGiantBytes(g);
if(totalBytes == 0) {
*numBytes = 0;
return GR_Success;
}
numDigits = g->sign;
if(totalBytes > *numBytes) {
dbgLog("serializeGiant: Insufficient space\n");
return GR_Overflow;
}
/*
* Emit bytes starting at the far end of the outgoing byte
* stream, which is the l.s. byte of giant data. In order to prevent
* writing out leading zeros, we special case the m.s. digit.
*/
currCp = cp + totalBytes - 1;
for(digitDex=0; digitDex<numDigits - 1; digitDex++) {
/* 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 */
*currCp-- = (gi_uint8)digit;
digit >>= 8;
}
}
/* Handle the m.s. digit, by writing out only as many bytes as are left.
Since we already wrote out numDigits - 1 digits above the answer is: */
bytesLeft = totalBytes - (numDigits - 1) * GIANT_BYTES_PER_DIGIT;
digit = g->n[digitDex];
for(digitByte=0; digitByte<bytesLeft; digitByte++) {
/* one loop per byte in the digit */
*currCp-- = (gi_uint8)digit;
digit >>= 8;
}
*numBytes = totalBytes;
return GR_Success;
}
/*
* Initialize a giant with specified data. Does not have to be
* aligned to giantDigits (as the output of serializeGiant() always
* is).
*/
GIReturn deserializeGiant(
giant g,
const gi_uint8 *cp,
gi_uint16 numBytes)
{
gi_size numDigits;
giantDigit digit;
giantDigit tempDigit;
gi_size digitDex;
gi_size digitByte;
gi_size dex;
const gi_uint8 *currCp;
GI_CHECK_SP("deserializeGiant");
if(g == NULL) {
return GR_IllegalArg;
}
if(numBytes == 0) {
g->sign = 0;
return GR_Success;
}
if(cp == NULL) {
return GR_IllegalArg;
}
/*
* Trim off leading zeroes, sometimes placed there during DER
* encoding to ensure the number does not appear negative. We
* don't support negative numbers in this module...
*/
while((*cp == 0) && (numBytes != 0)) {
cp++;
numBytes--;
}
if(numBytes == 0) {
g->sign = 0;
return GR_Success;
}
numDigits = BYTES_TO_GIANT_DIGITS(numBytes);
if(numDigits > g->capacity) {
return GR_Overflow;
}
/*
* Start at l.s. byte, at the far end of the byte stream.
*/
digitDex = 0; /* index into g->n[] */
digit = 0; /* accumulator */
digitByte = 0; /* byte index into digit */
currCp = cp + numBytes - 1;
for(dex=0; dex<numBytes; dex++) {
/* add in current byte */
tempDigit = *currCp--;
tempDigit <<= (8 * digitByte);
digit |= tempDigit;
digitByte++;
/* have a complete digit, or reached the last byte? */
if((digitByte == GIANT_BYTES_PER_DIGIT) || /* full digit */
(dex == (numBytes - 1))) { /* no more data */
g->n[digitDex++] = digit;
/* reset for next digit */
digit = 0;
digitByte = 0;
}
}
/*
* Infer sign/size from non-zero n[] elements
*/
g->sign = numDigits;
gtrimSign(g);
return GR_Success;
}