Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* pkix_pl_bigint.c
*
* BigInt Object Functions
*
*/
#include "pkix_pl_bigint.h"
/* --Private-Big-Int-Functions------------------------------------ */
/*
* FUNCTION: pkix_pl_BigInt_Comparator
* (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h)
*/
static PKIX_Error *
pkix_pl_BigInt_Comparator(
PKIX_PL_Object *firstObject,
PKIX_PL_Object *secondObject,
PKIX_Int32 *pResult,
void *plContext)
{
PKIX_PL_BigInt *firstBigInt = NULL;
PKIX_PL_BigInt *secondBigInt = NULL;
char *firstPtr = NULL;
char *secondPtr = NULL;
PKIX_UInt32 firstLen, secondLen;
PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Comparator");
PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
PKIX_CHECK(pkix_CheckTypes
(firstObject, secondObject, PKIX_BIGINT_TYPE, plContext),
PKIX_ARGUMENTSNOTBIGINTS);
/* It's safe to cast */
firstBigInt = (PKIX_PL_BigInt*)firstObject;
secondBigInt = (PKIX_PL_BigInt*)secondObject;
*pResult = 0;
firstPtr = firstBigInt->dataRep;
secondPtr = secondBigInt->dataRep;
firstLen = firstBigInt->length;
secondLen = secondBigInt->length;
if (firstLen < secondLen) {
*pResult = -1;
} else if (firstLen > secondLen) {
*pResult = 1;
} else if (firstLen == secondLen) {
PKIX_BIGINT_DEBUG("\t\tCalling PORT_Memcmp).\n");
*pResult = PORT_Memcmp(firstPtr, secondPtr, firstLen);
}
cleanup:
PKIX_RETURN(BIGINT);
}
/*
* FUNCTION: pkix_pl_BigInt_Destroy
* (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
*/
static PKIX_Error *
pkix_pl_BigInt_Destroy(
PKIX_PL_Object *object,
void *plContext)
{
PKIX_PL_BigInt *bigInt = NULL;
PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Destroy");
PKIX_NULLCHECK_ONE(object);
PKIX_CHECK(pkix_CheckType(object, PKIX_BIGINT_TYPE, plContext),
PKIX_OBJECTNOTBIGINT);
bigInt = (PKIX_PL_BigInt*)object;
PKIX_FREE(bigInt->dataRep);
bigInt->dataRep = NULL;
bigInt->length = 0;
cleanup:
PKIX_RETURN(BIGINT);
}
/*
* FUNCTION: pkix_pl_BigInt_ToString
* (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
*/
static PKIX_Error *
pkix_pl_BigInt_ToString(
PKIX_PL_Object *object,
PKIX_PL_String **pString,
void *plContext)
{
PKIX_PL_BigInt *bigInt = NULL;
char *outputText = NULL;
PKIX_UInt32 i, j, lengthChars;
PKIX_ENTER(BIGINT, "pkix_pl_BigInt_ToString");
PKIX_NULLCHECK_TWO(object, pString);
PKIX_CHECK(pkix_CheckType(object, PKIX_BIGINT_TYPE, plContext),
PKIX_OBJECTNOTBIGINT);
bigInt = (PKIX_PL_BigInt*)object;
/* number of chars = 2 * (number of bytes) + null terminator */
lengthChars = (bigInt->length * 2) + 1;
PKIX_CHECK(PKIX_PL_Malloc
(lengthChars, (void **)&outputText, plContext),
PKIX_MALLOCFAILED);
for (i = 0, j = 0; i < bigInt->length; i += 1, j += 2){
outputText[j] = pkix_i2hex
((char) ((*(bigInt->dataRep+i) & 0xf0) >> 4));
outputText[j+1] = pkix_i2hex
((char) (*(bigInt->dataRep+i) & 0x0f));
}
outputText[lengthChars-1] = '\0';
PKIX_CHECK(PKIX_PL_String_Create
(PKIX_ESCASCII,
outputText,
0,
pString,
plContext),
PKIX_STRINGCREATEFAILED);
cleanup:
PKIX_FREE(outputText);
PKIX_RETURN(BIGINT);
}
/*
* FUNCTION: pkix_pl_BigInt_Hashcode
* (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
*/
static PKIX_Error *
pkix_pl_BigInt_Hashcode(
PKIX_PL_Object *object,
PKIX_UInt32 *pHashcode,
void *plContext)
{
PKIX_PL_BigInt *bigInt = NULL;
PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Hashcode");
PKIX_NULLCHECK_TWO(object, pHashcode);
PKIX_CHECK(pkix_CheckType(object, PKIX_BIGINT_TYPE, plContext),
PKIX_OBJECTNOTBIGINT);
bigInt = (PKIX_PL_BigInt*)object;
PKIX_CHECK(pkix_hash
((void *)bigInt->dataRep,
bigInt->length,
pHashcode,
plContext),
PKIX_HASHFAILED);
cleanup:
PKIX_RETURN(BIGINT);
}
/*
* FUNCTION: pkix_pl_BigInt_Equals
* (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
*/
static PKIX_Error *
pkix_pl_BigInt_Equals(
PKIX_PL_Object *first,
PKIX_PL_Object *second,
PKIX_Boolean *pResult,
void *plContext)
{
PKIX_UInt32 secondType;
PKIX_Int32 cmpResult = 0;
PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Equals");
PKIX_NULLCHECK_THREE(first, second, pResult);
PKIX_CHECK(pkix_CheckType(first, PKIX_BIGINT_TYPE, plContext),
PKIX_FIRSTOBJECTNOTBIGINT);
PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext),
PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
*pResult = PKIX_FALSE;
if (secondType != PKIX_BIGINT_TYPE) goto cleanup;
PKIX_CHECK(pkix_pl_BigInt_Comparator
(first, second, &cmpResult, plContext),
PKIX_BIGINTCOMPARATORFAILED);
*pResult = (cmpResult == 0);
cleanup:
PKIX_RETURN(BIGINT);
}
/*
* FUNCTION: pkix_pl_BigInt_RegisterSelf
* DESCRIPTION:
* Registers PKIX_BIGINT_TYPE and its related functions with systemClasses[]
* THREAD SAFETY:
* Not Thread Safe - for performance and complexity reasons
*
* Since this function is only called by PKIX_PL_Initialize, which should
* only be called once, it is acceptable that this function is not
* thread-safe.
*/
PKIX_Error *
pkix_pl_BigInt_RegisterSelf(void *plContext)
{
extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
pkix_ClassTable_Entry entry;
PKIX_ENTER(BIGINT, "pkix_pl_BigInt_RegisterSelf");
entry.description = "BigInt";
entry.objCounter = 0;
entry.typeObjectSize = sizeof(PKIX_PL_BigInt);
entry.destructor = pkix_pl_BigInt_Destroy;
entry.equalsFunction = pkix_pl_BigInt_Equals;
entry.hashcodeFunction = pkix_pl_BigInt_Hashcode;
entry.toStringFunction = pkix_pl_BigInt_ToString;
entry.comparator = pkix_pl_BigInt_Comparator;
entry.duplicateFunction = pkix_duplicateImmutable;
systemClasses[PKIX_BIGINT_TYPE] = entry;
PKIX_RETURN(BIGINT);
}
/*
* FUNCTION: pkix_pl_BigInt_CreateWithBytes
* DESCRIPTION:
*
* Creates a new BigInt of size "length" representing the array of bytes
* pointed to by "bytes" and stores it at "pBigInt". The caller should make
* sure that the first byte is not 0x00 (unless it is the the only byte).
* This function does not do that checking.
*
* Once created, a PKIX_PL_BigInt object is immutable.
*
* PARAMETERS:
* "bytes"
* Address of array of bytes. Must be non-NULL.
* "length"
* Length of the array. Must be non-zero.
* "pBigInt"
* Address where object pointer will be stored. Must be non-NULL.
* "plContext" - Platform-specific context pointer.
* THREAD SAFETY:
* Thread Safe (see Thread Safety Definitions in Programmer's Guide)
* RETURNS:
* Returns NULL if the function succeeds.
* Returns a Fatal Error if the function fails in an unrecoverable way.
*/
PKIX_Error *
pkix_pl_BigInt_CreateWithBytes(
char *bytes,
PKIX_UInt32 length,
PKIX_PL_BigInt **pBigInt,
void *plContext)
{
PKIX_PL_BigInt *bigInt = NULL;
PKIX_ENTER(BIGINT, "pkix_pl_BigInt_CreateWithBytes");
PKIX_NULLCHECK_TWO(pBigInt, bytes);
if (length == 0) {
PKIX_ERROR(PKIX_BIGINTLENGTH0INVALID)
}
PKIX_CHECK(PKIX_PL_Object_Alloc
(PKIX_BIGINT_TYPE,
sizeof (PKIX_PL_BigInt),
(PKIX_PL_Object **)&bigInt,
plContext),
PKIX_COULDNOTCREATEOBJECT);
PKIX_CHECK(PKIX_PL_Malloc
(length, (void **)&(bigInt->dataRep), plContext),
PKIX_MALLOCFAILED);
PKIX_BIGINT_DEBUG("\t\tCalling PORT_Memcpy).\n");
(void) PORT_Memcpy(bigInt->dataRep, bytes, length);
bigInt->length = length;
*pBigInt = bigInt;
cleanup:
if (PKIX_ERROR_RECEIVED){
PKIX_DECREF(bigInt);
}
PKIX_RETURN(BIGINT);
}
/* --Public-Functions------------------------------------------------------- */
/*
* FUNCTION: PKIX_PL_BigInt_Create (see comments in pkix_pl_system.h)
*/
PKIX_Error *
PKIX_PL_BigInt_Create(
PKIX_PL_String *stringRep,
PKIX_PL_BigInt **pBigInt,
void *plContext)
{
PKIX_PL_BigInt *bigInt = NULL;
char *asciiString = NULL;
PKIX_UInt32 lengthBytes;
PKIX_UInt32 lengthString;
PKIX_UInt32 i;
char currChar;
PKIX_ENTER(BIGINT, "PKIX_PL_BigInt_Create");
PKIX_NULLCHECK_TWO(pBigInt, stringRep);
PKIX_CHECK(PKIX_PL_String_GetEncoded
(stringRep,
PKIX_ESCASCII,
(void **)&asciiString,
&lengthString,
plContext),
PKIX_STRINGGETENCODEDFAILED);
if ((lengthString == 0) || ((lengthString % 2) != 0)){
PKIX_ERROR(PKIX_SOURCESTRINGHASINVALIDLENGTH);
}
if (lengthString != 2){
if ((asciiString[0] == '0') && (asciiString[1] == '0')){
PKIX_ERROR(PKIX_FIRSTDOUBLEHEXMUSTNOTBE00);
}
}
for (i = 0; i < lengthString; i++) {
currChar = asciiString[i];
if (!PKIX_ISXDIGIT(currChar)){
PKIX_ERROR(PKIX_INVALIDCHARACTERINBIGINT);
}
}
PKIX_CHECK(PKIX_PL_Object_Alloc
(PKIX_BIGINT_TYPE,
sizeof (PKIX_PL_BigInt),
(PKIX_PL_Object **)&bigInt,
plContext),
PKIX_COULDNOTCREATEOBJECT);
/* number of bytes = 0.5 * (number of chars) */
lengthBytes = lengthString/2;
PKIX_CHECK(PKIX_PL_Malloc
(lengthBytes, (void **)&(bigInt->dataRep), plContext),
PKIX_MALLOCFAILED);
for (i = 0; i < lengthString; i += 2){
(bigInt->dataRep)[i/2] =
(pkix_hex2i(asciiString[i])<<4) |
pkix_hex2i(asciiString[i+1]);
}
bigInt->length = lengthBytes;
*pBigInt = bigInt;
cleanup:
PKIX_FREE(asciiString);
if (PKIX_ERROR_RECEIVED){
PKIX_DECREF(bigInt);
}
PKIX_RETURN(BIGINT);
}