Beispiel #1
0
static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) {
  assert(ctx != NULL);

  assert(rsa->n != NULL);
  assert(rsa->e != NULL);
  assert(rsa->d != NULL);
  assert(rsa->p != NULL);
  assert(rsa->q != NULL);
  assert(rsa->dmp1 != NULL);
  assert(rsa->dmq1 != NULL);
  assert(rsa->iqmp != NULL);

  BIGNUM *r1, *m1;
  int ret = 0;

  BN_CTX_start(ctx);
  r1 = BN_CTX_get(ctx);
  m1 = BN_CTX_get(ctx);
  if (r1 == NULL ||
      m1 == NULL) {
    goto err;
  }

  if (!freeze_private_key(rsa, ctx)) {
    goto err;
  }

  // Implementing RSA with CRT in constant-time is sensitive to which prime is
  // larger. Canonicalize fields so that |p| is the larger prime.
  const BIGNUM *dmp1 = rsa->dmp1_fixed, *dmq1 = rsa->dmq1_fixed;
  const BN_MONT_CTX *mont_p = rsa->mont_p, *mont_q = rsa->mont_q;
  if (BN_cmp(rsa->p, rsa->q) < 0) {
    mont_p = rsa->mont_q;
    mont_q = rsa->mont_p;
    dmp1 = rsa->dmq1_fixed;
    dmq1 = rsa->dmp1_fixed;
  }

  // Use the minimal-width versions of |n|, |p|, and |q|. Either works, but if
  // someone gives us non-minimal values, these will be slightly more efficient
  // on the non-Montgomery operations.
  const BIGNUM *n = &rsa->mont_n->N;
  const BIGNUM *p = &mont_p->N;
  const BIGNUM *q = &mont_q->N;

  // This is a pre-condition for |mod_montgomery|. It was already checked by the
  // caller.
  assert(BN_ucmp(I, n) < 0);

  if (// |m1| is the result modulo |q|.
      !mod_montgomery(r1, I, q, mont_q, p, ctx) ||
      !BN_mod_exp_mont_consttime(m1, r1, dmq1, q, ctx, mont_q) ||
      // |r0| is the result modulo |p|.
      !mod_montgomery(r1, I, p, mont_p, q, ctx) ||
      !BN_mod_exp_mont_consttime(r0, r1, dmp1, p, ctx, mont_p) ||
      // Compute r0 = r0 - m1 mod p. |p| is the larger prime, so |m1| is already
      // fully reduced mod |p|.
      !bn_mod_sub_consttime(r0, r0, m1, p, ctx) ||
      // r0 = r0 * iqmp mod p. We use Montgomery multiplication to compute this
      // in constant time. |inv_small_mod_large_mont| is in Montgomery form and
      // r0 is not, so the result is taken out of Montgomery form.
      !BN_mod_mul_montgomery(r0, r0, rsa->inv_small_mod_large_mont, mont_p,
                             ctx) ||
      // r0 = r0 * q + m1 gives the final result. Reducing modulo q gives m1, so
      // it is correct mod p. Reducing modulo p gives (r0-m1)*iqmp*q + m1 = r0,
      // so it is correct mod q. Finally, the result is bounded by [m1, n + m1),
      // and the result is at least |m1|, so this must be the unique answer in
      // [0, n).
      !bn_mul_consttime(r0, r0, q, ctx) ||
      !bn_uadd_consttime(r0, r0, m1) ||
      // The result should be bounded by |n|, but fixed-width operations may
      // bound the width slightly higher, so fix it.
      !bn_resize_words(r0, n->width)) {
    goto err;
  }

  ret = 1;

err:
  BN_CTX_end(ctx);
  return ret;
}
int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
                      BN_CTX *ctx) {
  int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *,
                   BN_CTX *);
  int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
  const BIGNUM *p;
  BN_CTX *new_ctx = NULL;
  BIGNUM *n0, *n1, *n2, *n3;
  int ret = 0;

  if (EC_POINT_is_at_infinity(group, a)) {
    BN_zero(&r->Z);
    return 1;
  }

  field_mul = group->meth->field_mul;
  field_sqr = group->meth->field_sqr;
  p = &group->field;

  if (ctx == NULL) {
    ctx = new_ctx = BN_CTX_new();
    if (ctx == NULL) {
      return 0;
    }
  }

  BN_CTX_start(ctx);
  n0 = BN_CTX_get(ctx);
  n1 = BN_CTX_get(ctx);
  n2 = BN_CTX_get(ctx);
  n3 = BN_CTX_get(ctx);
  if (n3 == NULL) {
    goto err;
  }

  // Note that in this function we must not read components of 'a'
  // once we have written the corresponding components of 'r'.
  // ('r' might the same as 'a'.)

  // n1
  if (BN_cmp(&a->Z, &group->one) == 0) {
    if (!field_sqr(group, n0, &a->X, ctx) ||
        !bn_mod_lshift1_consttime(n1, n0, p, ctx) ||
        !bn_mod_add_consttime(n0, n0, n1, p, ctx) ||
        !bn_mod_add_consttime(n1, n0, &group->a, p, ctx)) {
      goto err;
    }
    // n1 = 3 * X_a^2 + a_curve
  } else if (group->a_is_minus3) {
    if (!field_sqr(group, n1, &a->Z, ctx) ||
        !bn_mod_add_consttime(n0, &a->X, n1, p, ctx) ||
        !bn_mod_sub_consttime(n2, &a->X, n1, p, ctx) ||
        !field_mul(group, n1, n0, n2, ctx) ||
        !bn_mod_lshift1_consttime(n0, n1, p, ctx) ||
        !bn_mod_add_consttime(n1, n0, n1, p, ctx)) {
      goto err;
    }
    // n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2)
    //    = 3 * X_a^2 - 3 * Z_a^4
  } else {
    if (!field_sqr(group, n0, &a->X, ctx) ||
        !bn_mod_lshift1_consttime(n1, n0, p, ctx) ||
        !bn_mod_add_consttime(n0, n0, n1, p, ctx) ||
        !field_sqr(group, n1, &a->Z, ctx) ||
        !field_sqr(group, n1, n1, ctx) ||
        !field_mul(group, n1, n1, &group->a, ctx) ||
        !bn_mod_add_consttime(n1, n1, n0, p, ctx)) {
      goto err;
    }
    // n1 = 3 * X_a^2 + a_curve * Z_a^4
  }

  // Z_r
  if (BN_cmp(&a->Z, &group->one) == 0) {
    if (!BN_copy(n0, &a->Y)) {
      goto err;
    }
  } else if (!field_mul(group, n0, &a->Y, &a->Z, ctx)) {
    goto err;
  }
  if (!bn_mod_lshift1_consttime(&r->Z, n0, p, ctx)) {
    goto err;
  }
  // Z_r = 2 * Y_a * Z_a

  // n2
  if (!field_sqr(group, n3, &a->Y, ctx) ||
      !field_mul(group, n2, &a->X, n3, ctx) ||
      !bn_mod_lshift_consttime(n2, n2, 2, p, ctx)) {
    goto err;
  }
  // n2 = 4 * X_a * Y_a^2

  // X_r
  if (!bn_mod_lshift1_consttime(n0, n2, p, ctx) ||
      !field_sqr(group, &r->X, n1, ctx) ||
      !bn_mod_sub_consttime(&r->X, &r->X, n0, p, ctx)) {
    goto err;
  }
  // X_r = n1^2 - 2 * n2

  // n3
  if (!field_sqr(group, n0, n3, ctx) ||
      !bn_mod_lshift_consttime(n3, n0, 3, p, ctx)) {
    goto err;
  }
  // n3 = 8 * Y_a^4

  // Y_r
  if (!bn_mod_sub_consttime(n0, n2, &r->X, p, ctx) ||
      !field_mul(group, n0, n1, n0, ctx) ||
      !bn_mod_sub_consttime(&r->Y, n0, n3, p, ctx)) {
    goto err;
  }
  // Y_r = n1 * (n2 - X_r) - n3

  ret = 1;

