| OLD | NEW |
| (Empty) |
| 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 #include "plarena.h" | |
| 6 | |
| 7 #include "seccomon.h" | |
| 8 #include "secitem.h" | |
| 9 #include "secport.h" | |
| 10 #include "hasht.h" | |
| 11 #include "pkcs11t.h" | |
| 12 #include "blapi.h" | |
| 13 #include "hasht.h" | |
| 14 #include "secasn1.h" | |
| 15 #include "secder.h" | |
| 16 #include "lowpbe.h" | |
| 17 #include "secoid.h" | |
| 18 #include "alghmac.h" | |
| 19 #include "softoken.h" | |
| 20 #include "secerr.h" | |
| 21 | |
| 22 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) | |
| 23 | |
| 24 /* template for PKCS 5 PBE Parameter. This template has been expanded | |
| 25 * based upon the additions in PKCS 12. This should eventually be moved | |
| 26 * if RSA updates PKCS 5. | |
| 27 */ | |
| 28 static const SEC_ASN1Template NSSPKCS5PBEParameterTemplate[] = | |
| 29 { | |
| 30 { SEC_ASN1_SEQUENCE, | |
| 31 0, NULL, sizeof(NSSPKCS5PBEParameter) }, | |
| 32 { SEC_ASN1_OCTET_STRING, | |
| 33 offsetof(NSSPKCS5PBEParameter, salt) }, | |
| 34 { SEC_ASN1_INTEGER, | |
| 35 offsetof(NSSPKCS5PBEParameter, iteration) }, | |
| 36 { 0 } | |
| 37 }; | |
| 38 | |
| 39 static const SEC_ASN1Template NSSPKCS5PKCS12V2PBEParameterTemplate[] = | |
| 40 { | |
| 41 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSPKCS5PBEParameter) }, | |
| 42 { SEC_ASN1_OCTET_STRING, offsetof(NSSPKCS5PBEParameter, salt) }, | |
| 43 { SEC_ASN1_INTEGER, offsetof(NSSPKCS5PBEParameter, iteration) }, | |
| 44 { 0 } | |
| 45 }; | |
| 46 | |
| 47 | |
| 48 /* PKCS5 v2 */ | |
| 49 | |
| 50 struct nsspkcs5V2PBEParameterStr { | |
| 51 SECAlgorithmID keyParams; /* parameters of the key generation */ | |
| 52 SECAlgorithmID algParams; /* parameters for the encryption or mac op */ | |
| 53 }; | |
| 54 | |
| 55 typedef struct nsspkcs5V2PBEParameterStr nsspkcs5V2PBEParameter; | |
| 56 | |
| 57 static const SEC_ASN1Template NSSPKCS5V2PBES2ParameterTemplate[] = | |
| 58 { | |
| 59 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(nsspkcs5V2PBEParameter) }, | |
| 60 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, | |
| 61 offsetof(nsspkcs5V2PBEParameter, keyParams), | |
| 62 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, | |
| 63 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, | |
| 64 offsetof(nsspkcs5V2PBEParameter, algParams), | |
| 65 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, | |
| 66 { 0 } | |
| 67 }; | |
| 68 | |
| 69 static const SEC_ASN1Template NSSPKCS5V2PBEParameterTemplate[] = | |
| 70 { | |
| 71 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSPKCS5PBEParameter) }, | |
| 72 /* this is really a choice, but since we don't understand any other | |
| 73 *choice, just inline it. */ | |
| 74 { SEC_ASN1_OCTET_STRING, offsetof(NSSPKCS5PBEParameter, salt) }, | |
| 75 { SEC_ASN1_INTEGER, offsetof(NSSPKCS5PBEParameter, iteration) }, | |
| 76 { SEC_ASN1_INTEGER, offsetof(NSSPKCS5PBEParameter, keyLength) }, | |
| 77 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, | |
| 78 offsetof(NSSPKCS5PBEParameter, prfAlg), | |
| 79 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, | |
| 80 { 0 } | |
| 81 }; | |
| 82 | |
| 83 SECStatus | |
| 84 nsspkcs5_HashBuf(const SECHashObject *hashObj, unsigned char *dest, | |
| 85 unsigned char *src, int len) | |
| 86 { | |
| 87 void *ctx; | |
| 88 unsigned int retLen; | |
| 89 | |
| 90 ctx = hashObj->create(); | |
| 91 if(ctx == NULL) { | |
| 92 return SECFailure; | |
| 93 } | |
| 94 hashObj->begin(ctx); | |
| 95 hashObj->update(ctx, src, len); | |
| 96 hashObj->end(ctx, dest, &retLen, hashObj->length); | |
| 97 hashObj->destroy(ctx, PR_TRUE); | |
| 98 return SECSuccess; | |
| 99 } | |
| 100 | |
| 101 /* generate bits using any hash | |
| 102 */ | |
| 103 static SECItem * | |
| 104 nsspkcs5_PBKDF1(const SECHashObject *hashObj, SECItem *salt, SECItem *pwd, | |
| 105 int iter, PRBool faulty3DES) | |
| 106 { | |
| 107 SECItem *hash = NULL, *pre_hash = NULL; | |
| 108 SECStatus rv = SECFailure; | |
| 109 | |
| 110 if((salt == NULL) || (pwd == NULL) || (iter < 0)) { | |
| 111 return NULL; | |
| 112 } | |
| 113 | |
| 114 hash = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); | |
| 115 pre_hash = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); | |
| 116 | |
| 117 if((hash != NULL) && (pre_hash != NULL)) { | |
| 118 int i, ph_len; | |
| 119 | |
| 120 ph_len = hashObj->length; | |
| 121 if((salt->len + pwd->len) > hashObj->length) { | |
| 122 ph_len = salt->len + pwd->len; | |
| 123 } | |
| 124 | |
| 125 rv = SECFailure; | |
| 126 | |
| 127 /* allocate buffers */ | |
| 128 hash->len = hashObj->length; | |
| 129 hash->data = (unsigned char *)PORT_ZAlloc(hash->len); | |
| 130 pre_hash->data = (unsigned char *)PORT_ZAlloc(ph_len); | |
| 131 | |
| 132 /* in pbeSHA1TripleDESCBC there was an allocation error that made | |
| 133 * it into the caller. We do not want to propagate those errors | |
| 134 * further, so we are doing it correctly, but reading the old method. | |
| 135 */ | |
| 136 if (faulty3DES) { | |
| 137 pre_hash->len = ph_len; | |
| 138 } else { | |
| 139 pre_hash->len = salt->len + pwd->len; | |
| 140 } | |
| 141 | |
| 142 /* preform hash */ | |
| 143 if ((hash->data != NULL) && (pre_hash->data != NULL)) { | |
| 144 rv = SECSuccess; | |
| 145 /* check for 0 length password */ | |
| 146 if(pwd->len > 0) { | |
| 147 PORT_Memcpy(pre_hash->data, pwd->data, pwd->len); | |
| 148 } | |
| 149 if(salt->len > 0) { | |
| 150 PORT_Memcpy((pre_hash->data+pwd->len), salt->data, salt->len); | |
| 151 } | |
| 152 for(i = 0; ((i < iter) && (rv == SECSuccess)); i++) { | |
| 153 rv = nsspkcs5_HashBuf(hashObj, hash->data, | |
| 154 pre_hash->data, pre_hash->len); | |
| 155 if(rv != SECFailure) { | |
| 156 pre_hash->len = hashObj->length; | |
| 157 PORT_Memcpy(pre_hash->data, hash->data, hashObj->length); | |
| 158 } | |
| 159 } | |
| 160 } | |
| 161 } | |
| 162 | |
| 163 if(pre_hash != NULL) { | |
| 164 SECITEM_FreeItem(pre_hash, PR_TRUE); | |
| 165 } | |
| 166 | |
| 167 if((rv != SECSuccess) && (hash != NULL)) { | |
| 168 SECITEM_FreeItem(hash, PR_TRUE); | |
| 169 hash = NULL; | |
| 170 } | |
| 171 | |
| 172 return hash; | |
| 173 } | |
| 174 | |
| 175 /* this bit generation routine is described in PKCS 12 and the proposed | |
| 176 * extensions to PKCS 5. an initial hash is generated following the | |
| 177 * instructions laid out in PKCS 5. If the number of bits generated is | |
| 178 * insufficient, then the method discussed in the proposed extensions to | |
| 179 * PKCS 5 in PKCS 12 are used. This extension makes use of the HMAC | |
| 180 * function. And the P_Hash function from the TLS standard. | |
| 181 */ | |
| 182 static SECItem * | |
| 183 nsspkcs5_PFXPBE(const SECHashObject *hashObj, NSSPKCS5PBEParameter *pbe_param, | |
| 184 SECItem *init_hash, unsigned int bytes_needed) | |
| 185 { | |
| 186 SECItem *ret_bits = NULL; | |
| 187 int hash_size = 0; | |
| 188 unsigned int i; | |
| 189 unsigned int hash_iter; | |
| 190 unsigned int dig_len; | |
| 191 SECStatus rv = SECFailure; | |
| 192 unsigned char *state = NULL; | |
| 193 unsigned int state_len; | |
| 194 HMACContext *cx = NULL; | |
| 195 | |
| 196 hash_size = hashObj->length; | |
| 197 hash_iter = (bytes_needed + (unsigned int)hash_size - 1) / hash_size; | |
| 198 | |
| 199 /* allocate return buffer */ | |
| 200 ret_bits = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); | |
| 201 if(ret_bits == NULL) | |
| 202 return NULL; | |
| 203 ret_bits->data = (unsigned char *)PORT_ZAlloc((hash_iter * hash_size) + 1); | |
| 204 ret_bits->len = (hash_iter * hash_size); | |
| 205 if(ret_bits->data == NULL) { | |
| 206 PORT_Free(ret_bits); | |
| 207 return NULL; | |
| 208 } | |
| 209 | |
| 210 /* allocate intermediate hash buffer. 8 is for the 8 bytes of | |
| 211 * data which are added based on iteration number | |
| 212 */ | |
| 213 | |
| 214 if ((unsigned int)hash_size > pbe_param->salt.len) { | |
| 215 state_len = hash_size; | |
| 216 } else { | |
| 217 state_len = pbe_param->salt.len; | |
| 218 } | |
| 219 state = (unsigned char *)PORT_ZAlloc(state_len); | |
| 220 if(state == NULL) { | |
| 221 rv = SECFailure; | |
| 222 goto loser; | |
| 223 } | |
| 224 if(pbe_param->salt.len > 0) { | |
| 225 PORT_Memcpy(state, pbe_param->salt.data, pbe_param->salt.len); | |
| 226 } | |
| 227 | |
| 228 cx = HMAC_Create(hashObj, init_hash->data, init_hash->len, PR_TRUE); | |
| 229 if (cx == NULL) { | |
| 230 rv = SECFailure; | |
| 231 goto loser; | |
| 232 } | |
| 233 | |
| 234 for(i = 0; i < hash_iter; i++) { | |
| 235 | |
| 236 /* generate output bits */ | |
| 237 HMAC_Begin(cx); | |
| 238 HMAC_Update(cx, state, state_len); | |
| 239 HMAC_Update(cx, pbe_param->salt.data, pbe_param->salt.len); | |
| 240 rv = HMAC_Finish(cx, ret_bits->data + (i * hash_size), | |
| 241 &dig_len, hash_size); | |
| 242 if (rv != SECSuccess) | |
| 243 goto loser; | |
| 244 PORT_Assert((unsigned int)hash_size == dig_len); | |
| 245 | |
| 246 /* generate new state */ | |
| 247 HMAC_Begin(cx); | |
| 248 HMAC_Update(cx, state, state_len); | |
| 249 rv = HMAC_Finish(cx, state, &state_len, state_len); | |
| 250 if (rv != SECSuccess) | |
| 251 goto loser; | |
| 252 PORT_Assert(state_len == dig_len); | |
| 253 } | |
| 254 | |
| 255 loser: | |
| 256 if (state != NULL) | |
| 257 PORT_ZFree(state, state_len); | |
| 258 HMAC_Destroy(cx, PR_TRUE); | |
| 259 | |
| 260 if(rv != SECSuccess) { | |
| 261 SECITEM_ZfreeItem(ret_bits, PR_TRUE); | |
| 262 ret_bits = NULL; | |
| 263 } | |
| 264 | |
| 265 return ret_bits; | |
| 266 } | |
| 267 | |
| 268 /* generate bits for the key and iv determination. if enough bits | |
| 269 * are not generated using PKCS 5, then we need to generate more bits | |
| 270 * based on the extension proposed in PKCS 12 | |
| 271 */ | |
| 272 static SECItem * | |
| 273 nsspkcs5_PBKDF1Extended(const SECHashObject *hashObj, | |
| 274 NSSPKCS5PBEParameter *pbe_param, SECItem *pwitem, PRBool faulty3DES) | |
| 275 { | |
| 276 SECItem * hash = NULL; | |
| 277 SECItem * newHash = NULL; | |
| 278 int bytes_needed; | |
| 279 int bytes_available; | |
| 280 | |
| 281 bytes_needed = pbe_param->ivLen + pbe_param->keyLen; | |
| 282 bytes_available = hashObj->length; | |
| 283 | |
| 284 hash = nsspkcs5_PBKDF1(hashObj, &pbe_param->salt, pwitem, | |
| 285 pbe_param->iter, faulty3DES); | |
| 286 | |
| 287 if(hash == NULL) { | |
| 288 return NULL; | |
| 289 } | |
| 290 | |
| 291 if(bytes_needed <= bytes_available) { | |
| 292 return hash; | |
| 293 } | |
| 294 | |
| 295 newHash = nsspkcs5_PFXPBE(hashObj, pbe_param, hash, bytes_needed); | |
| 296 if (hash != newHash) | |
| 297 SECITEM_FreeItem(hash, PR_TRUE); | |
| 298 return newHash; | |
| 299 } | |
| 300 | |
| 301 /* | |
| 302 * PBDKDF2 is PKCS #5 v2.0 it's currently not used by NSS | |
| 303 */ | |
| 304 static void | |
| 305 do_xor(unsigned char *dest, unsigned char *src, int len) | |
| 306 { | |
| 307 /* use byt xor, not all platforms are happy about inaligned | |
| 308 * integer fetches */ | |
| 309 while (len--) { | |
| 310 *dest = *dest ^ *src; | |
| 311 dest++; | |
| 312 src++; | |
| 313 } | |
| 314 } | |
| 315 | |
| 316 static SECStatus | |
| 317 nsspkcs5_PBKDF2_F(const SECHashObject *hashobj, SECItem *pwitem, SECItem *salt, | |
| 318 int iterations, unsigned int i, unsigned char *T) | |
| 319 { | |
| 320 int j; | |
| 321 HMACContext *cx = NULL; | |
| 322 unsigned int hLen = hashobj->length; | |
| 323 SECStatus rv = SECFailure; | |
| 324 unsigned char *last = NULL; | |
| 325 unsigned int lastLength = salt->len + 4; | |
| 326 unsigned int lastBufLength; | |
| 327 | |
| 328 cx=HMAC_Create(hashobj,pwitem->data,pwitem->len,PR_FALSE); | |
| 329 if (cx == NULL) { | |
| 330 goto loser; | |
| 331 } | |
| 332 PORT_Memset(T,0,hLen); | |
| 333 lastBufLength = PR_MAX(lastLength, hLen); | |
| 334 last = PORT_Alloc(lastBufLength); | |
| 335 if (last == NULL) { | |
| 336 goto loser; | |
| 337 } | |
| 338 PORT_Memcpy(last,salt->data,salt->len); | |
| 339 last[salt->len ] = (i >> 24) & 0xff; | |
| 340 last[salt->len+1] = (i >> 16) & 0xff; | |
| 341 last[salt->len+2] = (i >> 8) & 0xff; | |
| 342 last[salt->len+3] = i & 0xff; | |
| 343 | |
| 344 /* NOTE: we need at least one iteration to return success! */ | |
| 345 for (j=0; j < iterations; j++) { | |
| 346 HMAC_Begin(cx); | |
| 347 HMAC_Update(cx,last,lastLength); | |
| 348 rv =HMAC_Finish(cx,last,&lastLength,hLen); | |
| 349 if (rv !=SECSuccess) { | |
| 350 break; | |
| 351 } | |
| 352 do_xor(T,last,hLen); | |
| 353 } | |
| 354 loser: | |
| 355 if (cx) { | |
| 356 HMAC_Destroy(cx, PR_TRUE); | |
| 357 } | |
| 358 if (last) { | |
| 359 PORT_ZFree(last,lastBufLength); | |
| 360 } | |
| 361 return rv; | |
| 362 } | |
| 363 | |
| 364 static SECItem * | |
| 365 nsspkcs5_PBKDF2(const SECHashObject *hashobj, NSSPKCS5PBEParameter *pbe_param, | |
| 366 SECItem *pwitem) | |
| 367 { | |
| 368 int iterations = pbe_param->iter; | |
| 369 int bytesNeeded = pbe_param->keyLen; | |
| 370 unsigned int dkLen = bytesNeeded; | |
| 371 unsigned int hLen = hashobj->length; | |
| 372 unsigned int nblocks = (dkLen+hLen-1) / hLen; | |
| 373 unsigned int i; | |
| 374 unsigned char *rp; | |
| 375 unsigned char *T = NULL; | |
| 376 SECItem *result = NULL; | |
| 377 SECItem *salt = &pbe_param->salt; | |
| 378 SECStatus rv = SECFailure; | |
| 379 | |
| 380 result = SECITEM_AllocItem(NULL,NULL,nblocks*hLen); | |
| 381 if (result == NULL) { | |
| 382 return NULL; | |
| 383 } | |
| 384 | |
| 385 T = PORT_Alloc(hLen); | |
| 386 if (T == NULL) { | |
| 387 goto loser; | |
| 388 } | |
| 389 | |
| 390 for (i=1,rp=result->data; i <= nblocks ; i++, rp +=hLen) { | |
| 391 rv = nsspkcs5_PBKDF2_F(hashobj, pwitem, salt, iterations, i, T); | |
| 392 if (rv != SECSuccess) { | |
| 393 break; | |
| 394 } | |
| 395 PORT_Memcpy(rp,T,hLen); | |
| 396 } | |
| 397 | |
| 398 loser: | |
| 399 if (T) { | |
| 400 PORT_ZFree(T,hLen); | |
| 401 } | |
| 402 if (rv != SECSuccess) { | |
| 403 SECITEM_FreeItem(result,PR_TRUE); | |
| 404 result = NULL; | |
| 405 } else { | |
| 406 result->len = dkLen; | |
| 407 } | |
| 408 | |
| 409 return result; | |
| 410 } | |
| 411 | |
| 412 #define HMAC_BUFFER 64 | |
| 413 #define NSSPBE_ROUNDUP(x,y) ((((x)+((y)-1))/(y))*(y)) | |
| 414 #define NSSPBE_MIN(x,y) ((x) < (y) ? (x) : (y)) | |
| 415 /* | |
| 416 * This is the extended PBE function defined by the final PKCS #12 spec. | |
| 417 */ | |
| 418 static SECItem * | |
| 419 nsspkcs5_PKCS12PBE(const SECHashObject *hashObject, | |
| 420 NSSPKCS5PBEParameter *pbe_param, SECItem *pwitem, | |
| 421 PBEBitGenID bitGenPurpose, unsigned int bytesNeeded) | |
| 422 { | |
| 423 PLArenaPool *arena = NULL; | |
| 424 unsigned int SLen,PLen; | |
| 425 unsigned int hashLength = hashObject->length; | |
| 426 unsigned char *S, *P; | |
| 427 SECItem *A = NULL, B, D, I; | |
| 428 SECItem *salt = &pbe_param->salt; | |
| 429 unsigned int c,i = 0; | |
| 430 unsigned int hashLen; | |
| 431 int iter; | |
| 432 unsigned char *iterBuf; | |
| 433 void *hash = NULL; | |
| 434 | |
| 435 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
| 436 if(!arena) { | |
| 437 return NULL; | |
| 438 } | |
| 439 | |
| 440 /* how many hash object lengths are needed */ | |
| 441 c = (bytesNeeded + (hashLength-1))/hashLength; | |
| 442 | |
| 443 /* initialize our buffers */ | |
| 444 D.len = HMAC_BUFFER; | |
| 445 /* B and D are the same length, use one alloc go get both */ | |
| 446 D.data = (unsigned char*)PORT_ArenaZAlloc(arena, D.len*2); | |
| 447 B.len = D.len; | |
| 448 B.data = D.data + D.len; | |
| 449 | |
| 450 /* if all goes well, A will be returned, so don't use our temp arena */ | |
| 451 A = SECITEM_AllocItem(NULL,NULL,c*hashLength); | |
| 452 if (A == NULL) { | |
| 453 goto loser; | |
| 454 } | |
| 455 | |
| 456 SLen = NSSPBE_ROUNDUP(salt->len,HMAC_BUFFER); | |
| 457 PLen = NSSPBE_ROUNDUP(pwitem->len,HMAC_BUFFER); | |
| 458 I.len = SLen+PLen; | |
| 459 I.data = (unsigned char*)PORT_ArenaZAlloc(arena, I.len); | |
| 460 if (I.data == NULL) { | |
| 461 goto loser; | |
| 462 } | |
| 463 | |
| 464 /* S & P are only used to initialize I */ | |
| 465 S = I.data; | |
| 466 P = S + SLen; | |
| 467 | |
| 468 PORT_Memset(D.data, (char)bitGenPurpose, D.len); | |
| 469 if (SLen) { | |
| 470 for (i=0; i < SLen; i += salt->len) { | |
| 471 PORT_Memcpy(S+i, salt->data, NSSPBE_MIN(SLen-i,salt->len)); | |
| 472 } | |
| 473 } | |
| 474 if (PLen) { | |
| 475 for (i=0; i < PLen; i += pwitem->len) { | |
| 476 PORT_Memcpy(P+i, pwitem->data, NSSPBE_MIN(PLen-i,pwitem->len)); | |
| 477 } | |
| 478 } | |
| 479 | |
| 480 iterBuf = (unsigned char*)PORT_ArenaZAlloc(arena,hashLength); | |
| 481 if (iterBuf == NULL) { | |
| 482 goto loser; | |
| 483 } | |
| 484 | |
| 485 hash = hashObject->create(); | |
| 486 if(!hash) { | |
| 487 goto loser; | |
| 488 } | |
| 489 /* calculate the PBE now */ | |
| 490 for(i = 0; i < c; i++) { | |
| 491 int Bidx; /* must be signed or the for loop won't terminate */ | |
| 492 unsigned int k, j; | |
| 493 unsigned char *Ai = A->data+i*hashLength; | |
| 494 | |
| 495 | |
| 496 for(iter = 0; iter < pbe_param->iter; iter++) { | |
| 497 hashObject->begin(hash); | |
| 498 | |
| 499 if (iter) { | |
| 500 hashObject->update(hash, iterBuf, hashLen); | |
| 501 } else { | |
| 502 hashObject->update(hash, D.data, D.len); | |
| 503 hashObject->update(hash, I.data, I.len); | |
| 504 } | |
| 505 | |
| 506 hashObject->end(hash, iterBuf, &hashLen, hashObject->length); | |
| 507 if(hashLen != hashObject->length) { | |
| 508 break; | |
| 509 } | |
| 510 } | |
| 511 | |
| 512 PORT_Memcpy(Ai, iterBuf, hashLength); | |
| 513 for (Bidx = 0; Bidx < (int)B.len; Bidx += hashLength) { | |
| 514 PORT_Memcpy(B.data+Bidx,iterBuf,NSSPBE_MIN(B.len-Bidx,hashLength)); | |
| 515 } | |
| 516 | |
| 517 k = I.len/B.len; | |
| 518 for(j = 0; j < k; j++) { | |
| 519 unsigned int q, carryBit; | |
| 520 unsigned char *Ij = I.data + j*B.len; | |
| 521 | |
| 522 /* (Ij = Ij+B+1) */ | |
| 523 for (Bidx = (B.len-1), q=1, carryBit=0; Bidx >= 0; Bidx--,q=0) { | |
| 524 q += (unsigned int)Ij[Bidx]; | |
| 525 q += (unsigned int)B.data[Bidx]; | |
| 526 q += carryBit; | |
| 527 | |
| 528 carryBit = (q > 0xff); | |
| 529 Ij[Bidx] = (unsigned char)(q & 0xff); | |
| 530 } | |
| 531 } | |
| 532 } | |
| 533 loser: | |
| 534 if (hash) { | |
| 535 hashObject->destroy(hash, PR_TRUE); | |
| 536 } | |
| 537 if(arena) { | |
| 538 PORT_FreeArena(arena, PR_TRUE); | |
| 539 } | |
| 540 | |
| 541 if (A) { | |
| 542 /* if i != c, then we didn't complete the loop above and must of failed | |
| 543 * somwhere along the way */ | |
| 544 if (i != c) { | |
| 545 SECITEM_ZfreeItem(A,PR_TRUE); | |
| 546 A = NULL; | |
| 547 } else { | |
| 548 A->len = bytesNeeded; | |
| 549 } | |
| 550 } | |
| 551 | |
| 552 return A; | |
| 553 } | |
| 554 | |
| 555 /* | |
| 556 * generate key as per PKCS 5 | |
| 557 */ | |
| 558 SECItem * | |
| 559 nsspkcs5_ComputeKeyAndIV(NSSPKCS5PBEParameter *pbe_param, SECItem *pwitem, | |
| 560 SECItem *iv, PRBool faulty3DES) | |
| 561 { | |
| 562 SECItem *hash = NULL, *key = NULL; | |
| 563 const SECHashObject *hashObj; | |
| 564 PRBool getIV = PR_FALSE; | |
| 565 | |
| 566 if((pbe_param == NULL) || (pwitem == NULL)) { | |
| 567 return NULL; | |
| 568 } | |
| 569 | |
| 570 key = SECITEM_AllocItem(NULL,NULL,pbe_param->keyLen); | |
| 571 if (key == NULL) { | |
| 572 return NULL; | |
| 573 } | |
| 574 | |
| 575 if (iv && (pbe_param->ivLen) && (iv->data == NULL)) { | |
| 576 getIV = PR_TRUE; | |
| 577 iv->data = (unsigned char *)PORT_Alloc(pbe_param->ivLen); | |
| 578 if (iv->data == NULL) { | |
| 579 goto loser; | |
| 580 } | |
| 581 iv->len = pbe_param->ivLen; | |
| 582 } | |
| 583 | |
| 584 hashObj = HASH_GetRawHashObject(pbe_param->hashType); | |
| 585 switch (pbe_param->pbeType) { | |
| 586 case NSSPKCS5_PBKDF1: | |
| 587 hash = nsspkcs5_PBKDF1Extended(hashObj,pbe_param,pwitem,faulty3DES); | |
| 588 if (hash == NULL) { | |
| 589 goto loser; | |
| 590 } | |
| 591 PORT_Assert(hash->len >= key->len+(getIV ? iv->len : 0)); | |
| 592 if (getIV) { | |
| 593 PORT_Memcpy(iv->data, hash->data+(hash->len - iv->len),iv->len); | |
| 594 } | |
| 595 | |
| 596 break; | |
| 597 case NSSPKCS5_PBKDF2: | |
| 598 hash = nsspkcs5_PBKDF2(hashObj,pbe_param,pwitem); | |
| 599 if (getIV) { | |
| 600 PORT_Memcpy(iv->data, pbe_param->ivData, iv->len); | |
| 601 } | |
| 602 break; | |
| 603 case NSSPKCS5_PKCS12_V2: | |
| 604 if (getIV) { | |
| 605 hash = nsspkcs5_PKCS12PBE(hashObj,pbe_param,pwitem, | |
| 606 pbeBitGenCipherIV,iv->len); | |
| 607 if (hash == NULL) { | |
| 608 goto loser; | |
| 609 } | |
| 610 PORT_Memcpy(iv->data,hash->data,iv->len); | |
| 611 SECITEM_ZfreeItem(hash,PR_TRUE); | |
| 612 hash = NULL; | |
| 613 } | |
| 614 hash = nsspkcs5_PKCS12PBE(hashObj,pbe_param,pwitem, | |
| 615 pbe_param->keyID,key->len); | |
| 616 default: | |
| 617 break; | |
| 618 } | |
| 619 | |
| 620 if (hash == NULL) { | |
| 621 goto loser; | |
| 622 } | |
| 623 | |
| 624 if (pbe_param->is2KeyDES) { | |
| 625 PORT_Memcpy(key->data, hash->data, (key->len * 2) / 3); | |
| 626 PORT_Memcpy(&(key->data[(key->len * 2) / 3]), key->data, | |
| 627 key->len / 3); | |
| 628 } else { | |
| 629 PORT_Memcpy(key->data, hash->data, key->len); | |
| 630 } | |
| 631 | |
| 632 SECITEM_ZfreeItem(hash, PR_TRUE); | |
| 633 return key; | |
| 634 | |
| 635 loser: | |
| 636 if (getIV && iv->data) { | |
| 637 PORT_ZFree(iv->data,iv->len); | |
| 638 iv->data = NULL; | |
| 639 } | |
| 640 | |
| 641 SECITEM_ZfreeItem(key, PR_TRUE); | |
| 642 return NULL; | |
| 643 } | |
| 644 | |
| 645 static SECStatus | |
| 646 nsspkcs5_FillInParam(SECOidTag algorithm, HASH_HashType hashType, | |
| 647 NSSPKCS5PBEParameter *pbe_param) | |
| 648 { | |
| 649 PRBool skipType = PR_FALSE; | |
| 650 | |
| 651 pbe_param->keyLen = 5; | |
| 652 pbe_param->ivLen = 8; | |
| 653 pbe_param->hashType = hashType; | |
| 654 pbe_param->pbeType = NSSPKCS5_PBKDF1; | |
| 655 pbe_param->encAlg = SEC_OID_RC2_CBC; | |
| 656 pbe_param->is2KeyDES = PR_FALSE; | |
| 657 switch(algorithm) { | |
| 658 /* DES3 Algorithms */ | |
| 659 case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC: | |
| 660 pbe_param->is2KeyDES = PR_TRUE; | |
| 661 /* fall through */ | |
| 662 case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC: | |
| 663 pbe_param->pbeType = NSSPKCS5_PKCS12_V2; | |
| 664 /* fall through */ | |
| 665 case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC: | |
| 666 pbe_param->keyLen = 24; | |
| 667 pbe_param->encAlg = SEC_OID_DES_EDE3_CBC; | |
| 668 break; | |
| 669 | |
| 670 /* DES Algorithms */ | |
| 671 case SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC: | |
| 672 pbe_param->hashType = HASH_AlgMD2; | |
| 673 goto finish_des; | |
| 674 case SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC: | |
| 675 pbe_param->hashType = HASH_AlgMD5; | |
| 676 /* fall through */ | |
| 677 case SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC: | |
| 678 finish_des: | |
| 679 pbe_param->keyLen = 8; | |
| 680 pbe_param->encAlg = SEC_OID_DES_CBC; | |
| 681 break; | |
| 682 | |
| 683 /* RC2 Algorithms */ | |
| 684 case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: | |
| 685 pbe_param->keyLen = 16; | |
| 686 /* fall through */ | |
| 687 case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: | |
| 688 pbe_param->pbeType = NSSPKCS5_PKCS12_V2; | |
| 689 break; | |
| 690 case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: | |
| 691 pbe_param->keyLen = 16; | |
| 692 /* fall through */ | |
| 693 case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: | |
| 694 break; | |
| 695 | |
| 696 /* RC4 algorithms */ | |
| 697 case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4: | |
| 698 skipType = PR_TRUE; | |
| 699 /* fall through */ | |
| 700 case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4: | |
| 701 pbe_param->keyLen = 16; | |
| 702 /* fall through */ | |
| 703 case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4: | |
| 704 if (!skipType) { | |
| 705 pbe_param->pbeType = NSSPKCS5_PKCS12_V2; | |
| 706 } | |
| 707 /* fall through */ | |
| 708 case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4: | |
| 709 pbe_param->ivLen = 0; | |
| 710 pbe_param->encAlg = SEC_OID_RC4; | |
| 711 break; | |
| 712 | |
| 713 case SEC_OID_PKCS5_PBKDF2: | |
| 714 case SEC_OID_PKCS5_PBES2: | |
| 715 case SEC_OID_PKCS5_PBMAC1: | |
| 716 /* everything else will be filled in by the template */ | |
| 717 pbe_param->ivLen = 0; | |
| 718 pbe_param->pbeType = NSSPKCS5_PBKDF2; | |
| 719 pbe_param->encAlg = SEC_OID_PKCS5_PBKDF2; | |
| 720 pbe_param->keyLen = 0; /* needs to be set by caller after return */ | |
| 721 break; | |
| 722 | |
| 723 default: | |
| 724 return SECFailure; | |
| 725 } | |
| 726 | |
| 727 return SECSuccess; | |
| 728 } | |
| 729 | |
| 730 /* decode the algid and generate a PKCS 5 parameter from it | |
| 731 */ | |
| 732 NSSPKCS5PBEParameter * | |
| 733 nsspkcs5_NewParam(SECOidTag alg, HASH_HashType hashType, SECItem *salt, | |
| 734 int iterationCount) | |
| 735 { | |
| 736 PLArenaPool *arena = NULL; | |
| 737 NSSPKCS5PBEParameter *pbe_param = NULL; | |
| 738 SECStatus rv = SECFailure; | |
| 739 | |
| 740 arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); | |
| 741 if (arena == NULL) | |
| 742 return NULL; | |
| 743 | |
| 744 /* allocate memory for the parameter */ | |
| 745 pbe_param = (NSSPKCS5PBEParameter *)PORT_ArenaZAlloc(arena, | |
| 746 sizeof(NSSPKCS5PBEParameter)); | |
| 747 | |
| 748 if (pbe_param == NULL) { | |
| 749 goto loser; | |
| 750 } | |
| 751 | |
| 752 pbe_param->poolp = arena; | |
| 753 | |
| 754 rv = nsspkcs5_FillInParam(alg, hashType, pbe_param); | |
| 755 if (rv != SECSuccess) { | |
| 756 goto loser; | |
| 757 } | |
| 758 | |
| 759 pbe_param->iter = iterationCount; | |
| 760 if (salt) { | |
| 761 rv = SECITEM_CopyItem(arena,&pbe_param->salt,salt); | |
| 762 } | |
| 763 | |
| 764 /* default key gen */ | |
| 765 pbe_param->keyID = pbeBitGenCipherKey; | |
| 766 | |
| 767 loser: | |
| 768 if (rv != SECSuccess) { | |
| 769 PORT_FreeArena(arena, PR_TRUE); | |
| 770 pbe_param = NULL; | |
| 771 } | |
| 772 | |
| 773 return pbe_param; | |
| 774 } | |
| 775 | |
| 776 /* | |
| 777 * find the hash type needed to implement a specific HMAC. | |
| 778 * OID definitions are from pkcs 5 v2.0 and 2.1 | |
| 779 */ | |
| 780 HASH_HashType | |
| 781 HASH_FromHMACOid(SECOidTag hmac) | |
| 782 { | |
| 783 switch (hmac) { | |
| 784 case SEC_OID_HMAC_SHA1: | |
| 785 return HASH_AlgSHA1; | |
| 786 case SEC_OID_HMAC_SHA256: | |
| 787 return HASH_AlgSHA256; | |
| 788 case SEC_OID_HMAC_SHA384: | |
| 789 return HASH_AlgSHA384; | |
| 790 case SEC_OID_HMAC_SHA512: | |
| 791 return HASH_AlgSHA512; | |
| 792 case SEC_OID_HMAC_SHA224: | |
| 793 default: | |
| 794 break; | |
| 795 } | |
| 796 return HASH_AlgNULL; | |
| 797 } | |
| 798 | |
| 799 /* decode the algid and generate a PKCS 5 parameter from it | |
| 800 */ | |
| 801 NSSPKCS5PBEParameter * | |
| 802 nsspkcs5_AlgidToParam(SECAlgorithmID *algid) | |
| 803 { | |
| 804 NSSPKCS5PBEParameter *pbe_param = NULL; | |
| 805 nsspkcs5V2PBEParameter pbev2_param; | |
| 806 SECOidTag algorithm; | |
| 807 SECStatus rv = SECFailure; | |
| 808 | |
| 809 if (algid == NULL) { | |
| 810 return NULL; | |
| 811 } | |
| 812 | |
| 813 algorithm = SECOID_GetAlgorithmTag(algid); | |
| 814 if (algorithm == SEC_OID_UNKNOWN) { | |
| 815 goto loser; | |
| 816 } | |
| 817 | |
| 818 pbe_param = nsspkcs5_NewParam(algorithm, HASH_AlgSHA1, NULL, 1); | |
| 819 if (pbe_param == NULL) { | |
| 820 goto loser; | |
| 821 } | |
| 822 | |
| 823 /* decode parameter */ | |
| 824 rv = SECFailure; | |
| 825 switch (pbe_param->pbeType) { | |
| 826 case NSSPKCS5_PBKDF1: | |
| 827 rv = SEC_ASN1DecodeItem(pbe_param->poolp, pbe_param, | |
| 828 NSSPKCS5PBEParameterTemplate, &algid->parameters); | |
| 829 break; | |
| 830 case NSSPKCS5_PKCS12_V2: | |
| 831 rv = SEC_ASN1DecodeItem(pbe_param->poolp, pbe_param, | |
| 832 NSSPKCS5PKCS12V2PBEParameterTemplate, &algid->parameters); | |
| 833 break; | |
| 834 case NSSPKCS5_PBKDF2: | |
| 835 PORT_Memset(&pbev2_param,0, sizeof(pbev2_param)); | |
| 836 /* just the PBE */ | |
| 837 if (algorithm == SEC_OID_PKCS5_PBKDF2) { | |
| 838 rv = SEC_ASN1DecodeItem(pbe_param->poolp, pbe_param, | |
| 839 NSSPKCS5V2PBEParameterTemplate, &algid->parameters); | |
| 840 } else { | |
| 841 /* PBE data an others */ | |
| 842 rv = SEC_ASN1DecodeItem(pbe_param->poolp, &pbev2_param, | |
| 843 NSSPKCS5V2PBES2ParameterTemplate, &algid->parameters); | |
| 844 if (rv != SECSuccess) { | |
| 845 break; | |
| 846 } | |
| 847 pbe_param->encAlg = SECOID_GetAlgorithmTag(&pbev2_param.algParams); | |
| 848 rv = SEC_ASN1DecodeItem(pbe_param->poolp, pbe_param, | |
| 849 NSSPKCS5V2PBEParameterTemplate, | |
| 850 &pbev2_param.keyParams.parameters); | |
| 851 if (rv != SECSuccess) { | |
| 852 break; | |
| 853 } | |
| 854 pbe_param->keyLen = DER_GetInteger(&pbe_param->keyLength); | |
| 855 } | |
| 856 /* we we are encrypting, save any iv's */ | |
| 857 if (algorithm == SEC_OID_PKCS5_PBES2) { | |
| 858 pbe_param->ivLen = pbev2_param.algParams.parameters.len; | |
| 859 pbe_param->ivData = pbev2_param.algParams.parameters.data; | |
| 860 } | |
| 861 pbe_param->hashType = | |
| 862 HASH_FromHMACOid(SECOID_GetAlgorithmTag(&pbe_param->prfAlg)); | |
| 863 if (pbe_param->hashType == HASH_AlgNULL) { | |
| 864 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); | |
| 865 rv = SECFailure; | |
| 866 } | |
| 867 break; | |
| 868 } | |
| 869 | |
| 870 loser: | |
| 871 if (rv == SECSuccess) { | |
| 872 pbe_param->iter = DER_GetInteger(&pbe_param->iteration); | |
| 873 } else { | |
| 874 nsspkcs5_DestroyPBEParameter(pbe_param); | |
| 875 pbe_param = NULL; | |
| 876 } | |
| 877 | |
| 878 return pbe_param; | |
| 879 } | |
| 880 | |
| 881 /* destroy a pbe parameter. it assumes that the parameter was | |
| 882 * generated using the appropriate create function and therefor | |
| 883 * contains an arena pool. | |
| 884 */ | |
| 885 void | |
| 886 nsspkcs5_DestroyPBEParameter(NSSPKCS5PBEParameter *pbe_param) | |
| 887 { | |
| 888 if (pbe_param != NULL) { | |
| 889 PORT_FreeArena(pbe_param->poolp, PR_FALSE); | |
| 890 } | |
| 891 } | |
| 892 | |
| 893 | |
| 894 /* crypto routines */ | |
| 895 /* perform DES encryption and decryption. these routines are called | |
| 896 * by nsspkcs5_CipherData. In the case of an error, NULL is returned. | |
| 897 */ | |
| 898 static SECItem * | |
| 899 sec_pkcs5_des(SECItem *key, SECItem *iv, SECItem *src, PRBool triple_des, | |
| 900 PRBool encrypt) | |
| 901 { | |
| 902 SECItem *dest; | |
| 903 SECItem *dup_src; | |
| 904 SECStatus rv = SECFailure; | |
| 905 int pad; | |
| 906 | |
| 907 if((src == NULL) || (key == NULL) || (iv == NULL)) | |
| 908 return NULL; | |
| 909 | |
| 910 dup_src = SECITEM_DupItem(src); | |
| 911 if(dup_src == NULL) { | |
| 912 return NULL; | |
| 913 } | |
| 914 | |
| 915 if(encrypt != PR_FALSE) { | |
| 916 void *dummy; | |
| 917 | |
| 918 dummy = CBC_PadBuffer(NULL, dup_src->data, | |
| 919 dup_src->len, &dup_src->len, 8 /* DES_BLOCK_SIZE */); | |
| 920 if(dummy == NULL) { | |
| 921 SECITEM_FreeItem(dup_src, PR_TRUE); | |
| 922 return NULL; | |
| 923 } | |
| 924 dup_src->data = (unsigned char*)dummy; | |
| 925 } | |
| 926 | |
| 927 dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); | |
| 928 if(dest != NULL) { | |
| 929 /* allocate with over flow */ | |
| 930 dest->data = (unsigned char *)PORT_ZAlloc(dup_src->len + 64); | |
| 931 if(dest->data != NULL) { | |
| 932 DESContext *ctxt; | |
| 933 ctxt = DES_CreateContext(key->data, iv->data, | |
| 934 (triple_des ? NSS_DES_EDE3_CBC : NSS_DES_CBC), | |
| 935 encrypt); | |
| 936 | |
| 937 if(ctxt != NULL) { | |
| 938 rv = (encrypt ? DES_Encrypt : DES_Decrypt)( | |
| 939 ctxt, dest->data, &dest->len, | |
| 940 dup_src->len + 64, dup_src->data, dup_src->len); | |
| 941 | |
| 942 /* remove padding -- assumes 64 bit blocks */ | |
| 943 if((encrypt == PR_FALSE) && (rv == SECSuccess)) { | |
| 944 pad = dest->data[dest->len-1]; | |
| 945 if((pad > 0) && (pad <= 8)) { | |
| 946 if(dest->data[dest->len-pad] != pad) { | |
| 947 rv = SECFailure; | |
| 948 PORT_SetError(SEC_ERROR_BAD_PASSWORD); | |
| 949 } else { | |
| 950 dest->len -= pad; | |
| 951 } | |
| 952 } else { | |
| 953 rv = SECFailure; | |
| 954 PORT_SetError(SEC_ERROR_BAD_PASSWORD); | |
| 955 } | |
| 956 } | |
| 957 DES_DestroyContext(ctxt, PR_TRUE); | |
| 958 } | |
| 959 } | |
| 960 } | |
| 961 | |
| 962 if(rv == SECFailure) { | |
| 963 if(dest != NULL) { | |
| 964 SECITEM_FreeItem(dest, PR_TRUE); | |
| 965 } | |
| 966 dest = NULL; | |
| 967 } | |
| 968 | |
| 969 if(dup_src != NULL) { | |
| 970 SECITEM_FreeItem(dup_src, PR_TRUE); | |
| 971 } | |
| 972 | |
| 973 return dest; | |
| 974 } | |
| 975 | |
| 976 /* perform aes encryption/decryption if an error occurs, NULL is returned | |
| 977 */ | |
| 978 static SECItem * | |
| 979 sec_pkcs5_aes(SECItem *key, SECItem *iv, SECItem *src, PRBool triple_des, | |
| 980 PRBool encrypt) | |
| 981 { | |
| 982 SECItem *dest; | |
| 983 SECItem *dup_src; | |
| 984 SECStatus rv = SECFailure; | |
| 985 int pad; | |
| 986 | |
| 987 if((src == NULL) || (key == NULL) || (iv == NULL)) | |
| 988 return NULL; | |
| 989 | |
| 990 dup_src = SECITEM_DupItem(src); | |
| 991 if(dup_src == NULL) { | |
| 992 return NULL; | |
| 993 } | |
| 994 | |
| 995 if(encrypt != PR_FALSE) { | |
| 996 void *dummy; | |
| 997 | |
| 998 dummy = CBC_PadBuffer(NULL, dup_src->data, | |
| 999 dup_src->len, &dup_src->len,AES_BLOCK_SIZE); | |
| 1000 if(dummy == NULL) { | |
| 1001 SECITEM_FreeItem(dup_src, PR_TRUE); | |
| 1002 return NULL; | |
| 1003 } | |
| 1004 dup_src->data = (unsigned char*)dummy; | |
| 1005 } | |
| 1006 | |
| 1007 dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); | |
| 1008 if(dest != NULL) { | |
| 1009 /* allocate with over flow */ | |
| 1010 dest->data = (unsigned char *)PORT_ZAlloc(dup_src->len + 64); | |
| 1011 if(dest->data != NULL) { | |
| 1012 AESContext *ctxt; | |
| 1013 ctxt = AES_CreateContext(key->data, iv->data, | |
| 1014 NSS_AES_CBC, encrypt, key->len, 16); | |
| 1015 | |
| 1016 if(ctxt != NULL) { | |
| 1017 rv = (encrypt ? AES_Encrypt : AES_Decrypt)( | |
| 1018 ctxt, dest->data, &dest->len, | |
| 1019 dup_src->len + 64, dup_src->data, dup_src->len); | |
| 1020 | |
| 1021 /* remove padding -- assumes 64 bit blocks */ | |
| 1022 if((encrypt == PR_FALSE) && (rv == SECSuccess)) { | |
| 1023 pad = dest->data[dest->len-1]; | |
| 1024 if((pad > 0) && (pad <= 16)) { | |
| 1025 if(dest->data[dest->len-pad] != pad) { | |
| 1026 rv = SECFailure; | |
| 1027 PORT_SetError(SEC_ERROR_BAD_PASSWORD); | |
| 1028 } else { | |
| 1029 dest->len -= pad; | |
| 1030 } | |
| 1031 } else { | |
| 1032 rv = SECFailure; | |
| 1033 PORT_SetError(SEC_ERROR_BAD_PASSWORD); | |
| 1034 } | |
| 1035 } | |
| 1036 AES_DestroyContext(ctxt, PR_TRUE); | |
| 1037 } | |
| 1038 } | |
| 1039 } | |
| 1040 | |
| 1041 if(rv == SECFailure) { | |
| 1042 if(dest != NULL) { | |
| 1043 SECITEM_FreeItem(dest, PR_TRUE); | |
| 1044 } | |
| 1045 dest = NULL; | |
| 1046 } | |
| 1047 | |
| 1048 if(dup_src != NULL) { | |
| 1049 SECITEM_FreeItem(dup_src, PR_TRUE); | |
| 1050 } | |
| 1051 | |
| 1052 return dest; | |
| 1053 } | |
| 1054 | |
| 1055 /* perform rc2 encryption/decryption if an error occurs, NULL is returned | |
| 1056 */ | |
| 1057 static SECItem * | |
| 1058 sec_pkcs5_rc2(SECItem *key, SECItem *iv, SECItem *src, PRBool dummy, | |
| 1059 PRBool encrypt) | |
| 1060 { | |
| 1061 SECItem *dest; | |
| 1062 SECItem *dup_src; | |
| 1063 SECStatus rv = SECFailure; | |
| 1064 int pad; | |
| 1065 | |
| 1066 if((src == NULL) || (key == NULL) || (iv == NULL)) { | |
| 1067 return NULL; | |
| 1068 } | |
| 1069 | |
| 1070 dup_src = SECITEM_DupItem(src); | |
| 1071 if(dup_src == NULL) { | |
| 1072 return NULL; | |
| 1073 } | |
| 1074 | |
| 1075 if(encrypt != PR_FALSE) { | |
| 1076 void *dummy; | |
| 1077 | |
| 1078 dummy = CBC_PadBuffer(NULL, dup_src->data, | |
| 1079 dup_src->len, &dup_src->len, 8 /* RC2_BLOCK_SIZE */); | |
| 1080 if(dummy == NULL) { | |
| 1081 SECITEM_FreeItem(dup_src, PR_TRUE); | |
| 1082 return NULL; | |
| 1083 } | |
| 1084 dup_src->data = (unsigned char*)dummy; | |
| 1085 } | |
| 1086 | |
| 1087 dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); | |
| 1088 if(dest != NULL) { | |
| 1089 dest->data = (unsigned char *)PORT_ZAlloc(dup_src->len + 64); | |
| 1090 if(dest->data != NULL) { | |
| 1091 RC2Context *ctxt; | |
| 1092 | |
| 1093 ctxt = RC2_CreateContext(key->data, key->len, iv->data, | |
| 1094 NSS_RC2_CBC, key->len); | |
| 1095 | |
| 1096 if(ctxt != NULL) { | |
| 1097 rv = (encrypt ? RC2_Encrypt: RC2_Decrypt)( | |
| 1098 ctxt, dest->data, &dest->len, | |
| 1099 dup_src->len + 64, dup_src->data, dup_src->len); | |
| 1100 | |
| 1101 /* assumes 8 byte blocks -- remove padding */ | |
| 1102 if((rv == SECSuccess) && (encrypt != PR_TRUE)) { | |
| 1103 pad = dest->data[dest->len-1]; | |
| 1104 if((pad > 0) && (pad <= 8)) { | |
| 1105 if(dest->data[dest->len-pad] != pad) { | |
| 1106 PORT_SetError(SEC_ERROR_BAD_PASSWORD); | |
| 1107 rv = SECFailure; | |
| 1108 } else { | |
| 1109 dest->len -= pad; | |
| 1110 } | |
| 1111 } else { | |
| 1112 PORT_SetError(SEC_ERROR_BAD_PASSWORD); | |
| 1113 rv = SECFailure; | |
| 1114 } | |
| 1115 } | |
| 1116 | |
| 1117 } | |
| 1118 } | |
| 1119 } | |
| 1120 | |
| 1121 if((rv != SECSuccess) && (dest != NULL)) { | |
| 1122 SECITEM_FreeItem(dest, PR_TRUE); | |
| 1123 dest = NULL; | |
| 1124 } | |
| 1125 | |
| 1126 if(dup_src != NULL) { | |
| 1127 SECITEM_FreeItem(dup_src, PR_TRUE); | |
| 1128 } | |
| 1129 | |
| 1130 return dest; | |
| 1131 } | |
| 1132 | |
| 1133 /* perform rc4 encryption and decryption */ | |
| 1134 static SECItem * | |
| 1135 sec_pkcs5_rc4(SECItem *key, SECItem *iv, SECItem *src, PRBool dummy_op, | |
| 1136 PRBool encrypt) | |
| 1137 { | |
| 1138 SECItem *dest; | |
| 1139 SECStatus rv = SECFailure; | |
| 1140 | |
| 1141 if((src == NULL) || (key == NULL) || (iv == NULL)) { | |
| 1142 return NULL; | |
| 1143 } | |
| 1144 | |
| 1145 dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); | |
| 1146 if(dest != NULL) { | |
| 1147 dest->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) * | |
| 1148 (src->len + 64)); | |
| 1149 if(dest->data != NULL) { | |
| 1150 RC4Context *ctxt; | |
| 1151 | |
| 1152 ctxt = RC4_CreateContext(key->data, key->len); | |
| 1153 if(ctxt) { | |
| 1154 rv = (encrypt ? RC4_Encrypt : RC4_Decrypt)( | |
| 1155 ctxt, dest->data, &dest->len, | |
| 1156 src->len + 64, src->data, src->len); | |
| 1157 RC4_DestroyContext(ctxt, PR_TRUE); | |
| 1158 } | |
| 1159 } | |
| 1160 } | |
| 1161 | |
| 1162 if((rv != SECSuccess) && (dest)) { | |
| 1163 SECITEM_FreeItem(dest, PR_TRUE); | |
| 1164 dest = NULL; | |
| 1165 } | |
| 1166 | |
| 1167 return dest; | |
| 1168 } | |
| 1169 /* function pointer template for crypto functions */ | |
| 1170 typedef SECItem *(* pkcs5_crypto_func)(SECItem *key, SECItem *iv, | |
| 1171 SECItem *src, PRBool op1, PRBool op2); | |
| 1172 | |
| 1173 /* performs the cipher operation on the src and returns the result. | |
| 1174 * if an error occurs, NULL is returned. | |
| 1175 * | |
| 1176 * a null length password is allowed. this corresponds to encrypting | |
| 1177 * the data with ust the salt. | |
| 1178 */ | |
| 1179 /* change this to use PKCS 11? */ | |
| 1180 SECItem * | |
| 1181 nsspkcs5_CipherData(NSSPKCS5PBEParameter *pbe_param, SECItem *pwitem, | |
| 1182 SECItem *src, PRBool encrypt, PRBool *update) | |
| 1183 { | |
| 1184 SECItem *key = NULL, iv; | |
| 1185 SECItem *dest = NULL; | |
| 1186 PRBool tripleDES = PR_TRUE; | |
| 1187 pkcs5_crypto_func cryptof; | |
| 1188 | |
| 1189 iv.data = NULL; | |
| 1190 | |
| 1191 if (update) { | |
| 1192 *update = PR_FALSE; | |
| 1193 } | |
| 1194 | |
| 1195 if ((pwitem == NULL) || (src == NULL)) { | |
| 1196 return NULL; | |
| 1197 } | |
| 1198 | |
| 1199 /* get key, and iv */ | |
| 1200 key = nsspkcs5_ComputeKeyAndIV(pbe_param, pwitem, &iv, PR_FALSE); | |
| 1201 if(key == NULL) { | |
| 1202 return NULL; | |
| 1203 } | |
| 1204 | |
| 1205 switch(pbe_param->encAlg) { | |
| 1206 /* PKCS 5 v2 only */ | |
| 1207 case SEC_OID_AES_128_CBC: | |
| 1208 case SEC_OID_AES_192_CBC: | |
| 1209 case SEC_OID_AES_256_CBC: | |
| 1210 cryptof = sec_pkcs5_aes; | |
| 1211 break; | |
| 1212 case SEC_OID_DES_EDE3_CBC: | |
| 1213 cryptof = sec_pkcs5_des; | |
| 1214 tripleDES = PR_TRUE; | |
| 1215 break; | |
| 1216 case SEC_OID_DES_CBC: | |
| 1217 cryptof = sec_pkcs5_des; | |
| 1218 tripleDES = PR_FALSE; | |
| 1219 break; | |
| 1220 case SEC_OID_RC2_CBC: | |
| 1221 cryptof = sec_pkcs5_rc2; | |
| 1222 break; | |
| 1223 case SEC_OID_RC4: | |
| 1224 cryptof = sec_pkcs5_rc4; | |
| 1225 break; | |
| 1226 default: | |
| 1227 cryptof = NULL; | |
| 1228 break; | |
| 1229 } | |
| 1230 | |
| 1231 if (cryptof == NULL) { | |
| 1232 goto loser; | |
| 1233 } | |
| 1234 | |
| 1235 dest = (*cryptof)(key, &iv, src, tripleDES, encrypt); | |
| 1236 /* | |
| 1237 * it's possible for some keys and keydb's to claim to | |
| 1238 * be triple des when they're really des. In this case | |
| 1239 * we simply try des. If des works we set the update flag | |
| 1240 * so the key db knows it needs to update all it's entries. | |
| 1241 * The case can only happen on decrypted of a | |
| 1242 * SEC_OID_DES_EDE3_CBD. | |
| 1243 */ | |
| 1244 if ((dest == NULL) && (encrypt == PR_FALSE) && | |
| 1245 (pbe_param->encAlg == SEC_OID_DES_EDE3_CBC)) { | |
| 1246 dest = (*cryptof)(key, &iv, src, PR_FALSE, encrypt); | |
| 1247 if (update && (dest != NULL)) *update = PR_TRUE; | |
| 1248 } | |
| 1249 | |
| 1250 loser: | |
| 1251 if (key != NULL) { | |
| 1252 SECITEM_ZfreeItem(key, PR_TRUE); | |
| 1253 } | |
| 1254 if (iv.data != NULL) { | |
| 1255 SECITEM_ZfreeItem(&iv, PR_FALSE); | |
| 1256 } | |
| 1257 | |
| 1258 return dest; | |
| 1259 } | |
| 1260 | |
| 1261 /* creates a algorithm ID containing the PBE algorithm and appropriate | |
| 1262 * parameters. the required parameter is the algorithm. if salt is | |
| 1263 * not specified, it is generated randomly. if IV is specified, it overrides | |
| 1264 * the PKCS 5 generation of the IV. | |
| 1265 * | |
| 1266 * the returned SECAlgorithmID should be destroyed using | |
| 1267 * SECOID_DestroyAlgorithmID | |
| 1268 */ | |
| 1269 SECAlgorithmID * | |
| 1270 nsspkcs5_CreateAlgorithmID(PLArenaPool *arena, SECOidTag algorithm, | |
| 1271 NSSPKCS5PBEParameter *pbe_param) | |
| 1272 { | |
| 1273 SECAlgorithmID *algid, *ret_algid = NULL; | |
| 1274 SECItem der_param; | |
| 1275 nsspkcs5V2PBEParameter pkcs5v2_param; | |
| 1276 | |
| 1277 SECStatus rv = SECFailure; | |
| 1278 void *dummy = NULL; | |
| 1279 | |
| 1280 if (arena == NULL) { | |
| 1281 return NULL; | |
| 1282 } | |
| 1283 | |
| 1284 der_param.data = NULL; | |
| 1285 der_param.len = 0; | |
| 1286 | |
| 1287 /* generate the algorithm id */ | |
| 1288 algid = (SECAlgorithmID *)PORT_ArenaZAlloc(arena, sizeof(SECAlgorithmID)); | |
| 1289 if (algid == NULL) { | |
| 1290 goto loser; | |
| 1291 } | |
| 1292 | |
| 1293 if (pbe_param->iteration.data == NULL) { | |
| 1294 dummy = SEC_ASN1EncodeInteger(pbe_param->poolp,&pbe_param->iteration, | |
| 1295 pbe_param->iter)
; | |
| 1296 if (dummy == NULL) { | |
| 1297 goto loser; | |
| 1298 } | |
| 1299 } | |
| 1300 switch (pbe_param->pbeType) { | |
| 1301 case NSSPKCS5_PBKDF1: | |
| 1302 dummy = SEC_ASN1EncodeItem(arena, &der_param, pbe_param, | |
| 1303 NSSPKCS5PBEParameterTemplate); | |
| 1304 break; | |
| 1305 case NSSPKCS5_PKCS12_V2: | |
| 1306 dummy = SEC_ASN1EncodeItem(arena, &der_param, pbe_param, | |
| 1307 NSSPKCS5PKCS12V2PBEParameterTemplate); | |
| 1308 break; | |
| 1309 case NSSPKCS5_PBKDF2: | |
| 1310 if (pbe_param->keyLength.data == NULL) { | |
| 1311 dummy = SEC_ASN1EncodeInteger(pbe_param->poolp, | |
| 1312 &pbe_param->keyLength, pbe_param->keyLen); | |
| 1313 if (dummy == NULL) { | |
| 1314 goto loser; | |
| 1315 } | |
| 1316 } | |
| 1317 PORT_Memset(&pkcs5v2_param, 0, sizeof(pkcs5v2_param)); | |
| 1318 dummy = SEC_ASN1EncodeItem(arena, &der_param, pbe_param, | |
| 1319 NSSPKCS5V2PBEParameterTemplate); | |
| 1320 if (dummy == NULL) { | |
| 1321 break; | |
| 1322 } | |
| 1323 dummy = NULL; | |
| 1324 rv = SECOID_SetAlgorithmID(arena, &pkcs5v2_param.keyParams, | |
| 1325 SEC_OID_PKCS5_PBKDF2, &der_param); | |
| 1326 if (rv != SECSuccess) { | |
| 1327 break; | |
| 1328 } | |
| 1329 der_param.data = pbe_param->ivData; | |
| 1330 der_param.len = pbe_param->ivLen; | |
| 1331 rv = SECOID_SetAlgorithmID(arena, &pkcs5v2_param.algParams, | |
| 1332 pbe_param->encAlg, pbe_param->ivLen ? &der_param : NULL); | |
| 1333 if (rv != SECSuccess) { | |
| 1334 break; | |
| 1335 } | |
| 1336 dummy = SEC_ASN1EncodeItem(arena, &der_param, &pkcs5v2_param, | |
| 1337 NSSPKCS5V2PBES2ParameterTemplate); | |
| 1338 break; | |
| 1339 default: | |
| 1340 break; | |
| 1341 } | |
| 1342 | |
| 1343 if (dummy == NULL) { | |
| 1344 goto loser; | |
| 1345 } | |
| 1346 | |
| 1347 rv = SECOID_SetAlgorithmID(arena, algid, algorithm, &der_param); | |
| 1348 if (rv != SECSuccess) { | |
| 1349 goto loser; | |
| 1350 } | |
| 1351 | |
| 1352 ret_algid = (SECAlgorithmID *)PORT_ZAlloc(sizeof(SECAlgorithmID)); | |
| 1353 if (ret_algid == NULL) { | |
| 1354 goto loser; | |
| 1355 } | |
| 1356 | |
| 1357 rv = SECOID_CopyAlgorithmID(NULL, ret_algid, algid); | |
| 1358 if (rv != SECSuccess) { | |
| 1359 SECOID_DestroyAlgorithmID(ret_algid, PR_TRUE); | |
| 1360 ret_algid = NULL; | |
| 1361 } | |
| 1362 | |
| 1363 loser: | |
| 1364 | |
| 1365 return ret_algid; | |
| 1366 } | |
| OLD | NEW |