pkix_pl_bigint.c (11276B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 /* 5 * pkix_pl_bigint.c 6 * 7 * BigInt Object Functions 8 * 9 */ 10 11 #include "pkix_pl_bigint.h" 12 13 /* --Private-Big-Int-Functions------------------------------------ */ 14 15 /* 16 * FUNCTION: pkix_pl_BigInt_Comparator 17 * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h) 18 */ 19 static PKIX_Error * 20 pkix_pl_BigInt_Comparator( 21 PKIX_PL_Object *firstObject, 22 PKIX_PL_Object *secondObject, 23 PKIX_Int32 *pResult, 24 void *plContext) 25 { 26 PKIX_PL_BigInt *firstBigInt = NULL; 27 PKIX_PL_BigInt *secondBigInt = NULL; 28 char *firstPtr = NULL; 29 char *secondPtr = NULL; 30 PKIX_UInt32 firstLen, secondLen; 31 32 PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Comparator"); 33 PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); 34 35 PKIX_CHECK(pkix_CheckTypes 36 (firstObject, secondObject, PKIX_BIGINT_TYPE, plContext), 37 PKIX_ARGUMENTSNOTBIGINTS); 38 39 /* It's safe to cast */ 40 firstBigInt = (PKIX_PL_BigInt*)firstObject; 41 secondBigInt = (PKIX_PL_BigInt*)secondObject; 42 43 *pResult = 0; 44 firstPtr = firstBigInt->dataRep; 45 secondPtr = secondBigInt->dataRep; 46 firstLen = firstBigInt->length; 47 secondLen = secondBigInt->length; 48 49 if (firstLen < secondLen) { 50 *pResult = -1; 51 } else if (firstLen > secondLen) { 52 *pResult = 1; 53 } else if (firstLen == secondLen) { 54 PKIX_BIGINT_DEBUG("\t\tCalling PORT_Memcmp).\n"); 55 *pResult = PORT_Memcmp(firstPtr, secondPtr, firstLen); 56 } 57 58 cleanup: 59 60 PKIX_RETURN(BIGINT); 61 } 62 63 /* 64 * FUNCTION: pkix_pl_BigInt_Destroy 65 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) 66 */ 67 static PKIX_Error * 68 pkix_pl_BigInt_Destroy( 69 PKIX_PL_Object *object, 70 void *plContext) 71 { 72 PKIX_PL_BigInt *bigInt = NULL; 73 74 PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Destroy"); 75 PKIX_NULLCHECK_ONE(object); 76 77 PKIX_CHECK(pkix_CheckType(object, PKIX_BIGINT_TYPE, plContext), 78 PKIX_OBJECTNOTBIGINT); 79 80 bigInt = (PKIX_PL_BigInt*)object; 81 82 PKIX_FREE(bigInt->dataRep); 83 bigInt->dataRep = NULL; 84 bigInt->length = 0; 85 86 cleanup: 87 88 PKIX_RETURN(BIGINT); 89 } 90 91 92 /* 93 * FUNCTION: pkix_pl_BigInt_ToString 94 * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) 95 */ 96 static PKIX_Error * 97 pkix_pl_BigInt_ToString( 98 PKIX_PL_Object *object, 99 PKIX_PL_String **pString, 100 void *plContext) 101 { 102 PKIX_PL_BigInt *bigInt = NULL; 103 char *outputText = NULL; 104 PKIX_UInt32 i, j, lengthChars; 105 106 PKIX_ENTER(BIGINT, "pkix_pl_BigInt_ToString"); 107 PKIX_NULLCHECK_TWO(object, pString); 108 109 PKIX_CHECK(pkix_CheckType(object, PKIX_BIGINT_TYPE, plContext), 110 PKIX_OBJECTNOTBIGINT); 111 112 bigInt = (PKIX_PL_BigInt*)object; 113 114 /* number of chars = 2 * (number of bytes) + null terminator */ 115 lengthChars = (bigInt->length * 2) + 1; 116 117 PKIX_CHECK(PKIX_PL_Malloc 118 (lengthChars, (void **)&outputText, plContext), 119 PKIX_MALLOCFAILED); 120 121 for (i = 0, j = 0; i < bigInt->length; i += 1, j += 2){ 122 outputText[j] = pkix_i2hex 123 ((char) ((*(bigInt->dataRep+i) & 0xf0) >> 4)); 124 outputText[j+1] = pkix_i2hex 125 ((char) (*(bigInt->dataRep+i) & 0x0f)); 126 } 127 128 outputText[lengthChars-1] = '\0'; 129 130 PKIX_CHECK(PKIX_PL_String_Create 131 (PKIX_ESCASCII, 132 outputText, 133 0, 134 pString, 135 plContext), 136 PKIX_STRINGCREATEFAILED); 137 138 cleanup: 139 140 PKIX_FREE(outputText); 141 142 PKIX_RETURN(BIGINT); 143 } 144 145 146 /* 147 * FUNCTION: pkix_pl_BigInt_Hashcode 148 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) 149 */ 150 static PKIX_Error * 151 pkix_pl_BigInt_Hashcode( 152 PKIX_PL_Object *object, 153 PKIX_UInt32 *pHashcode, 154 void *plContext) 155 { 156 PKIX_PL_BigInt *bigInt = NULL; 157 158 PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Hashcode"); 159 PKIX_NULLCHECK_TWO(object, pHashcode); 160 161 PKIX_CHECK(pkix_CheckType(object, PKIX_BIGINT_TYPE, plContext), 162 PKIX_OBJECTNOTBIGINT); 163 164 bigInt = (PKIX_PL_BigInt*)object; 165 166 PKIX_CHECK(pkix_hash 167 ((void *)bigInt->dataRep, 168 bigInt->length, 169 pHashcode, 170 plContext), 171 PKIX_HASHFAILED); 172 173 cleanup: 174 175 PKIX_RETURN(BIGINT); 176 } 177 178 /* 179 * FUNCTION: pkix_pl_BigInt_Equals 180 * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h) 181 */ 182 static PKIX_Error * 183 pkix_pl_BigInt_Equals( 184 PKIX_PL_Object *first, 185 PKIX_PL_Object *second, 186 PKIX_Boolean *pResult, 187 void *plContext) 188 { 189 PKIX_UInt32 secondType; 190 PKIX_Int32 cmpResult = 0; 191 192 PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Equals"); 193 PKIX_NULLCHECK_THREE(first, second, pResult); 194 195 PKIX_CHECK(pkix_CheckType(first, PKIX_BIGINT_TYPE, plContext), 196 PKIX_FIRSTOBJECTNOTBIGINT); 197 198 PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext), 199 PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); 200 201 *pResult = PKIX_FALSE; 202 203 if (secondType != PKIX_BIGINT_TYPE) goto cleanup; 204 205 PKIX_CHECK(pkix_pl_BigInt_Comparator 206 (first, second, &cmpResult, plContext), 207 PKIX_BIGINTCOMPARATORFAILED); 208 209 *pResult = (cmpResult == 0); 210 211 cleanup: 212 213 PKIX_RETURN(BIGINT); 214 } 215 216 /* 217 * FUNCTION: pkix_pl_BigInt_RegisterSelf 218 * DESCRIPTION: 219 * Registers PKIX_BIGINT_TYPE and its related functions with systemClasses[] 220 * THREAD SAFETY: 221 * Not Thread Safe - for performance and complexity reasons 222 * 223 * Since this function is only called by PKIX_PL_Initialize, which should 224 * only be called once, it is acceptable that this function is not 225 * thread-safe. 226 */ 227 PKIX_Error * 228 pkix_pl_BigInt_RegisterSelf(void *plContext) 229 { 230 231 extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; 232 pkix_ClassTable_Entry entry; 233 234 PKIX_ENTER(BIGINT, "pkix_pl_BigInt_RegisterSelf"); 235 236 entry.description = "BigInt"; 237 entry.objCounter = 0; 238 entry.typeObjectSize = sizeof(PKIX_PL_BigInt); 239 entry.destructor = pkix_pl_BigInt_Destroy; 240 entry.equalsFunction = pkix_pl_BigInt_Equals; 241 entry.hashcodeFunction = pkix_pl_BigInt_Hashcode; 242 entry.toStringFunction = pkix_pl_BigInt_ToString; 243 entry.comparator = pkix_pl_BigInt_Comparator; 244 entry.duplicateFunction = pkix_duplicateImmutable; 245 246 systemClasses[PKIX_BIGINT_TYPE] = entry; 247 248 PKIX_RETURN(BIGINT); 249 } 250 251 /* 252 * FUNCTION: pkix_pl_BigInt_CreateWithBytes 253 * DESCRIPTION: 254 * 255 * Creates a new BigInt of size "length" representing the array of bytes 256 * pointed to by "bytes" and stores it at "pBigInt". The caller should make 257 * sure that the first byte is not 0x00 (unless it is the the only byte). 258 * This function does not do that checking. 259 * 260 * Once created, a PKIX_PL_BigInt object is immutable. 261 * 262 * PARAMETERS: 263 * "bytes" 264 * Address of array of bytes. Must be non-NULL. 265 * "length" 266 * Length of the array. Must be non-zero. 267 * "pBigInt" 268 * Address where object pointer will be stored. Must be non-NULL. 269 * "plContext" - Platform-specific context pointer. 270 * THREAD SAFETY: 271 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) 272 * RETURNS: 273 * Returns NULL if the function succeeds. 274 * Returns a Fatal Error if the function fails in an unrecoverable way. 275 */ 276 PKIX_Error * 277 pkix_pl_BigInt_CreateWithBytes( 278 char *bytes, 279 PKIX_UInt32 length, 280 PKIX_PL_BigInt **pBigInt, 281 void *plContext) 282 { 283 PKIX_PL_BigInt *bigInt = NULL; 284 285 PKIX_ENTER(BIGINT, "pkix_pl_BigInt_CreateWithBytes"); 286 PKIX_NULLCHECK_TWO(pBigInt, bytes); 287 288 if (length == 0) { 289 PKIX_ERROR(PKIX_BIGINTLENGTH0INVALID) 290 } 291 292 PKIX_CHECK(PKIX_PL_Object_Alloc 293 (PKIX_BIGINT_TYPE, 294 sizeof (PKIX_PL_BigInt), 295 (PKIX_PL_Object **)&bigInt, 296 plContext), 297 PKIX_COULDNOTCREATEOBJECT); 298 299 PKIX_CHECK(PKIX_PL_Malloc 300 (length, (void **)&(bigInt->dataRep), plContext), 301 PKIX_MALLOCFAILED); 302 303 PKIX_BIGINT_DEBUG("\t\tCalling PORT_Memcpy).\n"); 304 (void) PORT_Memcpy(bigInt->dataRep, bytes, length); 305 306 bigInt->length = length; 307 308 *pBigInt = bigInt; 309 310 cleanup: 311 312 if (PKIX_ERROR_RECEIVED){ 313 PKIX_DECREF(bigInt); 314 } 315 316 PKIX_RETURN(BIGINT); 317 } 318 319 /* --Public-Functions------------------------------------------------------- */ 320 321 /* 322 * FUNCTION: PKIX_PL_BigInt_Create (see comments in pkix_pl_system.h) 323 */ 324 PKIX_Error * 325 PKIX_PL_BigInt_Create( 326 PKIX_PL_String *stringRep, 327 PKIX_PL_BigInt **pBigInt, 328 void *plContext) 329 { 330 PKIX_PL_BigInt *bigInt = NULL; 331 char *asciiString = NULL; 332 PKIX_UInt32 lengthBytes; 333 PKIX_UInt32 lengthString; 334 PKIX_UInt32 i; 335 char currChar; 336 337 PKIX_ENTER(BIGINT, "PKIX_PL_BigInt_Create"); 338 PKIX_NULLCHECK_TWO(pBigInt, stringRep); 339 340 PKIX_CHECK(PKIX_PL_String_GetEncoded 341 (stringRep, 342 PKIX_ESCASCII, 343 (void **)&asciiString, 344 &lengthString, 345 plContext), 346 PKIX_STRINGGETENCODEDFAILED); 347 348 if ((lengthString == 0) || ((lengthString % 2) != 0)){ 349 PKIX_ERROR(PKIX_SOURCESTRINGHASINVALIDLENGTH); 350 } 351 352 if (lengthString != 2){ 353 if ((asciiString[0] == '0') && (asciiString[1] == '0')){ 354 PKIX_ERROR(PKIX_FIRSTDOUBLEHEXMUSTNOTBE00); 355 } 356 } 357 358 for (i = 0; i < lengthString; i++) { 359 currChar = asciiString[i]; 360 if (!PKIX_ISXDIGIT(currChar)){ 361 PKIX_ERROR(PKIX_INVALIDCHARACTERINBIGINT); 362 } 363 } 364 365 PKIX_CHECK(PKIX_PL_Object_Alloc 366 (PKIX_BIGINT_TYPE, 367 sizeof (PKIX_PL_BigInt), 368 (PKIX_PL_Object **)&bigInt, 369 plContext), 370 PKIX_COULDNOTCREATEOBJECT); 371 372 /* number of bytes = 0.5 * (number of chars) */ 373 lengthBytes = lengthString/2; 374 375 PKIX_CHECK(PKIX_PL_Malloc 376 (lengthBytes, (void **)&(bigInt->dataRep), plContext), 377 PKIX_MALLOCFAILED); 378 379 for (i = 0; i < lengthString; i += 2){ 380 (bigInt->dataRep)[i/2] = 381 (pkix_hex2i(asciiString[i])<<4) | 382 pkix_hex2i(asciiString[i+1]); 383 } 384 385 bigInt->length = lengthBytes; 386 387 *pBigInt = bigInt; 388 389 cleanup: 390 391 PKIX_FREE(asciiString); 392 393 if (PKIX_ERROR_RECEIVED){ 394 PKIX_DECREF(bigInt); 395 } 396 397 PKIX_RETURN(BIGINT); 398 }