err:
  BN_CTX_end(ctx);
  BN_CTX_free(new_ctx);
  return ret;
}
int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
                              BN_CTX *ctx) {
  int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *,
                   BN_CTX *);
  int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
  const BIGNUM *p;
  BN_CTX *new_ctx = NULL;
  BIGNUM *rh, *tmp, *Z4, *Z6;
  int ret = 0;

  if (EC_POINT_is_at_infinity(group, point)) {
    return 1;
  }

  field_mul = group->meth->field_mul;
  field_sqr = group->meth->field_sqr;
  p = &group->field;

  if (ctx == NULL) {
    ctx = new_ctx = BN_CTX_new();
    if (ctx == NULL) {
      return 0;
    }
  }

  BN_CTX_start(ctx);
  rh = BN_CTX_get(ctx);
  tmp = BN_CTX_get(ctx);
  Z4 = BN_CTX_get(ctx);
  Z6 = BN_CTX_get(ctx);
  if (Z6 == NULL) {
    goto err;
  }

  // We have a curve defined by a Weierstrass equation
  //      y^2 = x^3 + a*x + b.
  // The point to consider is given in Jacobian projective coordinates
  // where  (X, Y, Z)  represents  (x, y) = (X/Z^2, Y/Z^3).
  // Substituting this and multiplying by  Z^6  transforms the above equation
  // into
  //      Y^2 = X^3 + a*X*Z^4 + b*Z^6.
  // To test this, we add up the right-hand side in 'rh'.

  // rh := X^2
  if (!field_sqr(group, rh, &point->X, ctx)) {
    goto err;
  }

  if (BN_cmp(&point->Z, &group->one) != 0) {
    if (!field_sqr(group, tmp, &point->Z, ctx) ||
        !field_sqr(group, Z4, tmp, ctx) ||
        !field_mul(group, Z6, Z4, tmp, ctx)) {
      goto err;
    }

    // rh := (rh + a*Z^4)*X
    if (group->a_is_minus3) {
      if (!bn_mod_lshift1_consttime(tmp, Z4, p, ctx) ||
          !bn_mod_add_consttime(tmp, tmp, Z4, p, ctx) ||
          !bn_mod_sub_consttime(rh, rh, tmp, p, ctx) ||
          !field_mul(group, rh, rh, &point->X, ctx)) {
        goto err;
      }
    } else {
      if (!field_mul(group, tmp, Z4, &group->a, ctx) ||
          !bn_mod_add_consttime(rh, rh, tmp, p, ctx) ||
          !field_mul(group, rh, rh, &point->X, ctx)) {
        goto err;
      }
    }

    // rh := rh + b*Z^6
    if (!field_mul(group, tmp, &group->b, Z6, ctx) ||
        !bn_mod_add_consttime(rh, rh, tmp, p, ctx)) {
      goto err;
    }
  } else {
    // rh := (rh + a)*X
    if (!bn_mod_add_consttime(rh, rh, &group->a, p, ctx) ||
        !field_mul(group, rh, rh, &point->X, ctx)) {
      goto err;
    }
    // rh := rh + b
    if (!bn_mod_add_consttime(rh, rh, &group->b, p, ctx)) {
      goto err;
    }
  }

  // 'lh' := Y^2
  if (!field_sqr(group, tmp, &point->Y, ctx)) {
    goto err;
  }

  ret = (0 == BN_ucmp(tmp, rh));

