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