/* BN_mod_add variant that may be used if both a and b are non-negative * and less than m */ int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m) { if (!BN_uadd(r, a, b)) return 0; if (BN_ucmp(r, m) >= 0) return BN_usub(r, r, m); return 1; }
int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { const BIGNUM *tmp; int a_neg = a->neg, ret; // a + b a+b // a + -b a-b // -a + b b-a // -a + -b -(a+b) if (a_neg ^ b->neg) { // only one is negative if (a_neg) { tmp = a; a = b; b = tmp; } // we are now a - b if (BN_ucmp(a, b) < 0) { if (!BN_usub(r, b, a)) { return 0; } r->neg = 1; } else { if (!BN_usub(r, a, b)) { return 0; } r->neg = 0; } return 1; } ret = BN_uadd(r, a, b); r->neg = a_neg; return ret; }
int BN_nist_mod_521(BIGNUM *r, const BIGNUM *a, const BIGNUM *field, BN_CTX *ctx) { #if BN_BITS2 == 64 #define BN_NIST_521_TOP_MASK (BN_ULONG)0x1FF #elif BN_BITS2 == 32 #define BN_NIST_521_TOP_MASK (BN_ULONG)0x1FF #elif BN_BITS2 == 16 #define BN_NIST_521_TOP_MASK (BN_ULONG)0x1FF #elif BN_BITS2 == 8 #define BN_NIST_521_TOP_MASK (BN_ULONG)0x1 #endif int top, ret = 0; BN_ULONG *r_d; BIGNUM *tmp; /* check whether a reduction is necessary */ top = a->top; if (top < BN_NIST_521_TOP || ( top == BN_NIST_521_TOP && (!(a->d[BN_NIST_521_TOP-1] & ~(BN_NIST_521_TOP_MASK))))) return (r == a)? 1 : (BN_copy(r ,a) != NULL); BN_CTX_start(ctx); tmp = BN_CTX_get(ctx); if (!tmp) goto err; if (!bn_wexpand(tmp, BN_NIST_521_TOP)) goto err; nist_cp_bn(tmp->d, a->d, BN_NIST_521_TOP); tmp->top = BN_NIST_521_TOP; tmp->d[BN_NIST_521_TOP-1] &= BN_NIST_521_TOP_MASK; bn_correct_top(tmp); if (!BN_rshift(r, a, 521)) goto err; if (!BN_uadd(r, tmp, r)) goto err; top = r->top; r_d = r->d; if (top == BN_NIST_521_TOP && (r_d[BN_NIST_521_TOP-1] & ~(BN_NIST_521_TOP_MASK))) { BN_NIST_ADD_ONE(r_d) r_d[BN_NIST_521_TOP-1] &= BN_NIST_521_TOP_MASK; } bn_correct_top(r); ret = 1; err: BN_CTX_end(ctx); bn_check_top(r); return ret; }
int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { int max; int add = 0, neg = 0; bn_check_top(a); bn_check_top(b); /*- * a - b a-b * a - -b a+b * -a - b -(a+b) * -a - -b b-a */ if (a->neg) { if (b->neg) { const BIGNUM *tmp; tmp = a; a = b; b = tmp; } else { add = 1; neg = 1; } } else { if (b->neg) { add = 1; neg = 0; } } if (add) { if (!BN_uadd(r, a, b)) return 0; r->neg = neg; return 1; } /* We are actually doing a - b :-) */ max = (a->top > b->top) ? a->top : b->top; if (bn_wexpand(r, max) == NULL) return 0; if (BN_ucmp(a, b) < 0) { if (!BN_usub(r, b, a)) return 0; r->neg = 1; } else { if (!BN_usub(r, a, b)) return 0; r->neg = 0; } bn_check_top(r); return 1; }
static RSA * fermat_question_ask(const RSA *rsa) { BIGNUM *a = BN_new(), *b = BN_new(), *a2 = BN_new(), *b2 = BN_new(); BIGNUM *n = rsa->n; BIGNUM *tmp = BN_new(), *rem = BN_new(), *dssdelta = BN_new(); BN_CTX *ctx = BN_CTX_new(); RSA *ret = NULL; BN_sqrtmod(tmp, rem, n, ctx); /* Δ = |p - q| = |a + b - a + b| = |2b| > √N 2⁻¹⁰⁰ */ /* BN_rshift(dssdelta, tmp, 101); */ BN_one(dssdelta); BN_lshift(dssdelta, dssdelta, BN_num_bits(n) / 4 + 10); BN_copy(a, tmp); BN_sqr(a2, a, ctx); do { /* a² += 2a + 1 */ BN_lshift1(tmp, a); BN_uiadd1(tmp); BN_add(a2, a2, tmp); /* a += 1 */ BN_uiadd1(a); /* b² = a² - N */ BN_usub(b2, a2, n); /* b */ BN_sqrtmod(b, rem, b2, ctx); } while (!BN_is_zero(rem) && BN_cmp(b, dssdelta) < 1); if (BN_is_zero(rem)) { BN_uadd(a, a, b); ret = qa_RSA_recover(rsa, a, ctx); } BN_CTX_free(ctx); BN_free(a); BN_free(b); BN_free(a2); BN_free(b2); BN_free(dssdelta); BN_free(tmp); BN_free(rem); return ret; }
int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { int add = 0, neg = 0; const BIGNUM *tmp; // a - b a-b // a - -b a+b // -a - b -(a+b) // -a - -b b-a if (a->neg) { if (b->neg) { tmp = a; a = b; b = tmp; } else { add = 1; neg = 1; } } else { if (b->neg) { add = 1; neg = 0; } } if (add) { if (!BN_uadd(r, a, b)) { return 0; } r->neg = neg; return 1; } if (BN_ucmp(a, b) < 0) { if (!BN_usub(r, b, a)) { return 0; } r->neg = 1; } else { if (!BN_usub(r, a, b)) { return 0; } r->neg = 0; } return 1; }
/* r can == a or b */ int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { int a_neg = a->neg, ret; bn_check_top(a); bn_check_top(b); /*- * a + b a+b * a + -b a-b * -a + b b-a * -a + -b -(a+b) */ if (a_neg ^ b->neg) { /* only one is negative */ if (a_neg) { const BIGNUM *tmp; tmp = a; a = b; b = tmp; } /* we are now a - b */ if (BN_ucmp(a, b) < 0) { if (!BN_usub(r, b, a)) return 0; r->neg = 1; } else { if (!BN_usub(r, a, b)) return 0; r->neg = 0; } return 1; } ret = BN_uadd(r, a, b); r->neg = a_neg; bn_check_top(r); return ret; }
/* r can == a or b */ int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { const BIGNUM *tmp; bn_check_top(a); bn_check_top(b); /* a + b a+b * a + -b a-b * -a + b b-a * -a + -b -(a+b) */ if (a->neg ^ b->neg) { /* only one is negative */ if (a->neg) { tmp=a; a=b; b=tmp; } /* we are now a - b */ if (BN_ucmp(a,b) < 0) { if (!BN_usub(r,b,a)) return(0); r->neg=1; } else { if (!BN_usub(r,a,b)) return(0); r->neg=0; } return(1); } if (a->neg) /* both are neg */ r->neg=1; else r->neg=0; if (!BN_uadd(r,a,b)) return(0); return(1); }
BIGNUM *BN_mod_inverse(BIGNUM *in, const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx) { BIGNUM *A,*B,*X,*Y,*M,*D,*T,*R=NULL; BIGNUM *ret=NULL; int sign; if ((BN_get_flags(a, BN_FLG_CONSTTIME) != 0) || (BN_get_flags(n, BN_FLG_CONSTTIME) != 0)) { return BN_mod_inverse_no_branch(in, a, n, ctx); } bn_check_top(a); bn_check_top(n); BN_CTX_start(ctx); A = BN_CTX_get(ctx); B = BN_CTX_get(ctx); X = BN_CTX_get(ctx); D = BN_CTX_get(ctx); M = BN_CTX_get(ctx); Y = BN_CTX_get(ctx); T = BN_CTX_get(ctx); if (T == NULL) goto err; if (in == NULL) R=BN_new(); else R=in; if (R == NULL) goto err; BN_one(X); BN_zero(Y); if (BN_copy(B,a) == NULL) goto err; if (BN_copy(A,n) == NULL) goto err; A->neg = 0; if (B->neg || (BN_ucmp(B, A) >= 0)) { if (!BN_nnmod(B, B, A, ctx)) goto err; } sign = -1; /* From B = a mod |n|, A = |n| it follows that * * 0 <= B < A, * -sign*X*a == B (mod |n|), * sign*Y*a == A (mod |n|). */ if (BN_is_odd(n) && (BN_num_bits(n) <= (BN_BITS <= 32 ? 450 : 2048))) { /* Binary inversion algorithm; requires odd modulus. * This is faster than the general algorithm if the modulus * is sufficiently small (about 400 .. 500 bits on 32-bit * sytems, but much more on 64-bit systems) */ int shift; while (!BN_is_zero(B)) { /* * 0 < B < |n|, * 0 < A <= |n|, * (1) -sign*X*a == B (mod |n|), * (2) sign*Y*a == A (mod |n|) */ /* Now divide B by the maximum possible power of two in the integers, * and divide X by the same value mod |n|. * When we're done, (1) still holds. */ shift = 0; while (!BN_is_bit_set(B, shift)) /* note that 0 < B */ { shift++; if (BN_is_odd(X)) { if (!BN_uadd(X, X, n)) goto err; } /* now X is even, so we can easily divide it by two */ if (!BN_rshift1(X, X)) goto err; } if (shift > 0) { if (!BN_rshift(B, B, shift)) goto err; } /* Same for A and Y. Afterwards, (2) still holds. */ shift = 0; while (!BN_is_bit_set(A, shift)) /* note that 0 < A */ { shift++; if (BN_is_odd(Y)) { if (!BN_uadd(Y, Y, n)) goto err; } /* now Y is even */ if (!BN_rshift1(Y, Y)) goto err; } if (shift > 0) { if (!BN_rshift(A, A, shift)) goto err; } /* We still have (1) and (2). * Both A and B are odd. * The following computations ensure that * * 0 <= B < |n|, * 0 < A < |n|, * (1) -sign*X*a == B (mod |n|), * (2) sign*Y*a == A (mod |n|), * * and that either A or B is even in the next iteration. */ if (BN_ucmp(B, A) >= 0) { /* -sign*(X + Y)*a == B - A (mod |n|) */ if (!BN_uadd(X, X, Y)) goto err; /* NB: we could use BN_mod_add_quick(X, X, Y, n), but that * actually makes the algorithm slower */ if (!BN_usub(B, B, A)) goto err; } else { /* sign*(X + Y)*a == A - B (mod |n|) */ if (!BN_uadd(Y, Y, X)) goto err; /* as above, BN_mod_add_quick(Y, Y, X, n) would slow things down */ if (!BN_usub(A, A, B)) goto err; } } } else { /* general inversion algorithm */ while (!BN_is_zero(B)) { BIGNUM *tmp; /* * 0 < B < A, * (*) -sign*X*a == B (mod |n|), * sign*Y*a == A (mod |n|) */ /* (D, M) := (A/B, A%B) ... */ if (BN_num_bits(A) == BN_num_bits(B)) { if (!BN_one(D)) goto err; if (!BN_sub(M,A,B)) goto err; } else if (BN_num_bits(A) == BN_num_bits(B) + 1) { /* A/B is 1, 2, or 3 */ if (!BN_lshift1(T,B)) goto err; if (BN_ucmp(A,T) < 0) { /* A < 2*B, so D=1 */ if (!BN_one(D)) goto err; if (!BN_sub(M,A,B)) goto err; } else { /* A >= 2*B, so D=2 or D=3 */ if (!BN_sub(M,A,T)) goto err; if (!BN_add(D,T,B)) goto err; /* use D (:= 3*B) as temp */ if (BN_ucmp(A,D) < 0) { /* A < 3*B, so D=2 */ if (!BN_set_word(D,2)) goto err; /* M (= A - 2*B) already has the correct value */ } else { /* only D=3 remains */ if (!BN_set_word(D,3)) goto err; /* currently M = A - 2*B, but we need M = A - 3*B */ if (!BN_sub(M,M,B)) goto err; } } } else { if (!BN_div(D,M,A,B,ctx)) goto err; } /* Now * A = D*B + M; * thus we have * (**) sign*Y*a == D*B + M (mod |n|). */ tmp=A; /* keep the BIGNUM object, the value does not matter */ /* (A, B) := (B, A mod B) ... */ A=B; B=M; /* ... so we have 0 <= B < A again */ /* Since the former M is now B and the former B is now A, * (**) translates into * sign*Y*a == D*A + B (mod |n|), * i.e. * sign*Y*a - D*A == B (mod |n|). * Similarly, (*) translates into * -sign*X*a == A (mod |n|). * * Thus, * sign*Y*a + D*sign*X*a == B (mod |n|), * i.e. * sign*(Y + D*X)*a == B (mod |n|). * * So if we set (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at * -sign*X*a == B (mod |n|), * sign*Y*a == A (mod |n|). * Note that X and Y stay non-negative all the time. */ /* most of the time D is very small, so we can optimize tmp := D*X+Y */ if (BN_is_one(D)) { if (!BN_add(tmp,X,Y)) goto err; } else { if (BN_is_word(D,2)) { if (!BN_lshift1(tmp,X)) goto err; } else if (BN_is_word(D,4)) { if (!BN_lshift(tmp,X,2)) goto err; } else if (D->top == 1) { if (!BN_copy(tmp,X)) goto err; if (!BN_mul_word(tmp,D->d[0])) goto err; } else { if (!BN_mul(tmp,D,X,ctx)) goto err; } if (!BN_add(tmp,tmp,Y)) goto err; } M=Y; /* keep the BIGNUM object, the value does not matter */ Y=X; X=tmp; sign = -sign; } } /* * The while loop (Euclid's algorithm) ends when * A == gcd(a,n); * we have * sign*Y*a == A (mod |n|), * where Y is non-negative. */ if (sign < 0) { if (!BN_sub(Y,n,Y)) goto err; } /* Now Y*a == A (mod |n|). */ if (BN_is_one(A)) { /* Y*a == 1 (mod |n|) */ if (!Y->neg && BN_ucmp(Y,n) < 0) { if (!BN_copy(R,Y)) goto err; } else { if (!BN_nnmod(R,Y,n,ctx)) goto err; } } else { BNerr(BN_F_BN_MOD_INVERSE,BN_R_NO_INVERSE); goto err; } ret=R; err: if ((ret == NULL) && (in == NULL)) BN_free(R); BN_CTX_end(ctx); bn_check_top(ret); return(ret); }
int DH_check_pubkey(const DH *dh, const BIGNUM *pub_key, int *codes) { BIGNUM *bn = NULL, *sum = NULL; int ret = 0; *codes = 0; /** * Checks that the function performs are: * - pub_key is not negative */ if (BN_is_negative(pub_key)) goto out; /** * - pub_key > 1 and pub_key < p - 1, * to avoid small subgroups attack. */ bn = BN_new(); if (bn == NULL) goto out; if (!BN_set_word(bn, 1)) goto out; if (BN_cmp(bn, pub_key) >= 0) *codes |= DH_CHECK_PUBKEY_TOO_SMALL; sum = BN_new(); if (sum == NULL) goto out; BN_uadd(sum, pub_key, bn); if (BN_cmp(sum, dh->p) >= 0) *codes |= DH_CHECK_PUBKEY_TOO_LARGE; /** * - if g == 2, pub_key have more then one bit set, * if bits set is 1, log_2(pub_key) is trival */ if (!BN_set_word(bn, 2)) goto out; if (BN_cmp(bn, dh->g) == 0) { unsigned i, n = BN_num_bits(pub_key); unsigned bits = 0; for (i = 0; i <= n; i++) if (BN_is_bit_set(pub_key, i)) bits++; if (bits < 2) { *codes |= DH_CHECK_PUBKEY_TOO_SMALL; goto out; } } ret = 1; out: if (bn) BN_free(bn); if (sum) BN_free(sum); return ret; }
static int test_BN_uadd(void) { BIGNUM *a, *b, *c; char *p; a = BN_new(); b = BN_new(); c = BN_new(); BN_set_word(a, 1); BN_set_word(b, 2); BN_uadd(c, a, b); if (BN_get_word(c) != 3) return 1; BN_uadd(c, b, a); if (BN_get_word(c) != 3) return 1; BN_set_word(b, 0xff); BN_uadd(c, a, b); if (BN_get_word(c) != 0x100) return 1; BN_uadd(c, b, a); if (BN_get_word(c) != 0x100) return 1; BN_set_word(a, 0xff); BN_uadd(c, a, b); if (BN_get_word(c) != 0x1fe) return 1; BN_uadd(c, b, a); if (BN_get_word(c) != 0x1fe) return 1; BN_free(a); BN_free(b); BN_hex2bn(&a, "50212A3B611D46642C825A16A354CE0FD4D85DD2"); BN_hex2bn(&b, "84B6C7E8D28ACA1614954DA"); BN_uadd(c, b, a); p = BN_bn2hex(c); if (strcmp(p, "50212A3B611D466434CDC695307D7AB13621B2AC") != 0) { free(p); return 1; } free(p); BN_uadd(c, a, b); p = BN_bn2hex(c); if (strcmp(p, "50212A3B611D466434CDC695307D7AB13621B2AC") != 0) { free(p); return 1; } free(p); BN_free(a); BN_free(b); BN_free(c); return 0; }