err:
  BN_CTX_end(ctx);
  BN_CTX_free(new_ctx);
  return ret;
}
int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
                      const EC_POINT *b, BN_CTX *ctx) {
  int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *,
                   BN_CTX *);
  int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
  const BIGNUM *p;
  BN_CTX *new_ctx = NULL;
  BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6;
  int ret = 0;

  if (a == b) {
    return EC_POINT_dbl(group, r, a, ctx);
  }
  if (EC_POINT_is_at_infinity(group, a)) {
    return EC_POINT_copy(r, b);
  }
  if (EC_POINT_is_at_infinity(group, b)) {
    return EC_POINT_copy(r, a);
  }

  field_mul = group->meth->field_mul;
  field_sqr = group->meth->field_sqr;
  p = &group->field;

  if (ctx == NULL) {
    ctx = new_ctx = BN_CTX_new();
    if (ctx == NULL) {
      return 0;
    }
  }

  BN_CTX_start(ctx);
  n0 = BN_CTX_get(ctx);
  n1 = BN_CTX_get(ctx);
  n2 = BN_CTX_get(ctx);
  n3 = BN_CTX_get(ctx);
  n4 = BN_CTX_get(ctx);
  n5 = BN_CTX_get(ctx);
  n6 = BN_CTX_get(ctx);
  if (n6 == NULL) {
    goto end;
  }

  // Note that in this function we must not read components of 'a' or 'b'
  // once we have written the corresponding components of 'r'.
  // ('r' might be one of 'a' or 'b'.)

  // n1, n2
  int b_Z_is_one = BN_cmp(&b->Z, &group->one) == 0;

  if (b_Z_is_one) {
    if (!BN_copy(n1, &a->X) || !BN_copy(n2, &a->Y)) {
      goto end;
    }
    // n1 = X_a
    // n2 = Y_a
  } else {
    if (!field_sqr(group, n0, &b->Z, ctx) ||
        !field_mul(group, n1, &a->X, n0, ctx)) {
      goto end;
    }
    // n1 = X_a * Z_b^2

    if (!field_mul(group, n0, n0, &b->Z, ctx) ||
        !field_mul(group, n2, &a->Y, n0, ctx)) {
      goto end;
    }
    // n2 = Y_a * Z_b^3
  }

  // n3, n4
  int a_Z_is_one = BN_cmp(&a->Z, &group->one) == 0;
  if (a_Z_is_one) {
    if (!BN_copy(n3, &b->X) || !BN_copy(n4, &b->Y)) {
      goto end;
    }
    // n3 = X_b
    // n4 = Y_b
  } else {
    if (!field_sqr(group, n0, &a->Z, ctx) ||
        !field_mul(group, n3, &b->X, n0, ctx)) {
      goto end;
    }
    // n3 = X_b * Z_a^2

    if (!field_mul(group, n0, n0, &a->Z, ctx) ||
        !field_mul(group, n4, &b->Y, n0, ctx)) {
      goto end;
    }
    // n4 = Y_b * Z_a^3
  }

  // n5, n6
  if (!bn_mod_sub_consttime(n5, n1, n3, p, ctx) ||
      !bn_mod_sub_consttime(n6, n2, n4, p, ctx)) {
    goto end;
  }
  // n5 = n1 - n3
  // n6 = n2 - n4

  if (BN_is_zero(n5)) {
    if (BN_is_zero(n6)) {
      // a is the same point as b
      BN_CTX_end(ctx);
      ret = EC_POINT_dbl(group, r, a, ctx);
      ctx = NULL;
      goto end;
    } else {
      // a is the inverse of b
      BN_zero(&r->Z);
      ret = 1;
      goto end;
    }
  }

  // 'n7', 'n8'
  if (!bn_mod_add_consttime(n1, n1, n3, p, ctx) ||
      !bn_mod_add_consttime(n2, n2, n4, p, ctx)) {
    goto end;
  }
  // 'n7' = n1 + n3
  // 'n8' = n2 + n4

  // Z_r
  if (a_Z_is_one && b_Z_is_one) {
    if (!BN_copy(&r->Z, n5)) {
      goto end;
    }
  } else {
    if (a_Z_is_one) {
      if (!BN_copy(n0, &b->Z)) {
        goto end;
      }
    } else if (b_Z_is_one) {
      if (!BN_copy(n0, &a->Z)) {
        goto end;
      }
    } else if (!field_mul(group, n0, &a->Z, &b->Z, ctx)) {
      goto end;
    }
    if (!field_mul(group, &r->Z, n0, n5, ctx)) {
      goto end;
    }
  }

  // Z_r = Z_a * Z_b * n5

  // X_r
  if (!field_sqr(group, n0, n6, ctx) ||
      !field_sqr(group, n4, n5, ctx) ||
      !field_mul(group, n3, n1, n4, ctx) ||
      !bn_mod_sub_consttime(&r->X, n0, n3, p, ctx)) {
    goto end;
  }
  // X_r = n6^2 - n5^2 * 'n7'

  // 'n9'
  if (!bn_mod_lshift1_consttime(n0, &r->X, p, ctx) ||
      !bn_mod_sub_consttime(n0, n3, n0, p, ctx)) {
    goto end;
  }
  // n9 = n5^2 * 'n7' - 2 * X_r

  // Y_r
  if (!field_mul(group, n0, n0, n6, ctx) ||
      !field_mul(group, n5, n4, n5, ctx)) {
    goto end;  // now n5 is n5^3
  }
  if (!field_mul(group, n1, n2, n5, ctx) ||
      !bn_mod_sub_consttime(n0, n0, n1, p, ctx)) {
    goto end;
  }
  if (BN_is_odd(n0) && !BN_add(n0, n0, p)) {
    goto end;
  }
  // now  0 <= n0 < 2*p,  and n0 is even
  if (!BN_rshift1(&r->Y, n0)) {
    goto end;
  }
  // Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2

  ret = 1;

end:
  if (ctx) {
    // otherwise we already called BN_CTX_end
    BN_CTX_end(ctx);
  }
  BN_CTX_free(new_ctx);
  return ret;
}