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