int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { int ret=0; int top,al,bl; BIGNUM *rr; #if defined(BN_MUL_COMBA) || defined(BN_RECURSION) int i; #endif #ifdef BN_RECURSION BIGNUM *t=NULL; int j=0,k; #endif bn_check_top(a); bn_check_top(b); bn_check_top(r); al=a->top; bl=b->top; if ((al == 0) || (bl == 0)) { BN_zero(r); return(1); } top=al+bl; BN_CTX_start(ctx); if ((r == a) || (r == b)) { if ((rr = BN_CTX_get(ctx)) == NULL) goto err; } else rr = r; rr->neg=a->neg^b->neg; #if defined(BN_MUL_COMBA) || defined(BN_RECURSION) i = al-bl; #endif #ifdef BN_MUL_COMBA if (i == 0) { # if 0 if (al == 4) { if (bn_wexpand(rr,8) == NULL) goto err; rr->top=8; bn_mul_comba4(rr->d,a->d,b->d); goto end; } # endif if (al == 8) { if (bn_wexpand(rr,16) == NULL) goto err; rr->top=16; bn_mul_comba8(rr->d,a->d,b->d); goto end; } } #endif /* BN_MUL_COMBA */ #ifdef BN_RECURSION if ((al >= BN_MULL_SIZE_NORMAL) && (bl >= BN_MULL_SIZE_NORMAL)) { if (i >= -1 && i <= 1) { int sav_j =0; /* Find out the power of two lower or equal to the longest of the two numbers */ if (i >= 0) { j = BN_num_bits_word((BN_ULONG)al); } if (i == -1) { j = BN_num_bits_word((BN_ULONG)bl); } sav_j = j; j = 1<<(j-1); //assert(j <= al || j <= bl); k = j+j; t = BN_CTX_get(ctx); if (t == NULL) goto err; if (al > j || bl > j) { if (bn_wexpand(t,k*4) == NULL) goto err; if (bn_wexpand(rr,k*4) == NULL) goto err; bn_mul_part_recursive(rr->d,a->d,b->d, j,al-j,bl-j,t->d); } else /* al <= j || bl <= j */ { if (bn_wexpand(t,k*2) == NULL) goto err; if (bn_wexpand(rr,k*2) == NULL) goto err; bn_mul_recursive(rr->d,a->d,b->d, j,al-j,bl-j,t->d); } rr->top=top; goto end; } #if 0 if (i == 1 && !BN_get_flags(b,BN_FLG_STATIC_DATA)) { BIGNUM *tmp_bn = (BIGNUM *)b; if (bn_wexpand(tmp_bn,al) == NULL) goto err; tmp_bn->d[bl]=0; bl++; i--; } else if (i == -1 && !BN_get_flags(a,BN_FLG_STATIC_DATA)) { BIGNUM *tmp_bn = (BIGNUM *)a; if (bn_wexpand(tmp_bn,bl) == NULL) goto err; tmp_bn->d[al]=0; al++; i++; } if (i == 0) { /* symmetric and > 4 */ /* 16 or larger */ j=BN_num_bits_word((BN_ULONG)al); j=1<<(j-1); k=j+j; t = BN_CTX_get(ctx); if (al == j) /* exact multiple */ { if (bn_wexpand(t,k*2) == NULL) goto err; if (bn_wexpand(rr,k*2) == NULL) goto err; bn_mul_recursive(rr->d,a->d,b->d,al,t->d); } else { if (bn_wexpand(t,k*4) == NULL) goto err; if (bn_wexpand(rr,k*4) == NULL) goto err; bn_mul_part_recursive(rr->d,a->d,b->d,al-j,j,t->d); } rr->top=top; goto end; } #endif } #endif /* BN_RECURSION */ if (bn_wexpand(rr,top) == NULL) goto err; rr->top=top; bn_mul_normal(rr->d,a->d,al,b->d,bl); #if defined(BN_MUL_COMBA) || defined(BN_RECURSION) end: #endif bn_correct_top(rr); if (r != rr) BN_copy(r,rr); ret=1; err: bn_check_top(r); BN_CTX_end(ctx); return(ret); }
/* DH stuff Functions */ static int DH_zencod_generate_key ( DH *dh ) { BIGNUM *bn_prv = NULL; BIGNUM *bn_pub = NULL; zen_nb_t y, x, g, p; int generate_x; CHEESE(); if ( !zencod_dso ) { ENGINEerr(ZENCOD_F_ZENCOD_DH_GENERATE, ZENCOD_R_NOT_LOADED); return 0; } /* Private key */ if ( dh->priv_key ) { bn_prv = dh->priv_key; generate_x = 0; } else { if (!(bn_prv = BN_new())) { ENGINEerr(ZENCOD_F_ZENCOD_DH_GENERATE, ZENCOD_R_BN_EXPAND_FAIL); goto FAILED; } generate_x = 1; } /* Public key */ if ( dh->pub_key ) bn_pub = dh->pub_key; else if ( !( bn_pub = BN_new () ) ) { ENGINEerr(ZENCOD_F_ZENCOD_DH_GENERATE, ZENCOD_R_BN_EXPAND_FAIL); goto FAILED; } /* Expand */ if ( !bn_wexpand ( bn_prv, dh->p->dmax ) || !bn_wexpand ( bn_pub, dh->p->dmax ) ) { ENGINEerr(ZENCOD_F_ZENCOD_DH_GENERATE, ZENCOD_R_BN_EXPAND_FAIL); goto FAILED; } bn_prv->top = dh->p->top; bn_pub->top = dh->p->top; /* Convert all keys */ BIGNUM2ZEN ( &p, dh->p ) ; BIGNUM2ZEN ( &g, dh->g ) ; BIGNUM2ZEN ( &y, bn_pub ) ; BIGNUM2ZEN ( &x, bn_prv ) ; x.len = DH_size(dh) * 8; /* Adjust the lengths of P and G */ p.len = ptr_zencod_bytes2bits ( p.data, ZEN_BYTES ( p.len ) ) ; g.len = ptr_zencod_bytes2bits ( g.data, ZEN_BYTES ( g.len ) ) ; /* Send the request to the driver */ if ( ptr_zencod_dh_generate_key ( &y, &x, &g, &p, generate_x ) < 0 ) { perror("zenbridge_dh_generate_key"); ENGINEerr(ZENCOD_F_ZENCOD_DH_GENERATE, ZENCOD_R_REQUEST_FAILED); goto FAILED; } dh->priv_key = bn_prv; dh->pub_key = bn_pub; return 1; FAILED: if (!dh->priv_key && bn_prv) BN_free(bn_prv); if (!dh->pub_key && bn_pub) BN_free(bn_pub); return 0; }
static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, const BN_MONT_CTX *mont) { const BIGNUM *n; BN_ULONG *ap, *np, *rp, n0, v, carry; int nl, max, i; n = &mont->N; nl = n->top; if (nl == 0) { ret->top = 0; return 1; } max = (2 * nl); /* carry is stored separately */ if (bn_wexpand(r, max) == NULL) { return 0; } r->neg ^= n->neg; np = n->d; rp = r->d; /* clear the top words of T */ if (max > r->top) { memset(&rp[r->top], 0, (max - r->top) * sizeof(BN_ULONG)); } r->top = max; n0 = mont->n0[0]; for (carry = 0, i = 0; i < nl; i++, rp++) { v = bn_mul_add_words(rp, np, nl, (rp[0] * n0) & BN_MASK2); v = (v + carry + rp[nl]) & BN_MASK2; carry |= (v != rp[nl]); carry &= (v <= rp[nl]); rp[nl] = v; } if (bn_wexpand(ret, nl) == NULL) { return 0; } ret->top = nl; ret->neg = r->neg; rp = ret->d; ap = &(r->d[nl]); { BN_ULONG *nrp; size_t m; v = bn_sub_words(rp, ap, np, nl) - carry; /* if subtraction result is real, then trick unconditional memcpy below to * perform in-place "refresh" instead of actual copy. */ m = (0 - (size_t)v); nrp = (BN_ULONG *)(((intptr_t)rp & ~m) | ((intptr_t)ap & m)); for (i = 0, nl -= 4; i < nl; i += 4) { BN_ULONG t1, t2, t3, t4; t1 = nrp[i + 0]; t2 = nrp[i + 1]; t3 = nrp[i + 2]; ap[i + 0] = 0; t4 = nrp[i + 3]; ap[i + 1] = 0; rp[i + 0] = t1; ap[i + 2] = 0; rp[i + 1] = t2; ap[i + 3] = 0; rp[i + 2] = t3; rp[i + 3] = t4; } for (nl += 4; i < nl; i++) { rp[i] = nrp[i], ap[i] = 0; } } bn_correct_top(r); bn_correct_top(ret); return 1; }
/* unsigned subtraction of b from a, a must be larger than b. */ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { int max, min, dif; register BN_ULONG t1, t2, *rp; register const BN_ULONG *ap, *bp; int i, carry; bn_check_top(a); bn_check_top(b); max = a->top; min = b->top; dif = max - min; if (dif < 0) { /* hmm... should not be happening */ BNerr(BN_F_BN_USUB, BN_R_ARG2_LT_ARG3); return (0); } if (bn_wexpand(r, max) == NULL) return (0); ap = a->d; bp = b->d; rp = r->d; #if 1 carry = 0; for (i = min; i != 0; i--) { t1 = *(ap++); t2 = *(bp++); if (carry) { carry = (t1 <= t2); t1 = (t1 - t2 - 1) & BN_MASK2; } else { carry = (t1 < t2); t1 = (t1 - t2) & BN_MASK2; } *(rp++) = t1 & BN_MASK2; } #else carry = bn_sub_words(rp, ap, bp, min); ap += min; bp += min; rp += min; #endif if (carry) { /* subtracted */ if (!dif) /* error: a < b */ return 0; while (dif) { dif--; t1 = *(ap++); t2 = (t1 - 1) & BN_MASK2; *(rp++) = t2; if (t1) break; } } memcpy(rp, ap, sizeof(*rp) * dif); r->top = max; r->neg = 0; bn_correct_top(r); return (1); }
static int atalla_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx) { /* I need somewhere to store temporary serialised values for * use with the Atalla API calls. A neat cheat - I'll use * BIGNUMs from the BN_CTX but access their arrays directly as * byte arrays <grin>. This way I don't have to clean anything * up. */ BIGNUM *modulus; BIGNUM *exponent; BIGNUM *argument; BIGNUM *result; RSAPrivateKey keydata; int to_return, numbytes; modulus = exponent = argument = result = NULL; to_return = 0; /* expect failure */ if(!atalla_dso) { ATALLAerr(ATALLA_F_ATALLA_MOD_EXP,ATALLA_R_NOT_LOADED); goto err; } /* Prepare the params */ BN_CTX_start(ctx); modulus = BN_CTX_get(ctx); exponent = BN_CTX_get(ctx); argument = BN_CTX_get(ctx); result = BN_CTX_get(ctx); if (!result) { ATALLAerr(ATALLA_F_ATALLA_MOD_EXP,ATALLA_R_BN_CTX_FULL); goto err; } if(!bn_wexpand(modulus, m->top) || !bn_wexpand(exponent, m->top) || !bn_wexpand(argument, m->top) || !bn_wexpand(result, m->top)) { ATALLAerr(ATALLA_F_ATALLA_MOD_EXP,ATALLA_R_BN_EXPAND_FAIL); goto err; } /* Prepare the key-data */ memset(&keydata, 0,sizeof keydata); numbytes = BN_num_bytes(m); memset(exponent->d, 0, numbytes); memset(modulus->d, 0, numbytes); BN_bn2bin(p, (unsigned char *)exponent->d + numbytes - BN_num_bytes(p)); BN_bn2bin(m, (unsigned char *)modulus->d + numbytes - BN_num_bytes(m)); keydata.privateExponent.data = (unsigned char *)exponent->d; keydata.privateExponent.len = numbytes; keydata.modulus.data = (unsigned char *)modulus->d; keydata.modulus.len = numbytes; /* Prepare the argument */ memset(argument->d, 0, numbytes); memset(result->d, 0, numbytes); BN_bn2bin(a, (unsigned char *)argument->d + numbytes - BN_num_bytes(a)); /* Perform the operation */ if(p_Atalla_RSAPrivateKeyOpFn(&keydata, (unsigned char *)result->d, (unsigned char *)argument->d, keydata.modulus.len) != 0) { ATALLAerr(ATALLA_F_ATALLA_MOD_EXP,ATALLA_R_REQUEST_FAILED); goto err; } /* Convert the response */ BN_bin2bn((unsigned char *)result->d, numbytes, r); to_return = 1; err: BN_CTX_end(ctx); return to_return; }
int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) { int max, al; int ret = 0; BIGNUM *tmp, *rr; al = a->top; if (al <= 0) { r->top = 0; r->neg = 0; return 1; } BN_CTX_start(ctx); rr = (a != r) ? r : BN_CTX_get(ctx); tmp = BN_CTX_get(ctx); if (!rr || !tmp) { goto err; } max = 2 * al; /* Non-zero (from above) */ if (bn_wexpand(rr, max) == NULL) { goto err; } if (al == 4) { bn_sqr_comba4(rr->d, a->d); } else if (al == 8) { bn_sqr_comba8(rr->d, a->d); } else { if (al < BN_SQR_RECURSIVE_SIZE_NORMAL) { BN_ULONG t[BN_SQR_RECURSIVE_SIZE_NORMAL * 2]; bn_sqr_normal(rr->d, a->d, al, t); } else { int j, k; j = BN_num_bits_word((BN_ULONG)al); j = 1 << (j - 1); k = j + j; if (al == j) { if (bn_wexpand(tmp, k * 2) == NULL) { goto err; } bn_sqr_recursive(rr->d, a->d, al, tmp->d); } else { if (bn_wexpand(tmp, max) == NULL) { goto err; } bn_sqr_normal(rr->d, a->d, al, tmp->d); } } } rr->neg = 0; /* If the most-significant half of the top word of 'a' is zero, then * the square of 'a' will max-1 words. */ if (a->d[al - 1] == (a->d[al - 1] & BN_MASK2l)) { rr->top = max - 1; } else { rr->top = max; } if (rr != r && !BN_copy(r, rr)) { goto err; } ret = 1; err: BN_CTX_end(ctx); return ret; }
int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx) { int i, nm, nd; int ret = 0; BIGNUM *D; bn_check_top(m); bn_check_top(d); if (BN_is_zero(d)) { BNerr(BN_F_BN_DIV, BN_R_DIV_BY_ZERO); return (0); } if (BN_ucmp(m, d) < 0) { if (rem != NULL) { if (BN_copy(rem, m) == NULL) return (0); } if (dv != NULL) BN_zero(dv); return (1); } BN_CTX_start(ctx); D = BN_CTX_get(ctx); if (dv == NULL) dv = BN_CTX_get(ctx); if (rem == NULL) rem = BN_CTX_get(ctx); if (D == NULL || dv == NULL || rem == NULL) goto end; nd = BN_num_bits(d); nm = BN_num_bits(m); if (BN_copy(D, d) == NULL) goto end; if (BN_copy(rem, m) == NULL) goto end; /* * The next 2 are needed so we can do a dv->d[0]|=1 later since * BN_lshift1 will only work once there is a value :-) */ BN_zero(dv); if (bn_wexpand(dv, 1) == NULL) goto end; dv->top = 1; if (!BN_lshift(D, D, nm - nd)) goto end; for (i = nm - nd; i >= 0; i--) { if (!BN_lshift1(dv, dv)) goto end; if (BN_ucmp(rem, D) >= 0) { dv->d[0] |= 1; if (!BN_usub(rem, rem, D)) goto end; } /* CAN IMPROVE (and have now :=) */ if (!BN_rshift1(D, D)) goto end; } rem->neg = BN_is_zero(rem) ? 0 : m->neg; dv->neg = m->neg ^ d->neg; ret = 1; end: BN_CTX_end(ctx); return (ret); }
static int ubsec_dh_generate_key(DH *dh) { int ret = 0, random_bits = 0, pub_key_len = 0, priv_key_len = 0, fd; BIGNUM *pub_key = NULL; BIGNUM *priv_key = NULL; /* * How many bits should Random x be? dh_key.c * sets the range from 0 to num_bits(modulus) ??? */ if (dh->priv_key == NULL) { priv_key = BN_new(); if (priv_key == NULL) goto err; priv_key_len = BN_num_bits(dh->p); if (bn_wexpand(priv_key, dh->p->top) == NULL) goto err; do if (!BN_rand_range(priv_key, dh->p)) goto err; while (BN_is_zero(priv_key)) ; random_bits = BN_num_bits(priv_key); } else { priv_key = dh->priv_key; } if (dh->pub_key == NULL) { pub_key = BN_new(); if (pub_key == NULL) goto err; pub_key_len = BN_num_bits(dh->p); if (bn_wexpand(pub_key, dh->p->top) == NULL) goto err; } else { pub_key = dh->pub_key; } if ((fd = p_UBSEC_ubsec_open(UBSEC_KEY_DEVICE_NAME)) <= 0) { const DH_METHOD *meth; UBSECerr(UBSEC_F_UBSEC_DH_GENERATE_KEY, UBSEC_R_UNIT_FAILURE); meth = DH_OpenSSL(); ret = meth->generate_key(dh); goto err; } if (p_UBSEC_diffie_hellman_generate_ioctl(fd, (unsigned char *)priv_key->d, &priv_key_len, (unsigned char *)pub_key->d, &pub_key_len, (unsigned char *)dh->g->d, BN_num_bits(dh->g), (unsigned char *)dh->p->d, BN_num_bits(dh->p), 0, 0, random_bits) != 0) { /* Hardware's a no go, failover to software */ const DH_METHOD *meth; UBSECerr(UBSEC_F_UBSEC_DH_GENERATE_KEY, UBSEC_R_REQUEST_FAILED); p_UBSEC_ubsec_close(fd); meth = DH_OpenSSL(); ret = meth->generate_key(dh); goto err; } p_UBSEC_ubsec_close(fd); dh->pub_key = pub_key; dh->pub_key->top = (pub_key_len + BN_BITS2 - 1) / BN_BITS2; dh->priv_key = priv_key; dh->priv_key->top = (priv_key_len + BN_BITS2 - 1) / BN_BITS2; ret = 1; err: return ret; }
/* Ein kleines chinesisches "Restessen" */ static int ibmca_mod_exp_crt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *q, const BIGNUM *dmp1, const BIGNUM *dmq1, const BIGNUM *iqmp, BN_CTX *ctx) { BIGNUM *argument = NULL; BIGNUM *result = NULL; BIGNUM *key = NULL; int to_return = 0; /* expect failure */ char *pkey=NULL; ICA_KEY_RSA_CRT *privKey=NULL; int inLen, outLen; int rc; unsigned int offset, pSize, qSize; /* SAB New variables */ unsigned int keyRecordSize; unsigned int pbytes = BN_num_bytes(p); unsigned int qbytes = BN_num_bytes(q); unsigned int dmp1bytes = BN_num_bytes(dmp1); unsigned int dmq1bytes = BN_num_bytes(dmq1); unsigned int iqmpbytes = BN_num_bytes(iqmp); /* Prepare the params */ BN_CTX_start(ctx); argument = BN_CTX_get(ctx); result = BN_CTX_get(ctx); key = BN_CTX_get(ctx); if(!argument || !result || !key) { IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_BN_CTX_FULL); goto err; } if(!bn_wexpand(argument, p->top + q->top) || !bn_wexpand(result, p->top + q->top) || !bn_wexpand(key, sizeof(*privKey)/BN_BYTES )) { IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_BN_EXPAND_FAIL); goto err; } privKey = (ICA_KEY_RSA_CRT *)key->d; /* SAB Add check for total size in bytes of the parms does not exceed the buffer space we have do this first */ keyRecordSize = pbytes+qbytes+dmp1bytes+dmq1bytes+iqmpbytes; if ( keyRecordSize > sizeof(privKey->keyRecord )) { IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OPERANDS_TO_LARGE); goto err; } if ( (qbytes + dmq1bytes) > 256 ){ IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OPERANDS_TO_LARGE); goto err; } if ( pbytes + dmp1bytes > 256 ) { IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OPERANDS_TO_LARGE); goto err; } /* end SAB additions */ memset(privKey, 0, sizeof(ICA_KEY_RSA_CRT)); privKey->keyType = CORRECT_ENDIANNESS(CRT_KEY_TYPE); privKey->keyLength = CORRECT_ENDIANNESS(sizeof(ICA_KEY_RSA_CRT)); privKey->modulusBitLength = CORRECT_ENDIANNESS(BN_num_bytes(q) * 2 * 8); /* * p,dp & qInv are 1 QWORD Larger */ privKey->pLength = CORRECT_ENDIANNESS(BN_num_bytes(p)+8); privKey->qLength = CORRECT_ENDIANNESS(BN_num_bytes(q)); privKey->dpLength = CORRECT_ENDIANNESS(BN_num_bytes(dmp1)+8); privKey->dqLength = CORRECT_ENDIANNESS(BN_num_bytes(dmq1)); privKey->qInvLength = CORRECT_ENDIANNESS(BN_num_bytes(iqmp)+8); offset = (char *) privKey->keyRecord - (char *) privKey; qSize = BN_num_bytes(q); pSize = qSize + 8; /* 1 QWORD larger */ /* SAB probably aittle redundant, but we'll verify that each of the components which make up a key record sent ot the card does not exceed the space that is allocated for it. this handles the case where even if the total length does not exceed keyrecord zied, if the operands are funny sized they could cause potential side affects on either the card or the result */ if ( (pbytes > pSize) || (dmp1bytes > pSize) || (iqmpbytes > pSize) || ( qbytes >qSize) || (dmq1bytes > qSize) ) { IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_OPERANDS_TO_LARGE); goto err; } privKey->dpOffset = CORRECT_ENDIANNESS(offset); offset += pSize; privKey->dqOffset = CORRECT_ENDIANNESS(offset); offset += qSize; privKey->pOffset = CORRECT_ENDIANNESS(offset); offset += pSize; privKey->qOffset = CORRECT_ENDIANNESS(offset); offset += qSize; privKey->qInvOffset = CORRECT_ENDIANNESS(offset); pkey = (char *) privKey->keyRecord; /* SAB first check that we don;t under flow the buffer */ if ( pSize < pbytes ) { IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT, IBMCA_R_UNDERFLOW_CONDITION); goto err; } /* pkey += pSize - BN_num_bytes(p); WROING this should be dmp1) */ pkey += pSize - BN_num_bytes(dmp1); BN_bn2bin(dmp1, pkey); pkey += BN_num_bytes(dmp1); /* move the pointer */ BN_bn2bin(dmq1, pkey); /* Copy over dmq1 */ pkey += qSize; /* move pointer */ pkey += pSize - BN_num_bytes(p); /* set up for zero padding of next field */ BN_bn2bin(p, pkey); pkey += BN_num_bytes(p); /* increment pointer by number of bytes moved */ BN_bn2bin(q, pkey); pkey += qSize ; /* move the pointer */ pkey += pSize - BN_num_bytes(iqmp); /* Adjust for padding */ BN_bn2bin(iqmp, pkey); /* Prepare the argument and response */ outLen = CORRECT_ENDIANNESS(privKey->qLength) * 2; /* Correct endianess is used because the fields were converted above */ if (outLen > 256) { IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_OUTLEN_TO_LARGE); goto err; } /* SAB check for underflow here on the argeument */ if ( outLen < BN_num_bytes(a)) { IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_UNDERFLOW_CONDITION); goto err; } BN_bn2bin(a, (unsigned char *)argument->d + outLen - BN_num_bytes(a)); inLen = outLen; memset(result->d, 0, outLen); /* Perform the operation */ if ( (rc = p_icaRsaCrt(handle, inLen, (unsigned char *)argument->d, privKey, &outLen, (unsigned char *)result->d)) != 0) { printf("rc = %d\n", rc); IBMCAerr(IBMCA_F_IBMCA_MOD_EXP_CRT,IBMCA_R_REQUEST_FAILED); goto err; } /* Convert the response */ BN_bin2bn((unsigned char *)result->d, outLen, r); to_return = 1; err: BN_CTX_end(ctx); return to_return; }
/*- * BN_div computes dv := num / divisor, rounding towards * zero, and sets up rm such that dv*divisor + rm = num holds. * Thus: * dv->neg == num->neg ^ divisor->neg (unless the result is zero) * rm->neg == num->neg (unless the remainder is zero) * If 'dv' or 'rm' is NULL, the respective value is not returned. */ int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, BN_CTX *ctx) { int norm_shift, i, loop; BIGNUM *tmp, wnum, *snum, *sdiv, *res; BN_ULONG *resp, *wnump; BN_ULONG d0, d1; int num_n, div_n; int no_branch = 0; /* * Invalid zero-padding would have particularly bad consequences so don't * just rely on bn_check_top() here (bn_check_top() works only for * BN_DEBUG builds) */ if ((num->top > 0 && num->d[num->top - 1] == 0) || (divisor->top > 0 && divisor->d[divisor->top - 1] == 0)) { BNerr(BN_F_BN_DIV, BN_R_NOT_INITIALIZED); return 0; } bn_check_top(num); bn_check_top(divisor); if ((BN_get_flags(num, BN_FLG_CONSTTIME) != 0) || (BN_get_flags(divisor, BN_FLG_CONSTTIME) != 0)) { no_branch = 1; } bn_check_top(dv); bn_check_top(rm); /*- bn_check_top(num); *//* * 'num' has been checked already */ /*- bn_check_top(divisor); *//* * 'divisor' has been checked already */ if (BN_is_zero(divisor)) { BNerr(BN_F_BN_DIV, BN_R_DIV_BY_ZERO); return (0); } if (!no_branch && BN_ucmp(num, divisor) < 0) { if (rm != NULL) { if (BN_copy(rm, num) == NULL) return (0); } if (dv != NULL) BN_zero(dv); return (1); } BN_CTX_start(ctx); tmp = BN_CTX_get(ctx); snum = BN_CTX_get(ctx); sdiv = BN_CTX_get(ctx); if (dv == NULL) res = BN_CTX_get(ctx); else res = dv; if (sdiv == NULL || res == NULL || tmp == NULL || snum == NULL) goto err; /* First we normalise the numbers */ norm_shift = BN_BITS2 - ((BN_num_bits(divisor)) % BN_BITS2); if (!(BN_lshift(sdiv, divisor, norm_shift))) goto err; sdiv->neg = 0; norm_shift += BN_BITS2; if (!(BN_lshift(snum, num, norm_shift))) goto err; snum->neg = 0; if (no_branch) { /* * Since we don't know whether snum is larger than sdiv, we pad snum * with enough zeroes without changing its value. */ if (snum->top <= sdiv->top + 1) { if (bn_wexpand(snum, sdiv->top + 2) == NULL) goto err; for (i = snum->top; i < sdiv->top + 2; i++) snum->d[i] = 0; snum->top = sdiv->top + 2; } else { if (bn_wexpand(snum, snum->top + 1) == NULL) goto err; snum->d[snum->top] = 0; snum->top++; } } div_n = sdiv->top; num_n = snum->top; loop = num_n - div_n; /* * Lets setup a 'window' into snum This is the part that corresponds to * the current 'area' being divided */ wnum.neg = 0; wnum.d = &(snum->d[loop]); wnum.top = div_n; /* * only needed when BN_ucmp messes up the values between top and max */ wnum.dmax = snum->dmax - loop; /* so we don't step out of bounds */ /* Get the top 2 words of sdiv */ /* div_n=sdiv->top; */ d0 = sdiv->d[div_n - 1]; d1 = (div_n == 1) ? 0 : sdiv->d[div_n - 2]; /* pointer to the 'top' of snum */ wnump = &(snum->d[num_n - 1]); /* Setup to 'res' */ res->neg = (num->neg ^ divisor->neg); if (!bn_wexpand(res, (loop + 1))) goto err; res->top = loop - no_branch; resp = &(res->d[loop - 1]); /* space for temp */ if (!bn_wexpand(tmp, (div_n + 1))) goto err; if (!no_branch) { if (BN_ucmp(&wnum, sdiv) >= 0) { /* * If BN_DEBUG_RAND is defined BN_ucmp changes (via bn_pollute) * the const bignum arguments => clean the values between top and * max again */ bn_clear_top2max(&wnum); bn_sub_words(wnum.d, wnum.d, sdiv->d, div_n); *resp = 1; } else res->top--; } /* * if res->top == 0 then clear the neg value otherwise decrease the resp * pointer */ if (res->top == 0) res->neg = 0; else resp--; for (i = 0; i < loop - 1; i++, wnump--, resp--) { BN_ULONG q, l0; /* * the first part of the loop uses the top two words of snum and sdiv * to calculate a BN_ULONG q such that | wnum - sdiv * q | < sdiv */ # if defined(BN_DIV3W) && !defined(OPENSSL_NO_ASM) BN_ULONG bn_div_3_words(BN_ULONG *, BN_ULONG, BN_ULONG); q = bn_div_3_words(wnump, d1, d0); # else BN_ULONG n0, n1, rem = 0; n0 = wnump[0]; n1 = wnump[-1]; if (n0 == d0) q = BN_MASK2; else { /* n0 < d0 */ # ifdef BN_LLONG BN_ULLONG t2; # if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(bn_div_words) q = (BN_ULONG)(((((BN_ULLONG) n0) << BN_BITS2) | n1) / d0); # else q = bn_div_words(n0, n1, d0); # endif # ifndef REMAINDER_IS_ALREADY_CALCULATED /* * rem doesn't have to be BN_ULLONG. The least we * know it's less that d0, isn't it? */ rem = (n1 - q * d0) & BN_MASK2; # endif t2 = (BN_ULLONG) d1 *q; for (;;) { if (t2 <= ((((BN_ULLONG) rem) << BN_BITS2) | wnump[-2])) break; q--; rem += d0; if (rem < d0) break; /* don't let rem overflow */ t2 -= d1; } # else /* !BN_LLONG */ BN_ULONG t2l, t2h; q = bn_div_words(n0, n1, d0); # ifndef REMAINDER_IS_ALREADY_CALCULATED rem = (n1 - q * d0) & BN_MASK2; # endif # if defined(BN_UMULT_LOHI) BN_UMULT_LOHI(t2l, t2h, d1, q); # elif defined(BN_UMULT_HIGH) t2l = d1 * q; t2h = BN_UMULT_HIGH(d1, q); # else { BN_ULONG ql, qh; t2l = LBITS(d1); t2h = HBITS(d1); ql = LBITS(q); qh = HBITS(q); mul64(t2l, t2h, ql, qh); /* t2=(BN_ULLONG)d1*q; */ } # endif for (;;) { if ((t2h < rem) || ((t2h == rem) && (t2l <= wnump[-2]))) break; q--; rem += d0; if (rem < d0) break; /* don't let rem overflow */ if (t2l < d1) t2h--; t2l -= d1; } # endif /* !BN_LLONG */ } # endif /* !BN_DIV3W */ l0 = bn_mul_words(tmp->d, sdiv->d, div_n, q); tmp->d[div_n] = l0; wnum.d--; /* * ingore top values of the bignums just sub the two BN_ULONG arrays * with bn_sub_words */ if (bn_sub_words(wnum.d, wnum.d, tmp->d, div_n + 1)) { /* * Note: As we have considered only the leading two BN_ULONGs in * the calculation of q, sdiv * q might be greater than wnum (but * then (q-1) * sdiv is less or equal than wnum) */ q--; if (bn_add_words(wnum.d, wnum.d, sdiv->d, div_n)) /* * we can't have an overflow here (assuming that q != 0, but * if q == 0 then tmp is zero anyway) */ (*wnump)++; } /* store part of the result */ *resp = q; } bn_correct_top(snum); if (rm != NULL) { /* * Keep a copy of the neg flag in num because if rm==num BN_rshift() * will overwrite it. */ int neg = num->neg; BN_rshift(rm, snum, norm_shift); if (!BN_is_zero(rm)) rm->neg = neg; bn_check_top(rm); } if (no_branch) bn_correct_top(res); BN_CTX_end(ctx); return (1); err: bn_check_top(rm); BN_CTX_end(ctx); return (0); }
static int ibmca_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx) { /* I need somewhere to store temporary serialised values for * use with the Ibmca API calls. A neat cheat - I'll use * BIGNUMs from the BN_CTX but access their arrays directly as * byte arrays <grin>. This way I don't have to clean anything * up. */ BIGNUM *argument=NULL; BIGNUM *result=NULL; BIGNUM *key=NULL; int to_return; int inLen, outLen, tmpLen; ICA_KEY_RSA_MODEXPO *publKey=NULL; unsigned int rc; to_return = 0; /* expect failure */ if(!ibmca_dso) { IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_NOT_LOADED); goto err; } /* Prepare the params */ BN_CTX_start(ctx); argument = BN_CTX_get(ctx); result = BN_CTX_get(ctx); key = BN_CTX_get(ctx); if( !argument || !result || !key) { IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_BN_CTX_FULL); goto err; } if(!bn_wexpand(argument, m->top) || !bn_wexpand(result, m->top) || !bn_wexpand(key, sizeof(*publKey)/BN_BYTES)) { IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_BN_EXPAND_FAIL); goto err; } publKey = (ICA_KEY_RSA_MODEXPO *)key->d; if (publKey == NULL) { goto err; } memset(publKey, 0, sizeof(ICA_KEY_RSA_MODEXPO)); publKey->keyType = CORRECT_ENDIANNESS(ME_KEY_TYPE); publKey->keyLength = CORRECT_ENDIANNESS(sizeof(ICA_KEY_RSA_MODEXPO)); publKey->expOffset = (char *) publKey->keyRecord - (char *) publKey; /* A quirk of the card: the exponent length has to be the same as the modulus (key) length */ outLen = BN_num_bytes(m); /* check for modulus length SAB*/ if (outLen > 256 ) { IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_MEXP_LENGTH_TO_LARGE); goto err; } /* check for modulus length SAB*/ publKey->expLength = publKey->nLength = outLen; /* SAB Check for underflow condition the size of the exponent is less than the size of the parameter then we have a big problem and will underflow the keyRecord buffer. Bad stuff could happen then */ if (outLen < BN_num_bytes(p)){ IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_UNDERFLOW_KEYRECORD); goto err; } /* SAB End check for underflow */ BN_bn2bin(p, &publKey->keyRecord[publKey->expLength - BN_num_bytes(p)]); BN_bn2bin(m, &publKey->keyRecord[publKey->expLength]); publKey->modulusBitLength = CORRECT_ENDIANNESS(publKey->nLength * 8); publKey->nOffset = CORRECT_ENDIANNESS(publKey->expOffset + publKey->expLength); publKey->expOffset = CORRECT_ENDIANNESS((char *) publKey->keyRecord - (char *) publKey); tmpLen = outLen; publKey->expLength = publKey->nLength = CORRECT_ENDIANNESS(tmpLen); /* Prepare the argument */ memset(argument->d, 0, outLen); BN_bn2bin(a, (unsigned char *)argument->d + outLen - BN_num_bytes(a)); inLen = outLen; /* Perform the operation */ if( (rc = p_icaRsaModExpo(handle, inLen,(unsigned char *)argument->d, publKey, &outLen, (unsigned char *)result->d)) !=0 ) { printf("rc = %d\n", rc); IBMCAerr(IBMCA_F_IBMCA_MOD_EXP,IBMCA_R_REQUEST_FAILED); goto err; } /* Convert the response */ BN_bin2bn((unsigned char *)result->d, outLen, r); to_return = 1; err: BN_CTX_end(ctx); return to_return; }
int BN_from_montgomery(BIGNUM *ret, const BIGNUM *a, BN_MONT_CTX *mont, BN_CTX *ctx) { int retn=0; #ifdef MONT_WORD BIGNUM *n,*r; BN_ULONG *ap,*np,*rp,n0,v,*nrp; int al,nl,max,i,x,ri; BN_CTX_start(ctx); if ((r = BN_CTX_get(ctx)) == NULL) goto err; if (!BN_copy(r,a)) goto err; n= &(mont->N); ap=a->d; /* mont->ri is the size of mont->N in bits (rounded up to the word size) */ al=ri=mont->ri/BN_BITS2; nl=n->top; if ((al == 0) || (nl == 0)) { r->top=0; return(1); } max=(nl+al+1); /* allow for overflow (no?) XXX */ if (bn_wexpand(r,max) == NULL) goto err; if (bn_wexpand(ret,max) == NULL) goto err; r->neg=a->neg^n->neg; np=n->d; rp=r->d; nrp= &(r->d[nl]); /* clear the top words of T */ #if 1 for (i=r->top; i<max; i++) /* memset? XXX */ r->d[i]=0; #else memset(&(r->d[r->top]),0,(max-r->top)*sizeof(BN_ULONG)); #endif r->top=max; n0=mont->n0; #ifdef BN_COUNT fprintf(stderr,"word BN_from_montgomery %d * %d\n",nl,nl); #endif for (i=0; i<nl; i++) { #ifdef __TANDEM { long long t1; long long t2; long long t3; t1 = rp[0] * (n0 & 0177777); t2 = 037777600000l; t2 = n0 & t2; t3 = rp[0] & 0177777; t2 = (t3 * t2) & BN_MASK2; t1 = t1 + t2; v=bn_mul_add_words(rp,np,nl,(BN_ULONG) t1); } #else v=bn_mul_add_words(rp,np,nl,(rp[0]*n0)&BN_MASK2); #endif nrp++; rp++; if (((nrp[-1]+=v)&BN_MASK2) >= v) continue; else { if (((++nrp[0])&BN_MASK2) != 0) continue; if (((++nrp[1])&BN_MASK2) != 0) continue; for (x=2; (((++nrp[x])&BN_MASK2) == 0); x++) ; } } bn_correct_top(r); /* mont->ri will be a multiple of the word size */ #if 0 BN_rshift(ret,r,mont->ri); #else ret->neg = r->neg; x=ri; rp=ret->d; ap= &(r->d[x]); if (r->top < x) al=0; else al=r->top-x; ret->top=al; al-=4; for (i=0; i<al; i+=4) { BN_ULONG t1,t2,t3,t4; t1=ap[i+0]; t2=ap[i+1]; t3=ap[i+2]; t4=ap[i+3]; rp[i+0]=t1; rp[i+1]=t2; rp[i+2]=t3; rp[i+3]=t4; } al+=4; for (; i<al; i++) rp[i]=ap[i]; #endif #else /* !MONT_WORD */ BIGNUM *t1,*t2; BN_CTX_start(ctx); t1 = BN_CTX_get(ctx); t2 = BN_CTX_get(ctx); if (t1 == NULL || t2 == NULL) goto err; if (!BN_copy(t1,a)) goto err; BN_mask_bits(t1,mont->ri); if (!BN_mul(t2,t1,&mont->Ni,ctx)) goto err; BN_mask_bits(t2,mont->ri); if (!BN_mul(t1,t2,&mont->N,ctx)) goto err; if (!BN_add(t2,a,t1)) goto err; if (!BN_rshift(ret,t2,mont->ri)) goto err; #endif /* MONT_WORD */ if (BN_ucmp(ret, &(mont->N)) >= 0) { if (!BN_usub(ret,ret,&(mont->N))) goto err; } retn=1; bn_check_top(ret); err: BN_CTX_end(ctx); return(retn); }
static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont) { BIGNUM *n; BN_ULONG *ap,*np,*rp,n0,v,*nrp; int al,nl,max,i,x,ri; n= &(mont->N); /* mont->ri is the size of mont->N in bits (rounded up to the word size) */ al=ri=mont->ri/BN_BITS2; nl=n->top; if ((al == 0) || (nl == 0)) { ret->top=0; return(1); } max=(nl+al+1); /* allow for overflow (no?) XXX */ if (bn_wexpand(r,max) == NULL) return(0); r->neg^=n->neg; np=n->d; rp=r->d; nrp= &(r->d[nl]); /* clear the top words of T */ #if 1 for (i=r->top; i<max; i++) /* memset? XXX */ r->d[i]=0; #else TINYCLR_SSL_MEMSET(&(r->d[r->top]),0,(max-r->top)*sizeof(BN_ULONG)); #endif r->top=max; n0=mont->n0[0]; #ifdef BN_COUNT TINYCLR_SSL_FPRINTF(OPENSSL_TYPE__FILE_STDERR,"word BN_from_montgomery_word %d * %d\n",nl,nl); #endif for (i=0; i<nl; i++) { #ifdef __TANDEM { long long t1; long long t2; long long t3; t1 = rp[0] * (n0 & 0177777); t2 = 037777600000l; t2 = n0 & t2; t3 = rp[0] & 0177777; t2 = (t3 * t2) & BN_MASK2; t1 = t1 + t2; v=bn_mul_add_words(rp,np,nl,(BN_ULONG) t1); } #else v=bn_mul_add_words(rp,np,nl,(rp[0]*n0)&BN_MASK2); #endif nrp++; rp++; if (((nrp[-1]+=v)&BN_MASK2) >= v) continue; else { if (((++nrp[0])&BN_MASK2) != 0) continue; if (((++nrp[1])&BN_MASK2) != 0) continue; for (x=2; (((++nrp[x])&BN_MASK2) == 0); x++) ; } } bn_correct_top(r); /* mont->ri will be a multiple of the word size and below code * is kind of BN_rshift(ret,r,mont->ri) equivalent */ if (r->top <= ri) { ret->top=0; return(1); } al=r->top-ri; #define BRANCH_FREE 1 #if BRANCH_FREE if (bn_wexpand(ret,ri) == NULL) return(0); x=0-(((al-ri)>>(sizeof(al)*8-1))&1); ret->top=x=(ri&~x)|(al&x); /* min(ri,al) */ ret->neg=r->neg; rp=ret->d; ap=&(r->d[ri]); { size_t m1,m2; v=bn_sub_words(rp,ap,np,ri); /* this ----------------^^ works even in al<ri case * thanks to zealous zeroing of top of the vector in the * beginning. */ /* if (al==ri && !v) || al>ri) nrp=rp; else nrp=ap; */ /* in other words if subtraction result is real, then * trick unconditional TINYCLR_SSL_MEMCPY below to perform in-place * "refresh" instead of actual copy. */ m1=0-(size_t)(((al-ri)>>(sizeof(al)*8-1))&1); /* al<ri */ m2=0-(size_t)(((ri-al)>>(sizeof(al)*8-1))&1); /* al>ri */ m1|=m2; /* (al!=ri) */ m1|=(0-(size_t)v); /* (al!=ri || v) */ m1&=~m2; /* (al!=ri || v) && !al>ri */ nrp=(BN_ULONG *)(((size_t)rp&~m1)|((size_t)ap&m1)); } /* 'i<ri' is chosen to eliminate dependency on input data, even * though it results in redundant copy in al<ri case. */ for (i=0,ri-=4; i<ri; i+=4) { BN_ULONG t1,t2,t3,t4; t1=nrp[i+0]; t2=nrp[i+1]; t3=nrp[i+2]; ap[i+0]=0; t4=nrp[i+3]; ap[i+1]=0; rp[i+0]=t1; ap[i+2]=0; rp[i+1]=t2; ap[i+3]=0; rp[i+2]=t3; rp[i+3]=t4; } for (ri+=4; i<ri; i++) rp[i]=nrp[i], ap[i]=0; bn_correct_top(r); bn_correct_top(ret); #else if (bn_wexpand(ret,al) == NULL) return(0); ret->top=al; ret->neg=r->neg; rp=ret->d; ap=&(r->d[ri]); al-=4; for (i=0; i<al; i+=4) { BN_ULONG t1,t2,t3,t4; t1=ap[i+0]; t2=ap[i+1]; t3=ap[i+2]; t4=ap[i+3]; rp[i+0]=t1; rp[i+1]=t2; rp[i+2]=t3; rp[i+3]=t4; } al+=4; for (; i<al; i++) rp[i]=ap[i]; if (BN_ucmp(ret, &(mont->N)) >= 0) { if (!BN_usub(ret,ret,&(mont->N))) return(0); } #endif bn_check_top(ret); return(1); }
/** * public static native int BN_lshift(int, int, int) */ static jboolean NativeBN_BN_lshift(JNIEnv* env, jclass cls, BIGNUM* r, BIGNUM* a, int n) { // LOGD("NativeBN_BN_lshift %p %p %d", r, a, n); if (!twoValidHandles(env, r, a)) return FALSE; if (n >= 0) return BN_lshift(r, a, n); n = -n; // return BN_rshift(r, a, n); // Following code insourced from bn_shift.c in order to have bug fixed: // FIXME: Should report to openssl team!!! int i,j,nw,lb,rb; BN_ULONG *t,*f; BN_ULONG l,tmp; bn_check_top(r); bn_check_top(a); nw=n/BN_BITS2; rb=n%BN_BITS2; lb=BN_BITS2-rb; // Changed "nw > a->top || a->top == 0" to nw >= a->top" as considering this a bug: if (nw >= a->top) { BN_zero(r); return(1); } if (r != a) { r->neg=a->neg; if (bn_wexpand(r,a->top-nw+1) == NULL) return(0); } else { if (n == 0) return 1; /* or the copying loop will go berserk */ } f= &(a->d[nw]); t=r->d; j=a->top-nw; r->top=j; if (rb == 0) { for (i=j; i != 0; i--) *(t++)= *(f++); } else { l= *(f++); for (i=j-1; i != 0; i--) { tmp =(l>>rb)&BN_MASK2; l= *(f++); *(t++) =(tmp|(l<<lb))&BN_MASK2; } *(t++) =(l>>rb)&BN_MASK2; } bn_correct_top(r); bn_check_top(r); return(1); }
/* Un petit mod_exp */ static int cswift_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx) { /* I need somewhere to store temporary serialised values for * use with the CryptoSwift API calls. A neat cheat - I'll use * BIGNUMs from the BN_CTX but access their arrays directly as * byte arrays <grin>. This way I don't have to clean anything * up. */ BIGNUM *modulus; BIGNUM *exponent; BIGNUM *argument; BIGNUM *result; SW_STATUS sw_status; SW_LARGENUMBER arg, res; SW_PARAM sw_param; SW_CONTEXT_HANDLE hac; int to_return, acquired; modulus = exponent = argument = result = NULL; to_return = 0; /* expect failure */ acquired = 0; if(!get_context(&hac)) { CSWIFTerr(CSWIFT_F_CSWIFT_MOD_EXP,CSWIFT_R_UNIT_FAILURE); goto err; } acquired = 1; /* Prepare the params */ BN_CTX_start(ctx); modulus = BN_CTX_get(ctx); exponent = BN_CTX_get(ctx); argument = BN_CTX_get(ctx); result = BN_CTX_get(ctx); if(!result) { CSWIFTerr(CSWIFT_F_CSWIFT_MOD_EXP,CSWIFT_R_BN_CTX_FULL); goto err; } if(!bn_wexpand(modulus, m->top) || !bn_wexpand(exponent, p->top) || !bn_wexpand(argument, a->top) || !bn_wexpand(result, m->top)) { CSWIFTerr(CSWIFT_F_CSWIFT_MOD_EXP,CSWIFT_R_BN_EXPAND_FAIL); goto err; } sw_param.type = SW_ALG_EXP; sw_param.up.exp.modulus.nbytes = BN_bn2bin(m, (unsigned char *)modulus->d); sw_param.up.exp.modulus.value = (unsigned char *)modulus->d; sw_param.up.exp.exponent.nbytes = BN_bn2bin(p, (unsigned char *)exponent->d); sw_param.up.exp.exponent.value = (unsigned char *)exponent->d; /* Attach the key params */ sw_status = p_CSwift_AttachKeyParam(hac, &sw_param); switch(sw_status) { case SW_OK: break; case SW_ERR_INPUT_SIZE: CSWIFTerr(CSWIFT_F_CSWIFT_MOD_EXP,CSWIFT_R_BAD_KEY_SIZE); goto err; default: { char tmpbuf[DECIMAL_SIZE(sw_status)+1]; CSWIFTerr(CSWIFT_F_CSWIFT_MOD_EXP,CSWIFT_R_REQUEST_FAILED); sprintf(tmpbuf, "%ld", sw_status); ERR_add_error_data(2, "CryptoSwift error number is ",tmpbuf); } goto err; } /* Prepare the argument and response */ arg.nbytes = BN_bn2bin(a, (unsigned char *)argument->d); arg.value = (unsigned char *)argument->d; res.nbytes = BN_num_bytes(m); memset(result->d, 0, res.nbytes); res.value = (unsigned char *)result->d; /* Perform the operation */ if((sw_status = p_CSwift_SimpleRequest(hac, SW_CMD_MODEXP, &arg, 1, &res, 1)) != SW_OK) { char tmpbuf[DECIMAL_SIZE(sw_status)+1]; CSWIFTerr(CSWIFT_F_CSWIFT_MOD_EXP,CSWIFT_R_REQUEST_FAILED); sprintf(tmpbuf, "%ld", sw_status); ERR_add_error_data(2, "CryptoSwift error number is ",tmpbuf); goto err; } /* Convert the response */ BN_bin2bn((unsigned char *)result->d, res.nbytes, r); to_return = 1; err: if(acquired) release_context(hac); BN_CTX_end(ctx); return to_return; }
static DSA_SIG *ubsec_dsa_do_sign(const unsigned char *dgst, int dlen, DSA *dsa) { DSA_SIG *to_return = NULL; int s_len = 160, r_len = 160, d_len, fd; BIGNUM m, *r = NULL, *s = NULL; BN_init(&m); s = BN_new(); r = BN_new(); if ((s == NULL) || (r == NULL)) goto err; d_len = p_UBSEC_ubsec_bytes_to_bits((unsigned char *)dgst, dlen); if (!bn_wexpand(r, (160 + BN_BITS2 - 1) / BN_BITS2) || (!bn_wexpand(s, (160 + BN_BITS2 - 1) / BN_BITS2))) { UBSECerr(UBSEC_F_UBSEC_DSA_DO_SIGN, UBSEC_R_BN_EXPAND_FAIL); goto err; } if (BN_bin2bn(dgst, dlen, &m) == NULL) { UBSECerr(UBSEC_F_UBSEC_DSA_DO_SIGN, UBSEC_R_BN_EXPAND_FAIL); goto err; } if ((fd = p_UBSEC_ubsec_open(UBSEC_KEY_DEVICE_NAME)) <= 0) { const DSA_METHOD *meth; fd = 0; UBSECerr(UBSEC_F_UBSEC_DSA_DO_SIGN, UBSEC_R_UNIT_FAILURE); meth = DSA_OpenSSL(); to_return = meth->dsa_do_sign(dgst, dlen, dsa); goto err; } if (p_UBSEC_dsa_sign_ioctl(fd, /* compute hash before signing */ 0, (unsigned char *)dgst, d_len, NULL, /* compute random value */ 0, (unsigned char *)dsa->p->d, BN_num_bits(dsa->p), (unsigned char *)dsa->q->d, BN_num_bits(dsa->q), (unsigned char *)dsa->g->d, BN_num_bits(dsa->g), (unsigned char *)dsa->priv_key->d, BN_num_bits(dsa->priv_key), (unsigned char *)r->d, &r_len, (unsigned char *)s->d, &s_len) != 0) { const DSA_METHOD *meth; UBSECerr(UBSEC_F_UBSEC_DSA_DO_SIGN, UBSEC_R_REQUEST_FAILED); p_UBSEC_ubsec_close(fd); meth = DSA_OpenSSL(); to_return = meth->dsa_do_sign(dgst, dlen, dsa); goto err; } p_UBSEC_ubsec_close(fd); r->top = (160 + BN_BITS2 - 1) / BN_BITS2; s->top = (160 + BN_BITS2 - 1) / BN_BITS2; to_return = DSA_SIG_new(); if (to_return == NULL) { UBSECerr(UBSEC_F_UBSEC_DSA_DO_SIGN, UBSEC_R_BN_EXPAND_FAIL); goto err; } to_return->r = r; to_return->s = s; err: if (!to_return) { if (r) BN_free(r); if (s) BN_free(s); } BN_clear_free(&m); return to_return; }
/* Un petit mod_exp chinois */ static int cswift_mod_exp_crt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *q, const BIGNUM *dmp1, const BIGNUM *dmq1, const BIGNUM *iqmp, BN_CTX *ctx) { SW_STATUS sw_status; SW_LARGENUMBER arg, res; SW_PARAM sw_param; SW_CONTEXT_HANDLE hac; BIGNUM *result = NULL; BIGNUM *argument = NULL; int to_return = 0; /* expect failure */ int acquired = 0; sw_param.up.crt.p.value = NULL; sw_param.up.crt.q.value = NULL; sw_param.up.crt.dmp1.value = NULL; sw_param.up.crt.dmq1.value = NULL; sw_param.up.crt.iqmp.value = NULL; if(!get_context(&hac)) { CSWIFTerr(CSWIFT_F_CSWIFT_MOD_EXP_CRT,CSWIFT_R_UNIT_FAILURE); goto err; } acquired = 1; /* Prepare the params */ argument = BN_new(); result = BN_new(); if(!result || !argument) { CSWIFTerr(CSWIFT_F_CSWIFT_MOD_EXP_CRT,CSWIFT_R_BN_CTX_FULL); goto err; } sw_param.type = SW_ALG_CRT; /************************************************************************/ /* 04/02/2003 */ /* Modified by Frederic Giudicelli (deny-all.com) to overcome the */ /* limitation of cswift with values not a multiple of 32 */ /************************************************************************/ if(!cswift_bn_32copy(&sw_param.up.crt.p, p)) { CSWIFTerr(CSWIFT_F_CSWIFT_MOD_EXP_CRT,CSWIFT_R_BN_EXPAND_FAIL); goto err; } if(!cswift_bn_32copy(&sw_param.up.crt.q, q)) { CSWIFTerr(CSWIFT_F_CSWIFT_MOD_EXP_CRT,CSWIFT_R_BN_EXPAND_FAIL); goto err; } if(!cswift_bn_32copy(&sw_param.up.crt.dmp1, dmp1)) { CSWIFTerr(CSWIFT_F_CSWIFT_MOD_EXP_CRT,CSWIFT_R_BN_EXPAND_FAIL); goto err; } if(!cswift_bn_32copy(&sw_param.up.crt.dmq1, dmq1)) { CSWIFTerr(CSWIFT_F_CSWIFT_MOD_EXP_CRT,CSWIFT_R_BN_EXPAND_FAIL); goto err; } if(!cswift_bn_32copy(&sw_param.up.crt.iqmp, iqmp)) { CSWIFTerr(CSWIFT_F_CSWIFT_MOD_EXP_CRT,CSWIFT_R_BN_EXPAND_FAIL); goto err; } if( !bn_wexpand(argument, a->top) || !bn_wexpand(result, p->top + q->top)) { CSWIFTerr(CSWIFT_F_CSWIFT_MOD_EXP_CRT,CSWIFT_R_BN_EXPAND_FAIL); goto err; } /* Attach the key params */ sw_status = p_CSwift_AttachKeyParam(hac, &sw_param); switch(sw_status) { case SW_OK: break; case SW_ERR_INPUT_SIZE: CSWIFTerr(CSWIFT_F_CSWIFT_MOD_EXP_CRT,CSWIFT_R_BAD_KEY_SIZE); goto err; default: { char tmpbuf[DECIMAL_SIZE(sw_status)+1]; CSWIFTerr(CSWIFT_F_CSWIFT_MOD_EXP_CRT,CSWIFT_R_REQUEST_FAILED); sprintf(tmpbuf, "%ld", sw_status); ERR_add_error_data(2, "CryptoSwift error number is ",tmpbuf); } goto err; } /* Prepare the argument and response */ arg.nbytes = BN_bn2bin(a, (unsigned char *)argument->d); arg.value = (unsigned char *)argument->d; res.nbytes = 2 * BN_num_bytes(p); memset(result->d, 0, res.nbytes); res.value = (unsigned char *)result->d; /* Perform the operation */ if((sw_status = p_CSwift_SimpleRequest(hac, SW_CMD_MODEXP_CRT, &arg, 1, &res, 1)) != SW_OK) { char tmpbuf[DECIMAL_SIZE(sw_status)+1]; CSWIFTerr(CSWIFT_F_CSWIFT_MOD_EXP_CRT,CSWIFT_R_REQUEST_FAILED); sprintf(tmpbuf, "%ld", sw_status); ERR_add_error_data(2, "CryptoSwift error number is ",tmpbuf); goto err; } /* Convert the response */ BN_bin2bn((unsigned char *)result->d, res.nbytes, r); to_return = 1; err: if(sw_param.up.crt.p.value) OPENSSL_free(sw_param.up.crt.p.value); if(sw_param.up.crt.q.value) OPENSSL_free(sw_param.up.crt.q.value); if(sw_param.up.crt.dmp1.value) OPENSSL_free(sw_param.up.crt.dmp1.value); if(sw_param.up.crt.dmq1.value) OPENSSL_free(sw_param.up.crt.dmq1.value); if(sw_param.up.crt.iqmp.value) OPENSSL_free(sw_param.up.crt.iqmp.value); if(result) BN_free(result); if(argument) BN_free(argument); if(acquired) release_context(hac); return to_return; }
/* unsigned subtraction of b from a, a must be larger than b. */ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { int max, min, dif; register BN_ULONG t1, t2, *ap, *bp, *rp; int i, carry; #if defined(IRIX_CC_BUG) && !defined(LINT) int dummy; #endif bn_check_top(a); bn_check_top(b); max = a->top; min = b->top; dif = max - min; if (dif < 0) { /* hmm... should not be happening */ BNerr(BN_F_BN_USUB, BN_R_ARG2_LT_ARG3); return (0); } if (bn_wexpand(r, max) == NULL) return (0); ap = a->d; bp = b->d; rp = r->d; #if 1 carry = 0; for (i = min; i != 0; i--) { t1 = *(ap++); t2 = *(bp++); if (carry) { carry = (t1 <= t2); t1 = (t1 - t2 - 1) & BN_MASK2; } else { carry = (t1 < t2); t1 = (t1 - t2) & BN_MASK2; } # if defined(IRIX_CC_BUG) && !defined(LINT) dummy = t1; # endif *(rp++) = t1 & BN_MASK2; } #else carry = bn_sub_words(rp, ap, bp, min); ap += min; bp += min; rp += min; #endif if (carry) { /* subtracted */ if (!dif) /* error: a < b */ return 0; while (dif) { dif--; t1 = *(ap++); t2 = (t1 - 1) & BN_MASK2; *(rp++) = t2; if (t1) break; } } #if 0 memcpy(rp, ap, sizeof(*rp) * (max - i)); #else if (rp != ap) { for (;;) { if (!dif--) break; rp[0] = ap[0]; if (!dif--) break; rp[1] = ap[1]; if (!dif--) break; rp[2] = ap[2]; if (!dif--) break; rp[3] = ap[3]; rp += 4; ap += 4; } } #endif r->top = max; r->neg = 0; bn_correct_top(r); return (1); }
static DSA_SIG *cswift_dsa_sign(const unsigned char *dgst, int dlen, DSA *dsa) { SW_CONTEXT_HANDLE hac; SW_PARAM sw_param; SW_STATUS sw_status; SW_LARGENUMBER arg, res; unsigned char *ptr; BN_CTX *ctx; BIGNUM *dsa_p = NULL; BIGNUM *dsa_q = NULL; BIGNUM *dsa_g = NULL; BIGNUM *dsa_key = NULL; BIGNUM *result = NULL; DSA_SIG *to_return = NULL; int acquired = 0; if((ctx = BN_CTX_new()) == NULL) goto err; if(!get_context(&hac)) { CSWIFTerr(CSWIFT_F_CSWIFT_DSA_SIGN,CSWIFT_R_UNIT_FAILURE); goto err; } acquired = 1; /* Prepare the params */ BN_CTX_start(ctx); dsa_p = BN_CTX_get(ctx); dsa_q = BN_CTX_get(ctx); dsa_g = BN_CTX_get(ctx); dsa_key = BN_CTX_get(ctx); result = BN_CTX_get(ctx); if(!result) { CSWIFTerr(CSWIFT_F_CSWIFT_DSA_SIGN,CSWIFT_R_BN_CTX_FULL); goto err; } if(!bn_wexpand(dsa_p, dsa->p->top) || !bn_wexpand(dsa_q, dsa->q->top) || !bn_wexpand(dsa_g, dsa->g->top) || !bn_wexpand(dsa_key, dsa->priv_key->top) || !bn_wexpand(result, dsa->p->top)) { CSWIFTerr(CSWIFT_F_CSWIFT_DSA_SIGN,CSWIFT_R_BN_EXPAND_FAIL); goto err; } sw_param.type = SW_ALG_DSA; sw_param.up.dsa.p.nbytes = BN_bn2bin(dsa->p, (unsigned char *)dsa_p->d); sw_param.up.dsa.p.value = (unsigned char *)dsa_p->d; sw_param.up.dsa.q.nbytes = BN_bn2bin(dsa->q, (unsigned char *)dsa_q->d); sw_param.up.dsa.q.value = (unsigned char *)dsa_q->d; sw_param.up.dsa.g.nbytes = BN_bn2bin(dsa->g, (unsigned char *)dsa_g->d); sw_param.up.dsa.g.value = (unsigned char *)dsa_g->d; sw_param.up.dsa.key.nbytes = BN_bn2bin(dsa->priv_key, (unsigned char *)dsa_key->d); sw_param.up.dsa.key.value = (unsigned char *)dsa_key->d; /* Attach the key params */ sw_status = p_CSwift_AttachKeyParam(hac, &sw_param); switch(sw_status) { case SW_OK: break; case SW_ERR_INPUT_SIZE: CSWIFTerr(CSWIFT_F_CSWIFT_DSA_SIGN,CSWIFT_R_BAD_KEY_SIZE); goto err; default: { char tmpbuf[DECIMAL_SIZE(sw_status)+1]; CSWIFTerr(CSWIFT_F_CSWIFT_DSA_SIGN,CSWIFT_R_REQUEST_FAILED); sprintf(tmpbuf, "%ld", sw_status); ERR_add_error_data(2, "CryptoSwift error number is ",tmpbuf); } goto err; } /* Prepare the argument and response */ arg.nbytes = dlen; arg.value = (unsigned char *)dgst; res.nbytes = BN_num_bytes(dsa->p); memset(result->d, 0, res.nbytes); res.value = (unsigned char *)result->d; /* Perform the operation */ sw_status = p_CSwift_SimpleRequest(hac, SW_CMD_DSS_SIGN, &arg, 1, &res, 1); if(sw_status != SW_OK) { char tmpbuf[DECIMAL_SIZE(sw_status)+1]; CSWIFTerr(CSWIFT_F_CSWIFT_DSA_SIGN,CSWIFT_R_REQUEST_FAILED); sprintf(tmpbuf, "%ld", sw_status); ERR_add_error_data(2, "CryptoSwift error number is ",tmpbuf); goto err; } /* Convert the response */ ptr = (unsigned char *)result->d; if((to_return = DSA_SIG_new()) == NULL) goto err; to_return->r = BN_bin2bn((unsigned char *)result->d, 20, NULL); to_return->s = BN_bin2bn((unsigned char *)result->d + 20, 20, NULL); err: if(acquired) release_context(hac); if(ctx) { BN_CTX_end(ctx); BN_CTX_free(ctx); } return to_return; }
int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { int ret = 0; int top, al, bl; BIGNUM *rr; int i; BIGNUM *t = NULL; int j = 0, k; al = a->top; bl = b->top; if ((al == 0) || (bl == 0)) { BN_zero(r); return 1; } top = al + bl; BN_CTX_start(ctx); if ((r == a) || (r == b)) { if ((rr = BN_CTX_get(ctx)) == NULL) { goto err; } } else { rr = r; } rr->neg = a->neg ^ b->neg; i = al - bl; if (i == 0) { if (al == 8) { if (bn_wexpand(rr, 16) == NULL) { goto err; } rr->top = 16; bn_mul_comba8(rr->d, a->d, b->d); goto end; } } if ((al >= BN_MULL_SIZE_NORMAL) && (bl >= BN_MULL_SIZE_NORMAL)) { if (i >= -1 && i <= 1) { /* Find out the power of two lower or equal to the longest of the two numbers */ if (i >= 0) { j = BN_num_bits_word((BN_ULONG)al); } if (i == -1) { j = BN_num_bits_word((BN_ULONG)bl); } j = 1 << (j - 1); assert(j <= al || j <= bl); k = j + j; t = BN_CTX_get(ctx); if (t == NULL) { goto err; } if (al > j || bl > j) { if (bn_wexpand(t, k * 4) == NULL) { goto err; } if (bn_wexpand(rr, k * 4) == NULL) { goto err; } bn_mul_part_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d); } else { /* al <= j || bl <= j */ if (bn_wexpand(t, k * 2) == NULL) { goto err; } if (bn_wexpand(rr, k * 2) == NULL) { goto err; } bn_mul_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d); } rr->top = top; goto end; } } if (bn_wexpand(rr, top) == NULL) { goto err; } rr->top = top; bn_mul_normal(rr->d, a->d, al, b->d, bl); end: bn_correct_top(rr); if (r != rr && !BN_copy(r, rr)) { goto err; } ret = 1; err: BN_CTX_end(ctx); return ret; }
static int cswift_dsa_verify(const unsigned char *dgst, int dgst_len, DSA_SIG *sig, DSA *dsa) { SW_CONTEXT_HANDLE hac; SW_PARAM sw_param; SW_STATUS sw_status; SW_LARGENUMBER arg[2], res; unsigned long sig_result; BN_CTX *ctx; BIGNUM *dsa_p = NULL; BIGNUM *dsa_q = NULL; BIGNUM *dsa_g = NULL; BIGNUM *dsa_key = NULL; BIGNUM *argument = NULL; int to_return = -1; int acquired = 0; if((ctx = BN_CTX_new()) == NULL) goto err; if(!get_context(&hac)) { CSWIFTerr(CSWIFT_F_CSWIFT_DSA_VERIFY,CSWIFT_R_UNIT_FAILURE); goto err; } acquired = 1; /* Prepare the params */ BN_CTX_start(ctx); dsa_p = BN_CTX_get(ctx); dsa_q = BN_CTX_get(ctx); dsa_g = BN_CTX_get(ctx); dsa_key = BN_CTX_get(ctx); argument = BN_CTX_get(ctx); if(!argument) { CSWIFTerr(CSWIFT_F_CSWIFT_DSA_VERIFY,CSWIFT_R_BN_CTX_FULL); goto err; } if(!bn_wexpand(dsa_p, dsa->p->top) || !bn_wexpand(dsa_q, dsa->q->top) || !bn_wexpand(dsa_g, dsa->g->top) || !bn_wexpand(dsa_key, dsa->pub_key->top) || !bn_wexpand(argument, 40)) { CSWIFTerr(CSWIFT_F_CSWIFT_DSA_VERIFY,CSWIFT_R_BN_EXPAND_FAIL); goto err; } sw_param.type = SW_ALG_DSA; sw_param.up.dsa.p.nbytes = BN_bn2bin(dsa->p, (unsigned char *)dsa_p->d); sw_param.up.dsa.p.value = (unsigned char *)dsa_p->d; sw_param.up.dsa.q.nbytes = BN_bn2bin(dsa->q, (unsigned char *)dsa_q->d); sw_param.up.dsa.q.value = (unsigned char *)dsa_q->d; sw_param.up.dsa.g.nbytes = BN_bn2bin(dsa->g, (unsigned char *)dsa_g->d); sw_param.up.dsa.g.value = (unsigned char *)dsa_g->d; sw_param.up.dsa.key.nbytes = BN_bn2bin(dsa->pub_key, (unsigned char *)dsa_key->d); sw_param.up.dsa.key.value = (unsigned char *)dsa_key->d; /* Attach the key params */ sw_status = p_CSwift_AttachKeyParam(hac, &sw_param); switch(sw_status) { case SW_OK: break; case SW_ERR_INPUT_SIZE: CSWIFTerr(CSWIFT_F_CSWIFT_DSA_VERIFY,CSWIFT_R_BAD_KEY_SIZE); goto err; default: { char tmpbuf[DECIMAL_SIZE(sw_status)+1]; CSWIFTerr(CSWIFT_F_CSWIFT_DSA_VERIFY,CSWIFT_R_REQUEST_FAILED); sprintf(tmpbuf, "%ld", sw_status); ERR_add_error_data(2, "CryptoSwift error number is ",tmpbuf); } goto err; } /* Prepare the argument and response */ arg[0].nbytes = dgst_len; arg[0].value = (unsigned char *)dgst; arg[1].nbytes = 40; arg[1].value = (unsigned char *)argument->d; memset(arg[1].value, 0, 40); BN_bn2bin(sig->r, arg[1].value + 20 - BN_num_bytes(sig->r)); BN_bn2bin(sig->s, arg[1].value + 40 - BN_num_bytes(sig->s)); res.nbytes = 4; /* unsigned long */ res.value = (unsigned char *)(&sig_result); /* Perform the operation */ sw_status = p_CSwift_SimpleRequest(hac, SW_CMD_DSS_VERIFY, arg, 2, &res, 1); if(sw_status != SW_OK) { char tmpbuf[DECIMAL_SIZE(sw_status)+1]; CSWIFTerr(CSWIFT_F_CSWIFT_DSA_VERIFY,CSWIFT_R_REQUEST_FAILED); sprintf(tmpbuf, "%ld", sw_status); ERR_add_error_data(2, "CryptoSwift error number is ",tmpbuf); goto err; } /* Convert the response */ to_return = ((sig_result == 0) ? 0 : 1); err: if(acquired) release_context(hac); if(ctx) { BN_CTX_end(ctx); BN_CTX_free(ctx); } return to_return; }
/*- * Computes scalar*point and stores the result in r. * point can not equal r. * Uses a modified algorithm 2P of * Lopez, J. and Dahab, R. "Fast multiplication on elliptic curves over * GF(2^m) without precomputation" (CHES '99, LNCS 1717). * * To protect against side-channel attack the function uses constant time swap, * avoiding conditional branches. */ static int ec_GF2m_montgomery_point_multiply(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, const EC_POINT *point, BN_CTX *ctx) { BIGNUM *x1, *x2, *z1, *z2; int ret = 0, i; BN_ULONG mask, word; if (r == point) { ECerr(EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY, EC_R_INVALID_ARGUMENT); return 0; } /* if result should be point at infinity */ if ((scalar == NULL) || BN_is_zero(scalar) || (point == NULL) || EC_POINT_is_at_infinity(group, point)) { return EC_POINT_set_to_infinity(group, r); } /* only support affine coordinates */ if (!point->Z_is_one) return 0; /* * Since point_multiply is static we can guarantee that ctx != NULL. */ BN_CTX_start(ctx); x1 = BN_CTX_get(ctx); z1 = BN_CTX_get(ctx); if (z1 == NULL) goto err; x2 = &r->X; z2 = &r->Y; bn_wexpand(x1, group->field.top); bn_wexpand(z1, group->field.top); bn_wexpand(x2, group->field.top); bn_wexpand(z2, group->field.top); if (!BN_GF2m_mod_arr(x1, &point->X, group->poly)) goto err; /* x1 = x */ if (!BN_one(z1)) goto err; /* z1 = 1 */ if (!group->meth->field_sqr(group, z2, x1, ctx)) goto err; /* z2 = x1^2 = x^2 */ if (!group->meth->field_sqr(group, x2, z2, ctx)) goto err; if (!BN_GF2m_add(x2, x2, &group->b)) goto err; /* x2 = x^4 + b */ /* find top most bit and go one past it */ i = scalar->top - 1; mask = BN_TBIT; word = scalar->d[i]; while (!(word & mask)) mask >>= 1; mask >>= 1; /* if top most bit was at word break, go to next word */ if (!mask) { i--; mask = BN_TBIT; } for (; i >= 0; i--) { word = scalar->d[i]; while (mask) { BN_consttime_swap(word & mask, x1, x2, group->field.top); BN_consttime_swap(word & mask, z1, z2, group->field.top); if (!gf2m_Madd(group, &point->X, x2, z2, x1, z1, ctx)) goto err; if (!gf2m_Mdouble(group, x1, z1, ctx)) goto err; BN_consttime_swap(word & mask, x1, x2, group->field.top); BN_consttime_swap(word & mask, z1, z2, group->field.top); mask >>= 1; } mask = BN_TBIT; } /* convert out of "projective" coordinates */ i = gf2m_Mxy(group, &point->X, &point->Y, x1, z1, x2, z2, ctx); if (i == 0) goto err; else if (i == 1) { if (!EC_POINT_set_to_infinity(group, r)) goto err; } else { if (!BN_one(&r->Z)) goto err; r->Z_is_one = 1; } /* GF(2^m) field elements should always have BIGNUM::neg = 0 */ BN_set_negative(&r->X, 0); BN_set_negative(&r->Y, 0); ret = 1; err: BN_CTX_end(ctx); return ret; }
/* I've just gone over this and it is now %20 faster on x86 - eay - 27 Jun 96 */ int BN_sqr(BIGNUM *r, BIGNUM *a, BN_CTX *ctx) { int max,al; int ret = 0; BIGNUM *tmp,*rr; #ifdef BN_COUNT printf("BN_sqr %d * %d\n",a->top,a->top); #endif bn_check_top(a); al=a->top; if (al <= 0) { r->top=0; return(1); } BN_CTX_start(ctx); rr=(a != r) ? r : BN_CTX_get(ctx); tmp=BN_CTX_get(ctx); if (tmp == NULL) goto err; max=(al+al); if (bn_wexpand(rr,max+1) == NULL) goto err; r->neg=0; if (al == 4) { #ifndef BN_SQR_COMBA BN_ULONG t[8]; bn_sqr_normal(rr->d,a->d,4,t); #else bn_sqr_comba4(rr->d,a->d); #endif } else if (al == 8) { #ifndef BN_SQR_COMBA BN_ULONG t[16]; bn_sqr_normal(rr->d,a->d,8,t); #else bn_sqr_comba8(rr->d,a->d); #endif } else { #if defined(BN_RECURSION) if (al < BN_SQR_RECURSIVE_SIZE_NORMAL) { BN_ULONG t[BN_SQR_RECURSIVE_SIZE_NORMAL*2]; bn_sqr_normal(rr->d,a->d,al,t); } else { int j,k; j=BN_num_bits_word((BN_ULONG)al); j=1<<(j-1); k=j+j; if (al == j) { if (bn_wexpand(a,k*2) == NULL) goto err; if (bn_wexpand(tmp,k*2) == NULL) goto err; bn_sqr_recursive(rr->d,a->d,al,tmp->d); } else { if (bn_wexpand(tmp,max) == NULL) goto err; bn_sqr_normal(rr->d,a->d,al,tmp->d); } } #else if (bn_wexpand(tmp,max) == NULL) goto err; bn_sqr_normal(rr->d,a->d,al,tmp->d); #endif } rr->top=max; if ((max > 0) && (rr->d[max-1] == 0)) rr->top--; if (rr != r) BN_copy(r,rr); ret = 1; err: BN_CTX_end(ctx); return(ret); }
static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont) { BIGNUM *n; BN_ULONG *ap, *np, *rp, n0, v, carry; int nl, max, i; n = &(mont->N); nl = n->top; if (nl == 0) { ret->top = 0; return (1); } max = (2 * nl); /* carry is stored separately */ if (bn_wexpand(r, max) == NULL) return (0); r->neg ^= n->neg; np = n->d; rp = r->d; /* clear the top words of T */ #if 1 for (i=r->top; i<max; i++) /* memset? XXX */ rp[i] = 0; #else memset(&(rp[r->top]), 0, (max - r->top) * sizeof(BN_ULONG)); #endif r->top = max; n0 = mont->n0[0]; #ifdef BN_COUNT fprintf(stderr, "word BN_from_montgomery_word %d * %d\n", nl, nl); #endif for (carry = 0, i = 0; i < nl; i++, rp++) { v = bn_mul_add_words(rp, np, nl, (rp[0] * n0) & BN_MASK2); v = (v + carry + rp[nl]) & BN_MASK2; carry |= (v != rp[nl]); carry &= (v <= rp[nl]); rp[nl] = v; } if (bn_wexpand(ret, nl) == NULL) return (0); ret->top = nl; ret->neg = r->neg; rp = ret->d; ap = &(r->d[nl]); #define BRANCH_FREE 1 #if BRANCH_FREE { BN_ULONG *nrp; size_t m; v = bn_sub_words(rp, ap, np, nl) - carry; /* if subtraction result is real, then * trick unconditional memcpy below to perform in-place * "refresh" instead of actual copy. */ m = (0 - (size_t)v); nrp = (BN_ULONG *)(((uintptr_t)rp & ~m)|((uintptr_t)ap & m)); for (i = 0, nl -= 4; i < nl; i += 4) { BN_ULONG t1, t2, t3, t4; t1 = nrp[i + 0]; t2 = nrp[i + 1]; t3 = nrp[i + 2]; ap[i + 0] = 0; t4 = nrp[i + 3]; ap[i + 1] = 0; rp[i + 0] = t1; ap[i + 2] = 0; rp[i + 1] = t2; ap[i + 3] = 0; rp[i + 2] = t3; rp[i + 3] = t4; } for (nl += 4; i < nl; i++) rp[i] = nrp[i], ap[i] = 0; } #else if (bn_sub_words (rp, ap, np, nl) - carry) memcpy(rp, ap, nl*sizeof(BN_ULONG)); #endif bn_correct_top(r); bn_correct_top(ret); bn_check_top(ret); return (1); }
static int bn_from_montgomery_word(BIGNUM *ret, BIGNUM *r, BN_MONT_CTX *mont) { BIGNUM *n; BN_ULONG *ap, *np, *rp, n0, v, carry; int nl, max, i; n = &(mont->N); nl = n->top; if (nl == 0) { ret->top = 0; return (1); } max = (2 * nl); /* carry is stored separately */ if (bn_wexpand(r, max) == NULL) return (0); r->neg ^= n->neg; np = n->d; rp = r->d; /* clear the top words of T */ i = max - r->top; if (i) memset(&rp[r->top], 0, sizeof(*rp) * i); r->top = max; r->flags |= BN_FLG_FIXED_TOP; n0 = mont->n0[0]; /* * Add multiples of |n| to |r| until R = 2^(nl * BN_BITS2) divides it. On * input, we had |r| < |n| * R, so now |r| < 2 * |n| * R. Note that |r| * includes |carry| which is stored separately. */ for (carry = 0, i = 0; i < nl; i++, rp++) { v = bn_mul_add_words(rp, np, nl, (rp[0] * n0) & BN_MASK2); v = (v + carry + rp[nl]) & BN_MASK2; carry |= (v != rp[nl]); carry &= (v <= rp[nl]); rp[nl] = v; } if (bn_wexpand(ret, nl) == NULL) return (0); ret->top = nl; ret->flags |= BN_FLG_FIXED_TOP; ret->neg = r->neg; rp = ret->d; /* * Shift |nl| words to divide by R. We have |ap| < 2 * |n|. Note that |ap| * includes |carry| which is stored separately. */ ap = &(r->d[nl]); carry -= bn_sub_words(rp, ap, np, nl); /* * |carry| is -1 if |ap| - |np| underflowed or zero if it did not. Note * |carry| cannot be 1. That would imply the subtraction did not fit in * |nl| words, and we know at most one subtraction is needed. */ for (i = 0; i < nl; i++) { rp[i] = (carry & ap[i]) | (~carry & rp[i]); ap[i] = 0; } return (1); }
/* BN_div_no_branch is a special version of BN_div. It does not contain * branches that may leak sensitive information. */ static int BN_div_no_branch(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, BN_CTX *ctx) { int norm_shift,i,loop; BIGNUM *tmp,wnum,*snum,*sdiv,*res; BN_ULONG *resp,*wnump; BN_ULONG d0,d1; int num_n,div_n; bn_check_top(dv); bn_check_top(rm); /* bn_check_top(num); */ /* 'num' has been checked in BN_div() */ bn_check_top(divisor); if (BN_is_zero(divisor)) { BNerr(BN_F_BN_DIV_NO_BRANCH,BN_R_DIV_BY_ZERO); return(0); } BN_CTX_start(ctx); tmp=BN_CTX_get(ctx); snum=BN_CTX_get(ctx); sdiv=BN_CTX_get(ctx); if (dv == NULL) res=BN_CTX_get(ctx); else res=dv; if (sdiv == NULL || res == NULL) goto err; /* First we normalise the numbers */ norm_shift=BN_BITS2-((BN_num_bits(divisor))%BN_BITS2); if (!(BN_lshift(sdiv,divisor,norm_shift))) goto err; sdiv->neg=0; norm_shift+=BN_BITS2; if (!(BN_lshift(snum,num,norm_shift))) goto err; snum->neg=0; /* Since we don't know whether snum is larger than sdiv, * we pad snum with enough zeroes without changing its * value. */ if (snum->top <= sdiv->top+1) { if (bn_wexpand(snum, sdiv->top + 2) == NULL) goto err; for (i = snum->top; i < sdiv->top + 2; i++) snum->d[i] = 0; snum->top = sdiv->top + 2; } else { if (bn_wexpand(snum, snum->top + 1) == NULL) goto err; snum->d[snum->top] = 0; snum->top ++; } div_n=sdiv->top; num_n=snum->top; loop=num_n-div_n; /* Lets setup a 'window' into snum * This is the part that corresponds to the current * 'area' being divided */ wnum.neg = 0; wnum.d = &(snum->d[loop]); wnum.top = div_n; /* only needed when BN_ucmp messes up the values between top and max */ wnum.dmax = snum->dmax - loop; /* so we don't step out of bounds */ /* Get the top 2 words of sdiv */ /* div_n=sdiv->top; */ d0=sdiv->d[div_n-1]; d1=(div_n == 1)?0:sdiv->d[div_n-2]; /* pointer to the 'top' of snum */ wnump= &(snum->d[num_n-1]); /* Setup to 'res' */ res->neg= (num->neg^divisor->neg); if (!bn_wexpand(res,(loop+1))) goto err; res->top=loop-1; resp= &(res->d[loop-1]); /* space for temp */ if (!bn_wexpand(tmp,(div_n+1))) goto err; /* if res->top == 0 then clear the neg value otherwise decrease * the resp pointer */ if (res->top == 0) res->neg = 0; else resp--; for (i=0; i<loop-1; i++, wnump--, resp--) { BN_ULONG q,l0; /* the first part of the loop uses the top two words of * snum and sdiv to calculate a BN_ULONG q such that * | wnum - sdiv * q | < sdiv */ #if defined(BN_DIV3W) && !defined(OPENSSL_NO_ASM) BN_ULONG bn_div_3_words(BN_ULONG*,BN_ULONG,BN_ULONG); q=bn_div_3_words(wnump,d1,d0); #else BN_ULONG n0,n1,rem=0; n0=wnump[0]; n1=wnump[-1]; if (n0 == d0) q=BN_MASK2; else /* n0 < d0 */ { #ifdef BN_LLONG BN_ULLONG t2; #if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(bn_div_words) q=(BN_ULONG)(((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0); #else q=bn_div_words(n0,n1,d0); #ifdef BN_DEBUG_LEVITTE fprintf(stderr,"DEBUG: bn_div_words(0x%08X,0x%08X,0x%08\ X) -> 0x%08X\n", n0, n1, d0, q); #endif #endif #ifndef REMAINDER_IS_ALREADY_CALCULATED /* * rem doesn't have to be BN_ULLONG. The least we * know it's less that d0, isn't it? */ rem=(n1-q*d0)&BN_MASK2; #endif t2=(BN_ULLONG)d1*q; for (;;) { if (t2 <= ((((BN_ULLONG)rem)<<BN_BITS2)|wnump[-2])) break; q--; rem += d0; if (rem < d0) break; /* don't let rem overflow */ t2 -= d1; } #else /* !BN_LLONG */ BN_ULONG t2l,t2h; #if !defined(BN_UMULT_LOHI) && !defined(BN_UMULT_HIGH) BN_ULONG ql,qh; #endif q=bn_div_words(n0,n1,d0); #ifdef BN_DEBUG_LEVITTE fprintf(stderr,"DEBUG: bn_div_words(0x%08X,0x%08X,0x%08\ X) -> 0x%08X\n", n0, n1, d0, q); #endif #ifndef REMAINDER_IS_ALREADY_CALCULATED rem=(n1-q*d0)&BN_MASK2; #endif #if defined(BN_UMULT_LOHI) BN_UMULT_LOHI(t2l,t2h,d1,q); #elif defined(BN_UMULT_HIGH) t2l = d1 * q; t2h = BN_UMULT_HIGH(d1,q); #else t2l=LBITS(d1); t2h=HBITS(d1); ql =LBITS(q); qh =HBITS(q); mul64(t2l,t2h,ql,qh); /* t2=(BN_ULLONG)d1*q; */ #endif for (;;) { if ((t2h < rem) || ((t2h == rem) && (t2l <= wnump[-2]))) break; q--; rem += d0; if (rem < d0) break; /* don't let rem overflow */ if (t2l < d1) t2h--; t2l -= d1; } #endif /* !BN_LLONG */ } #endif /* !BN_DIV3W */ l0=bn_mul_words(tmp->d,sdiv->d,div_n,q); tmp->d[div_n]=l0; wnum.d--; /* ingore top values of the bignums just sub the two * BN_ULONG arrays with bn_sub_words */ if (bn_sub_words(wnum.d, wnum.d, tmp->d, div_n+1)) { /* Note: As we have considered only the leading * two BN_ULONGs in the calculation of q, sdiv * q * might be greater than wnum (but then (q-1) * sdiv * is less or equal than wnum) */ q--; if (bn_add_words(wnum.d, wnum.d, sdiv->d, div_n)) /* we can't have an overflow here (assuming * that q != 0, but if q == 0 then tmp is * zero anyway) */ (*wnump)++; } /* store part of the result */ *resp = q; } bn_correct_top(snum); if (rm != NULL) { /* Keep a copy of the neg flag in num because if rm==num * BN_rshift() will overwrite it. */ int neg = num->neg; BN_rshift(rm,snum,norm_shift); if (!BN_is_zero(rm)) rm->neg = neg; bn_check_top(rm); } bn_correct_top(res); BN_CTX_end(ctx); return(1); err: bn_check_top(rm); BN_CTX_end(ctx); return(0); }
/* unsigned subtraction of b from a, a must be larger than b. */ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { int max,min; register BN_ULONG t1,t2,*ap,*bp,*rp; int i,carry; #if defined(IRIX_CC_BUG) && !defined(LINT) int dummy; #endif bn_check_top(a); bn_check_top(b); if (a->top < b->top) /* hmm... should not be happening */ { return(0); } max=a->top; min=b->top; if (bn_wexpand(r,max) == NULL) return(0); ap=a->d; bp=b->d; rp=r->d; #if 1 carry=0; for (i=0; i<min; i++) { t1= *(ap++); t2= *(bp++); if (carry) { carry=(t1 <= t2); t1=(t1-t2-1)&BN_MASK2; } else { carry=(t1 < t2); t1=(t1-t2)&BN_MASK2; } #if defined(IRIX_CC_BUG) && !defined(LINT) dummy=t1; #endif *(rp++)=t1&BN_MASK2; } #else carry=bn_sub_words(rp,ap,bp,min); ap+=min; bp+=min; rp+=min; i=min; #endif if (carry) /* subtracted */ { while (i < max) { i++; t1= *(ap++); t2=(t1-1)&BN_MASK2; *(rp++)=t2; if (t1 > t2) break; } } #if 0 memcpy(rp,ap,sizeof(*rp)*(max-i)); #else if (rp != ap) { for (;;) { if (i++ >= max) break; rp[0]=ap[0]; if (i++ >= max) break; rp[1]=ap[1]; if (i++ >= max) break; rp[2]=ap[2]; if (i++ >= max) break; rp[3]=ap[3]; rp+=4; ap+=4; } } #endif r->top=max; bn_fix_top(r); return(1); }
/* I've just gone over this and it is now %20 faster on x86 - eay - 27 Jun 96 */ int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) { int max, al; int ret = 0; BIGNUM *tmp, *rr; #ifdef BN_COUNT fprintf(stderr, "BN_sqr %d * %d\n", a->top, a->top); #endif bn_check_top(a); al = a->top; if (al <= 0) { r->top = 0; r->neg = 0; return 1; } BN_CTX_start(ctx); rr = (a != r) ? r : BN_CTX_get(ctx); tmp = BN_CTX_get(ctx); if (rr == NULL || tmp == NULL) goto err; max = 2 * al; /* Non-zero (from above) */ if (bn_wexpand(rr, max) == NULL) goto err; if (al == 4) { #ifndef BN_SQR_COMBA BN_ULONG t[8]; bn_sqr_normal(rr->d, a->d, 4, t); #else bn_sqr_comba4(rr->d, a->d); #endif } else if (al == 8) { #ifndef BN_SQR_COMBA BN_ULONG t[16]; bn_sqr_normal(rr->d, a->d, 8, t); #else bn_sqr_comba8(rr->d, a->d); #endif } else { #if defined(BN_RECURSION) if (al < BN_SQR_RECURSIVE_SIZE_NORMAL) { BN_ULONG t[BN_SQR_RECURSIVE_SIZE_NORMAL*2]; bn_sqr_normal(rr->d, a->d, al, t); } else { int j, k; j = BN_num_bits_word((BN_ULONG)al); j = 1 << (j - 1); k = j + j; if (al == j) { if (bn_wexpand(tmp, k * 2) == NULL) goto err; bn_sqr_recursive(rr->d, a->d, al, tmp->d); } else { if (bn_wexpand(tmp, max) == NULL) goto err; bn_sqr_normal(rr->d, a->d, al, tmp->d); } } #else if (bn_wexpand(tmp, max) == NULL) goto err; bn_sqr_normal(rr->d, a->d, al, tmp->d); #endif } rr->neg = 0; /* If the most-significant half of the top word of 'a' is zero, then * the square of 'a' will max-1 words. */ if (a->d[al - 1] == (a->d[al - 1] & BN_MASK2l)) rr->top = max - 1; else rr->top = max; if (rr != r) BN_copy(r, rr); ret = 1; err: bn_check_top(rr); bn_check_top(tmp); BN_CTX_end(ctx); return (ret); }
// bn_mul_impl implements |BN_mul| and |bn_mul_consttime|. Note this function // breaks |BIGNUM| invariants and may return a negative zero. This is handled by // the callers. static int bn_mul_impl(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { int al = a->width; int bl = b->width; if (al == 0 || bl == 0) { BN_zero(r); return 1; } int ret = 0; BIGNUM *rr; BN_CTX_start(ctx); if (r == a || r == b) { rr = BN_CTX_get(ctx); if (rr == NULL) { goto err; } } else { rr = r; } rr->neg = a->neg ^ b->neg; int i = al - bl; if (i == 0) { if (al == 8) { if (!bn_wexpand(rr, 16)) { goto err; } rr->width = 16; bn_mul_comba8(rr->d, a->d, b->d); goto end; } } int top = al + bl; static const int kMulNormalSize = 16; if (al >= kMulNormalSize && bl >= kMulNormalSize) { if (-1 <= i && i <= 1) { // Find the larger power of two less than or equal to the larger length. int j; if (i >= 0) { j = BN_num_bits_word((BN_ULONG)al); } else { j = BN_num_bits_word((BN_ULONG)bl); } j = 1 << (j - 1); assert(j <= al || j <= bl); BIGNUM *t = BN_CTX_get(ctx); if (t == NULL) { goto err; } if (al > j || bl > j) { // We know |al| and |bl| are at most one from each other, so if al > j, // bl >= j, and vice versa. Thus we can use |bn_mul_part_recursive|. assert(al >= j && bl >= j); if (!bn_wexpand(t, j * 8) || !bn_wexpand(rr, j * 4)) { goto err; } bn_mul_part_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d); } else { // al <= j && bl <= j. Additionally, we know j <= al or j <= bl, so one // of al - j or bl - j is zero. The other, by the bound on |i| above, is // zero or -1. Thus, we can use |bn_mul_recursive|. if (!bn_wexpand(t, j * 4) || !bn_wexpand(rr, j * 2)) { goto err; } bn_mul_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d); } rr->width = top; goto end; } } if (!bn_wexpand(rr, top)) { goto err; } rr->width = top; bn_mul_normal(rr->d, a->d, al, b->d, bl); end: if (r != rr && !BN_copy(r, rr)) { goto err; } ret = 1; err: BN_CTX_end(ctx); return ret; }