Hi all, we have recently disclosed a vulnerability in ECDSA on binary field curves in the SunEC library used in OpenJDK at:
https://minerva.crocs.fi.muni.cz We have prepared a patch for this earlier, which was sent to Oracle along with the report of the vulnerability. As the vulnerability is not fixed at this time, I am resending the patch here. *Vulnerability description* Timing leak in ECDSA signature generation on binary field curves (ec2) in the SunEC library (libsunec.so). The library essentially leaks the bit-length of the secret nonce used in the scalar multiplication via the duration of scalar multiplication. This leak is present in all scalar multiplication on binary field curves in SunEC, but can be abused in the case of ECDSA, where an attacker that is able to measure the duration of signing of a few hundreds or thousands of known messages can use a lattice attack based on the Hidden Number Problem [1] to reconstruct the private key used, as demonstrated in [2]. *Issue* The issue is in ec_GF2m_pt_mul_mont in ec2_mont.c which starts the Montgomery ladder at the most significant set bit thus leaking bit-length by the duration of the loop. This is necessary because the addition formulas used are incomplete (they cannot handle the point at infinity correctly) and thus the computation of the ladder cannot start past the end of the scalar at some fixed bit-length (of the order of the curve for example). If it did, the variables (x1, z1) would have to be initialized with the point at infinity, which is not even representable in the coordinates that are used here. *Affected* Java 7 - Java 12 (current master) seems to all be affected, because ec_GF2m_pt_mul_mont was not changed during that time and ECDSA_SignDigestWithSeed calls it through this call chain: ECDSA_SignDigestWithSeed -> ec_points_mul -> ECPoints_mul -> group->points_mul == ec_pts_mul_basic -> ECPoint_mul -> group->point_mul == ec_GF2m_pt_mul_mont Notice also the pointless detour through the multi-scalar multiplication functions which then short circuit to the single-scalar multiplication function when only one input is provided. *Mitigation* One mitigation, that was presented in [2] and is used in quite a few libraries, is to blind the bit-length of the secret nonce (and any secret scalar used in EC point multiplication, so private key in ECDH, etc.) as follows: Instead of computing [k]G, with k being the nonce, compute k* = k + 2*n (if log_2(k + n) = log_2(n)) = k + n (else) then compute [k*]G, which = [k]G, because n is the order of the subgroup. The log_2(k*) is then a fixed value, so nothing leaks. This fixes the bit-length of k*, such that the distribution of k = k* mod n remains unaffected (and so ECDSA is ok with regards to lattice attacks on biased nonces) and [k*]G = [k]G so the mitigation is correct. Other mitigations might include using complete addition formulas, which will allows the ladder to start at any bit past the end of the scalar, thus it might be fixed to the order bit-length. The patch does the following to fix the issue: - ec.c: * Splits ec_points_mul to ec_point_mul and ec_points_mul, so that the single-scalar multiplication doesn't go through ECPoints_mul and the multi-scalar functions. * Cleans up some ifdef'ed code that really has no purpose to be there. * Adds the mitigation to the ECDSA sign function. - ecl_mult.c, ecl.h: * Introduces an argument to the ECPoint_mul and ECPoints_mul function that specifies whether to reduce the scalar modulo the order or not. This is necessary because the mitigation in ECDSA adjust the scalar to be bigger than the order. So reducing here would negate the effect. This argument is false (not reduce) only in the ECDSA sign call site. - ecp_jm.c: * Changes the orderBitSize bound in the ec_GFp_pt_mul_jm_wNAF function to take the maximum of the order bit size and the scalar bit size. For reduced scalars, this is constant and is equal to the order bit size. For scalars produced as a result of the above mitigation, this is larger than the order bit size, but still constant. - ecp_aff.c, ec2_aff.c: * Use the new parameter to the ECPoint_mul function in the pubkey validation functions. After applying this patch, all tests passed on my end, I tested with: make test TEST="sun/security/ec" With this patch applied, one issue could still be present. Since the scalars passed to the scalar multiplication function will not be reduced, there is a possibility that the point at infinity is reached as an intermediate value during computation. Looking at the prime field code, there it should not be an issue, as the formulas handle the case of a point at infinity by short circuiting and returning the correct value. The timing difference by the short-circuit would be minuscule in this case and mitigated by the currently applied timing measure. Looking at the binary field case might pose a problem currently, as the formulas are incomplete (which is actually the root cause of this whole vulnerability) and do not short-circuit on the point at infinity. This point doesn't really have a representation in the coordinates used, but could be represented and detected as (0, 0), then the formulas could be made to handle this and short-circuit to the correct result. It can be shown that for scalars of the form k + n or k + 2n, with k in [1, n-1], the intermediate value of [n]G or [2n]G is is only reached in Montgomery ladder for a few values so that this is actually not an issue. [1]: D. Boneh, R. Venkatesan: Hardness of computing the most significant bits of secret keys in Diffie-Hellman and related schemes; https://crypto.stanford.edu/~dabo/abstracts/dhmsb.html [2]: B. B. Brumley, N. Tuveri: Remote Timing Attacks are Still Practical; https://eprint.iacr.org/2011/232.pdf Cheers, Jan
diff -r f3630a2d3d5c src/jdk.crypto.ec/share/native/libsunec/impl/ec.c
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ec.c Tue Aug 13 14:59:29 2019 +0200
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ec.c Wed Aug 14 17:34:19 2019 +0200
@@ -81,55 +81,88 @@
return PR_TRUE;
}
+SECStatus
+ec_point_mul(const ECParams *params, const mp_int *k, const SECItem *pointP,
+ SECItem *pointQ, int kmflag, int reduce, int timing)
+{
+ mp_int Px, Py, Qx, Qy;
+ ECGroup *group = NULL;
+ SECStatus rv = SECFailure;
+ mp_err err = MP_OKAY;
+ unsigned int len;
+
+ len = (params->fieldID.size + 7) >> 3;
+ if (pointP != NULL) {
+ if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) ||
+ (pointP->len != (2 * len + 1))) {
+ return SECFailure;
+ };
+ }
+
+ MP_DIGITS(&Px) = 0;
+ MP_DIGITS(&Py) = 0;
+ MP_DIGITS(&Qx) = 0;
+ MP_DIGITS(&Qy) = 0;
+ CHECK_MPI_OK( mp_init(&Px, kmflag) );
+ CHECK_MPI_OK( mp_init(&Py, kmflag) );
+ CHECK_MPI_OK( mp_init(&Qx, kmflag) );
+ CHECK_MPI_OK( mp_init(&Qy, kmflag) );
+
+ if (pointP != NULL) {
+ CHECK_MPI_OK(mp_read_unsigned_octets(&Px, pointP->data + 1, (mp_size)len));
+ CHECK_MPI_OK(mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size)len));
+ }
+
+ if (params->name != ECCurve_noName) {
+ group = ECGroup_fromName(params->name, kmflag);
+ }
+
+ if (group == NULL)
+ goto cleanup;
+
+ if (pointP != NULL) {
+ CHECK_MPI_OK( ECPoint_mul(group, k, &Px, &Py, &Qx, &Qy, reduce, timing) );
+ } else {
+ CHECK_MPI_OK( ECPoint_mul(group, k, NULL, NULL, &Qx, &Qy, reduce, timing) );
+ }
+
+ /* Construct the SECItem representation of point Q */
+ pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED;
+ CHECK_MPI_OK( mp_to_fixlen_octets(&Qx, pointQ->data + 1,
+ (mp_size) len) );
+ CHECK_MPI_OK( mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len,
+ (mp_size) len) );
+
+ rv = SECSuccess;
+cleanup:
+ ECGroup_free(group);
+ mp_clear(&Px);
+ mp_clear(&Py);
+ mp_clear(&Qx);
+ mp_clear(&Qy);
+ if (err) {
+ MP_TO_SEC_ERROR(err);
+ rv = SECFailure;
+ }
+
+ return rv;
+}
+
/*
* Computes scalar point multiplication pointQ = k1 * G + k2 * pointP for
* the curve whose parameters are encoded in params with base point G.
*/
SECStatus
ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2,
- const SECItem *pointP, SECItem *pointQ, int kmflag, int timing)
+ const SECItem *pointP, SECItem *pointQ, int kmflag, int reduce, int timing)
{
mp_int Px, Py, Qx, Qy;
mp_int Gx, Gy, order, irreducible, a, b;
-#if 0 /* currently don't support non-named curves */
- unsigned int irr_arr[5];
-#endif
ECGroup *group = NULL;
SECStatus rv = SECFailure;
mp_err err = MP_OKAY;
unsigned int len;
-#if EC_DEBUG
- int i;
- char mpstr[256];
-
- printf("ec_points_mul: params [len=%d]:", params->DEREncoding.len);
- for (i = 0; i < params->DEREncoding.len; i++)
- printf("%02x:", params->DEREncoding.data[i]);
- printf("\n");
-
- if (k1 != NULL) {
- mp_tohex((mp_int*)k1, mpstr);
- printf("ec_points_mul: scalar k1: %s\n", mpstr);
- mp_todecimal((mp_int*)k1, mpstr);
- printf("ec_points_mul: scalar k1: %s (dec)\n", mpstr);
- }
-
- if (k2 != NULL) {
- mp_tohex((mp_int*)k2, mpstr);
- printf("ec_points_mul: scalar k2: %s\n", mpstr);
- mp_todecimal((mp_int*)k2, mpstr);
- printf("ec_points_mul: scalar k2: %s (dec)\n", mpstr);
- }
-
- if (pointP != NULL) {
- printf("ec_points_mul: pointP [len=%d]:", pointP->len);
- for (i = 0; i < pointP->len; i++)
- printf("%02x:", pointP->data[i]);
- printf("\n");
- }
-#endif
-
/* NOTE: We only support uncompressed points for now */
len = (params->fieldID.size + 7) >> 3;
if (pointP != NULL) {
@@ -143,66 +176,24 @@
MP_DIGITS(&Py) = 0;
MP_DIGITS(&Qx) = 0;
MP_DIGITS(&Qy) = 0;
- MP_DIGITS(&Gx) = 0;
- MP_DIGITS(&Gy) = 0;
- MP_DIGITS(&order) = 0;
- MP_DIGITS(&irreducible) = 0;
- MP_DIGITS(&a) = 0;
- MP_DIGITS(&b) = 0;
CHECK_MPI_OK( mp_init(&Px, kmflag) );
CHECK_MPI_OK( mp_init(&Py, kmflag) );
CHECK_MPI_OK( mp_init(&Qx, kmflag) );
CHECK_MPI_OK( mp_init(&Qy, kmflag) );
- CHECK_MPI_OK( mp_init(&Gx, kmflag) );
- CHECK_MPI_OK( mp_init(&Gy, kmflag) );
- CHECK_MPI_OK( mp_init(&order, kmflag) );
- CHECK_MPI_OK( mp_init(&irreducible, kmflag) );
- CHECK_MPI_OK( mp_init(&a, kmflag) );
- CHECK_MPI_OK( mp_init(&b, kmflag) );
- if ((k2 != NULL) && (pointP != NULL)) {
- /* Initialize Px and Py */
CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1, (mp_size) len) );
CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size) len) );
- }
/* construct from named params, if possible */
if (params->name != ECCurve_noName) {
group = ECGroup_fromName(params->name, kmflag);
}
-#if 0 /* currently don't support non-named curves */
- if (group == NULL) {
- /* Set up mp_ints containing the curve coefficients */
- CHECK_MPI_OK( mp_read_unsigned_octets(&Gx, params->base.data + 1,
- (mp_size) len) );
- CHECK_MPI_OK( mp_read_unsigned_octets(&Gy, params->base.data + 1 + len,
- (mp_size) len) );
- SECITEM_TO_MPINT( params->order, &order );
- SECITEM_TO_MPINT( params->curve.a, &a );
- SECITEM_TO_MPINT( params->curve.b, &b );
- if (params->fieldID.type == ec_field_GFp) {
- SECITEM_TO_MPINT( params->fieldID.u.prime, &irreducible );
- group = ECGroup_consGFp(&irreducible, &a, &b, &Gx, &Gy, &order, params->cofactor);
- } else {
- SECITEM_TO_MPINT( params->fieldID.u.poly, &irreducible );
- irr_arr[0] = params->fieldID.size;
- irr_arr[1] = params->fieldID.k1;
- irr_arr[2] = params->fieldID.k2;
- irr_arr[3] = params->fieldID.k3;
- irr_arr[4] = 0;
- group = ECGroup_consGF2m(&irreducible, irr_arr, &a, &b, &Gx, &Gy, &order, params->cofactor);
- }
- }
-#endif
if (group == NULL)
goto cleanup;
- if ((k2 != NULL) && (pointP != NULL)) {
- CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy, timing) );
- } else {
- CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy, timing) );
- }
+ CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy, reduce, timing) );
+
/* Construct the SECItem representation of point Q */
pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED;
@@ -213,25 +204,12 @@
rv = SECSuccess;
-#if EC_DEBUG
- printf("ec_points_mul: pointQ [len=%d]:", pointQ->len);
- for (i = 0; i < pointQ->len; i++)
- printf("%02x:", pointQ->data[i]);
- printf("\n");
-#endif
-
cleanup:
ECGroup_free(group);
mp_clear(&Px);
mp_clear(&Py);
mp_clear(&Qx);
mp_clear(&Qy);
- mp_clear(&Gx);
- mp_clear(&Gy);
- mp_clear(&order);
- mp_clear(&irreducible);
- mp_clear(&a);
- mp_clear(&b);
if (err) {
MP_TO_SEC_ERROR(err);
rv = SECFailure;
@@ -255,9 +233,6 @@
mp_err err = MP_OKAY;
int len;
-#if EC_DEBUG
- printf("ec_NewKey called\n");
-#endif
k.dp = (mp_digit*)NULL;
if (!ecParams || !privKey || !privKeyBytes || (privKeyLen < 0)) {
@@ -334,7 +309,7 @@
(mp_size) len) );
/* key generation does not support timing mitigation */
- rv = ec_points_mul(ecParams, &k, NULL, NULL, &(key->publicValue), kmflag, /*timing*/ 0);
+ rv = ec_point_mul(ecParams, &k, NULL, &(key->publicValue), kmflag, 1, /*timing*/ 0);
if (rv != SECSuccess) goto cleanup;
*privKey = key;
@@ -344,13 +319,7 @@
PORT_FreeArena(arena, PR_TRUE);
}
-#if EC_DEBUG
- printf("ec_NewKey returning %s\n",
- (rv == SECSuccess) ? "success" : "failure");
-#endif
-
return rv;
-
}
/* Generates a new EC key pair. The private key is a supplied
@@ -463,10 +432,6 @@
if (privKeyBytes) {
PORT_ZFree(privKeyBytes, len * 2);
}
-#if EC_DEBUG
- printf("EC_NewKey returning %s\n",
- (rv == SECSuccess) ? "success" : "failure");
-#endif
return rv;
}
@@ -578,9 +543,6 @@
mp_int k; /* to hold the private value */
mp_int cofactor;
mp_err err = MP_OKAY;
-#if EC_DEBUG
- int i;
-#endif
if (!publicValue || !ecParams || !privateValue ||
!derivedSecret) {
@@ -612,7 +574,7 @@
/* Multiply our private key and peer's public point */
/* ECDH doesn't support timing mitigation */
- if ((ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ, kmflag, /*timing*/ 0) != SECSuccess) ||
+ if ((ec_point_mul(ecParams, &k, publicValue, &pointQ, kmflag, 1, /*timing*/ 0) != SECSuccess) ||
ec_point_at_infinity(&pointQ))
goto cleanup;
@@ -624,13 +586,6 @@
rv = SECSuccess;
-#if EC_DEBUG
- printf("derived_secret:\n");
- for (i = 0; i < derivedSecret->len; i++)
- printf("%02x:", derivedSecret->data[i]);
- printf("\n");
-#endif
-
cleanup:
mp_clear(&k);
@@ -662,10 +617,6 @@
unsigned olen; /* length in bytes of the base point order */
unsigned int orderBitSize;
-#if EC_DEBUG
- char mpstr[256];
-#endif
-
/* Initialize MPI integers. */
/* must happen before the first potential call to cleanup */
MP_DIGITS(&x1) = 0;
@@ -707,17 +658,16 @@
CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, kblen) );
/* Make sure k is in the interval [1, n-1] */
if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) {
-#if EC_DEBUG
- printf("k is outside [1, n-1]\n");
- mp_tohex(&k, mpstr);
- printf("k : %s \n", mpstr);
- mp_tohex(&n, mpstr);
- printf("n : %s \n", mpstr);
-#endif
PORT_SetError(SEC_ERROR_NEED_RANDOM);
goto cleanup;
}
+ /* Fix bit-length of random nonce to prevent leakage. */
+ mp_add(&k, &n, &k);
+ if (mpl_significant_bits(&k) != mpl_significant_bits(&n)) {
+ mp_add(&k, &n, &k);
+ }
+
/*
** ANSI X9.62, Section 5.3.2, Step 2
**
@@ -726,7 +676,7 @@
kGpoint.len = 2*flen + 1;
kGpoint.data = PORT_Alloc(2*flen + 1, kmflag);
if ((kGpoint.data == NULL) ||
- (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint, kmflag, timing)
+ (ec_point_mul(ecParams, &k, NULL, &kGpoint, kmflag, 0, timing)
!= SECSuccess))
goto cleanup;
@@ -770,21 +720,6 @@
mpl_rsh(&s,&s,digest->len*8 - orderBitSize);
}
-#if EC_DEBUG
- mp_todecimal(&n, mpstr);
- printf("n : %s (dec)\n", mpstr);
- mp_todecimal(&d, mpstr);
- printf("d : %s (dec)\n", mpstr);
- mp_tohex(&x1, mpstr);
- printf("x1: %s\n", mpstr);
- mp_todecimal(&s, mpstr);
- printf("digest: %s (decimal)\n", mpstr);
- mp_todecimal(&r, mpstr);
- printf("r : %s (dec)\n", mpstr);
- mp_tohex(&r, mpstr);
- printf("r : %s\n", mpstr);
-#endif
-
CHECK_MPI_OK( mp_invmod(&k, &n, &k) ); /* k = k**-1 mod n */
CHECK_MPI_OK( mp_mulmod(&d, &r, &n, &d) ); /* d = d * r mod n */
CHECK_MPI_OK( mp_addmod(&s, &d, &n, &s) ); /* s = s + d mod n */
@@ -834,12 +769,6 @@
MP_TO_SEC_ERROR(err);
rv = SECFailure;
}
-
-#if EC_DEBUG
- printf("ECDSA signing with seed %s\n",
- (rv == SECSuccess) ? "succeeded" : "failed");
-#endif
-
return rv;
}
@@ -874,11 +803,6 @@
PORT_ZFree(kBytes, len * 2);
}
-#if EC_DEBUG
- printf("ECDSA signing %s\n",
- (rv == SECSuccess) ? "succeeded" : "failed");
-#endif
-
return rv;
}
@@ -902,11 +826,6 @@
unsigned olen; /* length in bytes of the base point order */
unsigned int orderBitSize;
-#if EC_DEBUG
- char mpstr[256];
- printf("ECDSA verification called\n");
-#endif
-
/* Initialize MPI integers. */
/* must happen before the first potential call to cleanup */
MP_DIGITS(&r_) = 0;
@@ -988,17 +907,6 @@
mpl_rsh(&u1,&u1,digest->len*8- orderBitSize);
}
-#if EC_DEBUG
- mp_todecimal(&r_, mpstr);
- printf("r_: %s (dec)\n", mpstr);
- mp_todecimal(&s_, mpstr);
- printf("s_: %s (dec)\n", mpstr);
- mp_todecimal(&c, mpstr);
- printf("c : %s (dec)\n", mpstr);
- mp_todecimal(&u1, mpstr);
- printf("digest: %s (dec)\n", mpstr);
-#endif
-
CHECK_MPI_OK( mp_mulmod(&u1, &c, &n, &u1) ); /* u1 = u1 * c mod n */
/*
@@ -1016,7 +924,7 @@
** If the result, C, is the point at infinity, reject the signature
*/
/* verification does not support timing mitigation */
- if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC, kmflag, /*timing*/ 0)
+ if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC, kmflag, 1, /*timing*/ 0)
!= SECSuccess) {
rv = SECFailure;
goto cleanup;
@@ -1036,13 +944,6 @@
*/
CHECK_MPI_OK( mp_mod(&x1, &n, &v) );
-#if EC_DEBUG
- mp_todecimal(&r_, mpstr);
- printf("r_: %s (dec)\n", mpstr);
- mp_todecimal(&v, mpstr);
- printf("v : %s (dec)\n", mpstr);
-#endif
-
/*
** ANSI X9.62, Section 5.4.4, Step 3
**
@@ -1055,17 +956,6 @@
rv = SECSuccess; /* Signature verified. */
}
-#if EC_DEBUG
- mp_todecimal(&u1, mpstr);
- printf("u1: %s (dec)\n", mpstr);
- mp_todecimal(&u2, mpstr);
- printf("u2: %s (dec)\n", mpstr);
- mp_tohex(&x1, mpstr);
- printf("x1: %s\n", mpstr);
- mp_todecimal(&v, mpstr);
- printf("v : %s (dec)\n", mpstr);
-#endif
-
cleanup:
mp_clear(&r_);
mp_clear(&s_);
@@ -1082,10 +972,5 @@
rv = SECFailure;
}
-#if EC_DEBUG
- printf("ECDSA verification %s\n",
- (rv == SECSuccess) ? "succeeded" : "failed");
-#endif
-
return rv;
}
diff -r f3630a2d3d5c src/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c Tue Aug 13 14:59:29 2019 +0200
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ec2_aff.c Wed Aug 14 17:34:19 2019 +0200
@@ -331,7 +331,7 @@
* is the point at infinity.
*/
/* timing mitigation is not supported */
- MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt, /*timing*/ 0) );
+ MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt, 0, /*timing*/ 0) );
if (ec_GF2m_pt_is_inf_aff(&pxt, &pyt) != MP_YES) {
res = MP_NO;
goto CLEANUP;
diff -r f3630a2d3d5c src/jdk.crypto.ec/share/native/libsunec/impl/ecl.h
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecl.h Tue Aug 13 14:59:29 2019 +0200
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecl.h Wed Aug 14 17:34:19 2019 +0200
@@ -72,7 +72,7 @@
* are assumed to be NOT field-encoded. */
mp_err ECPoint_mul(const ECGroup *group, const mp_int *k, const mp_int *px,
const mp_int *py, mp_int *qx, mp_int *qy,
- int timing);
+ int reduce, int timing);
/* Elliptic curve scalar-point multiplication. Computes Q(x, y) = k1 * G +
* k2 * P(x, y), where G is the generator (base point) of the group of
@@ -80,7 +80,7 @@
* be NOT field-encoded. */
mp_err ECPoints_mul(const ECGroup *group, const mp_int *k1,
const mp_int *k2, const mp_int *px, const mp_int *py,
- mp_int *qx, mp_int *qy, int timing);
+ mp_int *qx, mp_int *qy, int reduce, int timing);
/* Validates an EC public key as described in Section 5.2.2 of X9.62.
* Returns MP_YES if the public key is valid, MP_NO if the public key
diff -r f3630a2d3d5c src/jdk.crypto.ec/share/native/libsunec/impl/ecl_mult.c
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecl_mult.c Tue Aug 13 14:59:29 2019 +0200
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecl_mult.c Wed Aug 14 17:34:19 2019 +0200
@@ -51,23 +51,23 @@
mp_err
ECPoint_mul(const ECGroup *group, const mp_int *k, const mp_int *px,
const mp_int *py, mp_int *rx, mp_int *ry,
- int timing)
+ int reduce, int timing)
{
mp_err res = MP_OKAY;
mp_int kt;
ARGCHK((k != NULL) && (group != NULL), MP_BADARG);
- MP_DIGITS(&kt) = 0;
+ MP_SIGN(&kt) = MP_ZPOS;
+ MP_USED(&kt) = MP_USED(k);
+ MP_ALLOC(&kt) = MP_ALLOC(k);
+ MP_DIGITS(&kt) = MP_DIGITS(k);
+ if (reduce) {
/* want scalar to be less than or equal to group order */
if (mp_cmp(k, &group->order) > 0) {
MP_CHECKOK(mp_init(&kt, FLAG(k)));
MP_CHECKOK(mp_mod(k, &group->order, &kt));
- } else {
- MP_SIGN(&kt) = MP_ZPOS;
- MP_USED(&kt) = MP_USED(k);
- MP_ALLOC(&kt) = MP_ALLOC(k);
- MP_DIGITS(&kt) = MP_DIGITS(k);
+ }
}
if ((px == NULL) || (py == NULL)) {
@@ -114,24 +114,15 @@
mp_int sx, sy;
ARGCHK(group != NULL, MP_BADARG);
- ARGCHK(!((k1 == NULL)
- && ((k2 == NULL) || (px == NULL)
- || (py == NULL))), MP_BADARG);
-
- /* if some arguments are not defined used ECPoint_mul */
- if (k1 == NULL) {
- return ECPoint_mul(group, k2, px, py, rx, ry, timing);
- } else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
- return ECPoint_mul(group, k1, NULL, NULL, rx, ry, timing);
- }
+ ARGCHK(!((k1 == NULL) || (k2 == NULL) || (px == NULL) || (py == NULL)), MP_BADARG);
MP_DIGITS(&sx) = 0;
MP_DIGITS(&sy) = 0;
MP_CHECKOK(mp_init(&sx, FLAG(k1)));
MP_CHECKOK(mp_init(&sy, FLAG(k1)));
- MP_CHECKOK(ECPoint_mul(group, k1, NULL, NULL, &sx, &sy, timing));
- MP_CHECKOK(ECPoint_mul(group, k2, px, py, rx, ry, timing));
+ MP_CHECKOK(ECPoint_mul(group, k1, NULL, NULL, &sx, &sy, 1, timing));
+ MP_CHECKOK(ECPoint_mul(group, k2, px, py, rx, ry, 1, timing));
if (group->meth->field_enc) {
MP_CHECKOK(group->meth->field_enc(&sx, &sx, group->meth));
@@ -172,16 +163,8 @@
int ai, bi, d;
ARGCHK(group != NULL, MP_BADARG);
- ARGCHK(!((k1 == NULL)
- && ((k2 == NULL) || (px == NULL)
- || (py == NULL))), MP_BADARG);
+ ARGCHK(!((k1 == NULL) || (k2 == NULL) || (px == NULL) || (py == NULL)), MP_BADARG);
- /* if some arguments are not defined used ECPoint_mul */
- if (k1 == NULL) {
- return ECPoint_mul(group, k2, px, py, rx, ry, timing);
- } else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
- return ECPoint_mul(group, k1, NULL, NULL, rx, ry, timing);
- }
/* initialize precomputation table */
for (i = 0; i < 4; i++) {
@@ -313,7 +296,7 @@
mp_err
ECPoints_mul(const ECGroup *group, const mp_int *k1, const mp_int *k2,
const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry,
- int timing)
+ int reduce, int timing)
{
mp_err res = MP_OKAY;
mp_int k1t, k2t;
@@ -324,28 +307,20 @@
ARGCHK(group != NULL, MP_BADARG);
+ k1p = k1;
+ k2p = k2;
+ if (reduce) {
/* want scalar to be less than or equal to group order */
- if (k1 != NULL) {
- if (mp_cmp(k1, &group->order) >= 0) {
+ if (k1 != NULL && mp_cmp(k1, &group->order) >= 0) {
MP_CHECKOK(mp_init(&k1t, FLAG(k1)));
MP_CHECKOK(mp_mod(k1, &group->order, &k1t));
k1p = &k1t;
- } else {
- k1p = k1;
}
- } else {
- k1p = k1;
- }
- if (k2 != NULL) {
- if (mp_cmp(k2, &group->order) >= 0) {
+ if (k2 != NULL && mp_cmp(k2, &group->order) >= 0) {
MP_CHECKOK(mp_init(&k2t, FLAG(k2)));
MP_CHECKOK(mp_mod(k2, &group->order, &k2t));
k2p = &k2t;
- } else {
- k2p = k2;
}
- } else {
- k2p = k2;
}
/* if points_mul is defined, then use it */
diff -r f3630a2d3d5c src/jdk.crypto.ec/share/native/libsunec/impl/ecp_aff.c
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_aff.c Tue Aug 13 14:59:29 2019 +0200
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_aff.c Wed Aug 14 17:34:19 2019 +0200
@@ -342,7 +342,7 @@
* is the point at infinity.
*/
/* timing mitigation is not supported */
- MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt, /*timing*/ 0) );
+ MP_CHECKOK( ECPoint_mul(group, &group->order, px, py, &pxt, &pyt, 0, /*timing*/ 0) );
if (ec_GFp_pt_is_inf_aff(&pxt, &pyt) != MP_YES) {
res = MP_NO;
goto CLEANUP;
diff -r f3630a2d3d5c src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jac.c
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jac.c Tue Aug 13 14:59:29 2019 +0200
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jac.c Wed Aug 14 17:34:19 2019 +0200
@@ -434,16 +434,7 @@
MP_DIGITS(&rz) = 0;
ARGCHK(group != NULL, MP_BADARG);
- ARGCHK(!((k1 == NULL)
- && ((k2 == NULL) || (px == NULL)
- || (py == NULL))), MP_BADARG);
-
- /* if some arguments are not defined used ECPoint_mul */
- if (k1 == NULL) {
- return ECPoint_mul(group, k2, px, py, rx, ry, timing);
- } else if ((k2 == NULL) || (px == NULL) || (py == NULL)) {
- return ECPoint_mul(group, k1, NULL, NULL, rx, ry, timing);
- }
+ ARGCHK(!((k1 == NULL) || (k2 == NULL) || (px == NULL) || (py == NULL)), MP_BADARG);
/* initialize precomputation table */
for (i = 0; i < 4; i++) {
diff -r f3630a2d3d5c src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jm.c
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jm.c Tue Aug 13 14:59:29 2019 +0200
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ecp_jm.c Wed Aug 14 17:34:19 2019 +0200
@@ -232,7 +232,7 @@
mp_int raz4, tpaz4;
mp_int scratch[MAX_SCRATCH];
signed char *naf = NULL;
- int i, orderBitSize;
+ int i, bitSize;
int numDoubles, numAdds, extraDoubles, extraAdds;
MP_DIGITS(&rz) = 0;
@@ -296,13 +296,16 @@
/* R = inf */
MP_CHECKOK(ec_GFp_pt_set_inf_jac(rx, ry, &rz));
- orderBitSize = mpl_significant_bits(&group->order);
+ bitSize = mpl_significant_bits(&group->order);
+ if (mpl_significant_bits(n) > bitSize) {
+ bitSize = mpl_significant_bits(n);
+ }
/* Allocate memory for NAF */
#ifdef _KERNEL
- naf = (signed char *) kmem_alloc((orderBitSize + 1), FLAG(n));
+ naf = (signed char *) kmem_alloc((bitSize + 1), FLAG(n));
#else
- naf = (signed char *) malloc(sizeof(signed char) * (orderBitSize + 1));
+ naf = (signed char *) malloc(sizeof(signed char) * (bitSize + 1));
if (naf == NULL) {
res = MP_MEM;
goto CLEANUP;
@@ -310,12 +313,12 @@
#endif
/* Compute 5NAF */
- ec_compute_wNAF(naf, orderBitSize, n, 5);
+ ec_compute_wNAF(naf, bitSize, n, 5);
numAdds = 0;
- numDoubles = orderBitSize;
+ numDoubles = bitSize;
/* wNAF method */
- for (i = orderBitSize; i >= 0; i--) {
+ for (i = bitSize; i >= 0; i--) {
if (ec_GFp_pt_is_inf_jac(rx, ry, &rz) == MP_YES) {
numDoubles--;
@@ -351,9 +354,9 @@
/* two bits of extra adds */
extraAdds = timing & 0x3;
timing >>= 2;
- /* Window size is 5, so the maximum number of additions is ceil(orderBitSize/5) */
- /* This is the same as (orderBitSize + 4) / 5 */
- for(i = numAdds; i <= (orderBitSize + 4) / 5 + extraAdds; i++) {
+ /* Window size is 5, so the maximum number of additions is ceil(bitSize/5) */
+ /* This is the same as (bitSize + 4) / 5 */
+ for(i = numAdds; i <= (bitSize + 4) / 5 + extraAdds; i++) {
ec_GFp_pt_add_jm_aff(&tpx, &tpy, &tpz, &tpaz4,
&precomp[9 + (i % 3)][0],
&precomp[9 + (i % 3)][1], &tpx, &tpy,
@@ -363,7 +366,7 @@
/* two bits of extra doubles */
extraDoubles = timing & 0x3;
timing >>= 2;
- for(i = numDoubles; i <= orderBitSize + extraDoubles; i++) {
+ for(i = numDoubles; i <= bitSize + extraDoubles; i++) {
ec_GFp_pt_dbl_jm(&tpx, &tpy, &tpz, &tpaz4, &tpx, &tpy, &tpz,
&tpaz4, scratch, group);
}
@@ -388,7 +391,7 @@
mp_clear(&rz);
mp_clear(&raz4);
#ifdef _KERNEL
- kmem_free(naf, (orderBitSize + 1));
+ kmem_free(naf, (bitSize + 1));
#else
free(naf);
#endif
signature.asc
Description: OpenPGP digital signature
