Implement coordinate blinding for EC_POINT
authorSohaib ul Hassan <soh.19.hassan@gmail.com>
Sat, 16 Jun 2018 14:07:40 +0000 (17:07 +0300)
committerNicola Tuveri <nic.tuv@gmail.com>
Tue, 2 Oct 2018 15:12:37 +0000 (18:12 +0300)
This commit implements coordinate blinding, i.e., it randomizes the
representative of an elliptic curve point in its equivalence class, for
prime curves implemented through EC_GFp_simple_method,
EC_GFp_mont_method, and EC_GFp_nist_method.

This commit is derived from the patch
https://marc.info/?l=openssl-dev&m=131194808413635 by Billy Brumley.

Coordinate blinding is a generally useful side-channel countermeasure
and is (mostly) free. The function itself takes a few field
multiplicationss, but is usually only necessary at the beginning of a
scalar multiplication (as implemented in the patch). When used this way,
it makes the values that variables take (i.e., field elements in an
algorithm state) unpredictable.

For instance, this mitigates chosen EC point side-channel attacks for
settings such as ECDH and EC private key decryption, for the
aforementioned curves.

For EC_METHODs using different coordinate representations this commit
does nothing, but the corresponding coordinate blinding function can be
easily added in the future to extend these changes to such curves.

Co-authored-by: Nicola Tuveri <nic.tuv@gmail.com>
Co-authored-by: Billy Brumley <bbrumley@gmail.com>
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Nicola Tuveri <nic.tuv@gmail.com>
Reviewed-by: Andy Polyakov <appro@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/6526)

13 files changed:
CHANGES
crypto/ec/ec2_smpl.c
crypto/ec/ec_err.c
crypto/ec/ec_lcl.h
crypto/ec/ec_lib.c
crypto/ec/ec_mult.c
crypto/ec/ecp_mont.c
crypto/ec/ecp_nist.c
crypto/ec/ecp_nistp224.c
crypto/ec/ecp_nistp521.c
crypto/ec/ecp_nistz256.c
crypto/ec/ecp_smpl.c
include/openssl/ec.h

diff --git a/CHANGES b/CHANGES
index ae8cecaa6a5e2961f33d8c5e6f51901971f9881c..28b9938ebf4fa79ce8cbe8ec9fcf36a64fa652ec 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -9,7 +9,10 @@
 
  Changes between 1.1.0i and 1.1.0j [xx XXX xxxx]
 
-  *)
+  *) Add coordinate blinding for EC_POINT and implement projective
+     coordinate blinding for generic prime curves as a countermeasure to
+     chosen point SCA attacks.
+     [Sohaib ul Hassan, Nicola Tuveri, Billy Bob Brumley]
 
  Changes between 1.1.0h and 1.1.0i [14 Aug 2018]
 
index 28b91d510236841864a60d31e2b53df98957c5d9..cdacce61acf97b473d399e2a619630d51417d8d7 100644 (file)
@@ -83,7 +83,8 @@ const EC_METHOD *EC_GF2m_simple_method(void)
         ec_key_simple_generate_public_key,
         0, /* keycopy */
         0, /* keyfinish */
-        ecdh_simple_compute_key
+        ecdh_simple_compute_key,
+        0  /* blind_coordinates */
     };
 
     return &ret;
index e4c2c1c1a42deabb82f2a7f46d8e95b66c37726e..717c92e984591643a6a78b9750a81b3e3b31a787 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -97,6 +97,8 @@ static ERR_STRING_DATA EC_str_functs[] = {
     {ERR_FUNC(EC_F_EC_GFP_NIST_FIELD_SQR), "ec_GFp_nist_field_sqr"},
     {ERR_FUNC(EC_F_EC_GFP_NIST_GROUP_SET_CURVE),
      "ec_GFp_nist_group_set_curve"},
+    {ERR_FUNC(EC_F_EC_GFP_SIMPLE_BLIND_COORDINATES),
+     "ec_GFp_simple_blind_coordinates"},
     {ERR_FUNC(EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT),
      "ec_GFp_simple_group_check_discriminant"},
     {ERR_FUNC(EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE),
index d8141704cfb19084609d1b97264bab8699d7aa5d..ca1776efdb1f720d6f4a2cccd3ecf9256641383c 100644 (file)
@@ -169,6 +169,7 @@ struct ec_method_st {
     /* custom ECDH operation */
     int (*ecdh_compute_key)(unsigned char **pout, size_t *poutlen,
                             const EC_POINT *pub_key, const EC_KEY *ecdh);
+    int (*blind_coordinates)(const EC_GROUP *group, EC_POINT *p, BN_CTX *ctx);
 };
 
 /*
@@ -375,6 +376,8 @@ int ec_GFp_simple_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
                             const BIGNUM *b, BN_CTX *);
 int ec_GFp_simple_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a,
                             BN_CTX *);
+int ec_GFp_simple_blind_coordinates(const EC_GROUP *group, EC_POINT *p,
+                                    BN_CTX *ctx);
 
 /* method functions in ecp_mont.c */
 int ec_GFp_mont_group_init(EC_GROUP *);
@@ -627,3 +630,5 @@ int X25519(uint8_t out_shared_key[32], const uint8_t private_key[32],
            const uint8_t peer_public_value[32]);
 void X25519_public_from_private(uint8_t out_public_value[32],
                                 const uint8_t private_key[32]);
+
+int ec_point_blind_coordinates(const EC_GROUP *group, EC_POINT *p, BN_CTX *ctx);
index d665556d5788c2d95aca6b434dc4f8664401a2d1..a7be03b627eecdfefadfba96d586863c10f6f9d5 100644 (file)
@@ -1017,3 +1017,21 @@ int ec_group_simple_order_bits(const EC_GROUP *group)
         return 0;
     return BN_num_bits(group->order);
 }
+
+/*-
+ * Coordinate blinding for EC_POINT.
+ *
+ * The underlying EC_METHOD can optionally implement this function:
+ * underlying implementations should return 0 on errors, or 1 on
+ * success.
+ *
+ * This wrapper returns 1 in case the underlying EC_METHOD does not
+ * support coordinate blinding.
+ */
+int ec_point_blind_coordinates(const EC_GROUP *group, EC_POINT *p, BN_CTX *ctx)
+{
+    if (group->meth->blind_coordinates == NULL)
+        return 1; /* ignore if not implemented */
+
+    return group->meth->blind_coordinates(group, p, ctx);
+}
index 71ec910c99b7eb2f76532479b9d76bb28c9c27d8..22bb30ffa1bc824a1c136edab465d296428d7cf9 100644 (file)
@@ -216,6 +216,17 @@ static int ec_mul_consttime(const EC_GROUP *group, EC_POINT *r,
         || (bn_wexpand(r->Z, group_top) == NULL))
         goto err;
 
+    /*-
+     * Apply coordinate blinding for EC_POINT.
+     *
+     * The underlying EC_METHOD can optionally implement this function:
+     * ec_point_blind_coordinates() returns 0 in case of errors or 1 on
+     * success or if coordinate blinding is not implemented for this
+     * group.
+     */
+    if (!ec_point_blind_coordinates(group, s, ctx))
+        goto err;
+
     /* top bit is a 1, in a fixed pos */
     if (!EC_POINT_copy(r, s))
         goto err;
index 994cc1d0fff5f79c59c771f6fd3b43132dca6952..1e0a3e0df88ed3d1ac6701e2bbc85566108b1e24 100644 (file)
@@ -66,7 +66,8 @@ const EC_METHOD *EC_GFp_mont_method(void)
         ec_key_simple_generate_public_key,
         0, /* keycopy */
         0, /* keyfinish */
-        ecdh_simple_compute_key
+        ecdh_simple_compute_key,
+        ec_GFp_simple_blind_coordinates
     };
 
     return &ret;
index 615563bc38e0c9d020c6e84941e498cbcc3a688e..66b88d5ccd26029e5476e160459cc5eef30d3457 100644 (file)
@@ -68,7 +68,8 @@ const EC_METHOD *EC_GFp_nist_method(void)
         ec_key_simple_generate_public_key,
         0, /* keycopy */
         0, /* keyfinish */
-        ecdh_simple_compute_key
+        ecdh_simple_compute_key,
+        ec_GFp_simple_blind_coordinates
     };
 
     return &ret;
index 0cd994fc230e57714b4d608ffef2ee4a74db0734..7dc5309f7184af8dd71b8fe2410c5cd64cb0946c 100644 (file)
@@ -290,7 +290,8 @@ const EC_METHOD *EC_GFp_nistp224_method(void)
         ec_key_simple_generate_public_key,
         0, /* keycopy */
         0, /* keyfinish */
-        ecdh_simple_compute_key
+        ecdh_simple_compute_key,
+        0  /* blind_coordinates */
     };
 
     return &ret;
index 133f089fd2cb638a4c31a6d14dcb6b0056a16738..74d56e333655f6d78fcc0785b29c16959500914b 100644 (file)
@@ -1642,7 +1642,8 @@ const EC_METHOD *EC_GFp_nistp521_method(void)
         ec_key_simple_generate_public_key,
         0, /* keycopy */
         0, /* keyfinish */
-        ecdh_simple_compute_key
+        ecdh_simple_compute_key,
+        0  /* blind_coordinates */
     };
 
     return &ret;
index 4dbe21692721221d95b683ad52f98609b8d8d44d..7eafce649b451798ef734db08b4a90bd4523dd60 100644 (file)
@@ -1536,7 +1536,8 @@ const EC_METHOD *EC_GFp_nistz256_method(void)
         ec_key_simple_generate_public_key,
         0, /* keycopy */
         0, /* keyfinish */
-        ecdh_simple_compute_key
+        ecdh_simple_compute_key,
+        0                                           /* blind_coordinates */
     };
 
     return &ret;
index e3b88315fd47a71da5526488f939645b179ef6bd..2015f1173bf71742a8ef969cffcecce96e261cd4 100644 (file)
@@ -67,7 +67,8 @@ const EC_METHOD *EC_GFp_simple_method(void)
         ec_key_simple_generate_public_key,
         0, /* keycopy */
         0, /* keyfinish */
-        ecdh_simple_compute_key
+        ecdh_simple_compute_key,
+        ec_GFp_simple_blind_coordinates
     };
 
     return &ret;
@@ -1368,3 +1369,57 @@ int ec_GFp_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
 {
     return BN_mod_sqr(r, a, group->field, ctx);
 }
+
+/*-
+ * Apply randomization of EC point projective coordinates:
+ *
+ *   (X, Y ,Z ) = (lambda^2*X, lambda^3*Y, lambda*Z)
+ *   lambda = [1,group->field)
+ *
+ */
+int ec_GFp_simple_blind_coordinates(const EC_GROUP *group, EC_POINT *p,
+                                    BN_CTX *ctx)
+{
+    int ret = 0;
+    BIGNUM *lambda = NULL;
+    BIGNUM *temp = NULL;
+
+    BN_CTX_start(ctx);
+    lambda = BN_CTX_get(ctx);
+    temp = BN_CTX_get(ctx);
+    if (temp == NULL) {
+        ECerr(EC_F_EC_GFP_SIMPLE_BLIND_COORDINATES, ERR_R_MALLOC_FAILURE);
+        goto err;
+    }
+
+    /* make sure lambda is not zero */
+    do {
+        if (!BN_rand_range(lambda, group->field)) {
+            ECerr(EC_F_EC_GFP_SIMPLE_BLIND_COORDINATES, ERR_R_BN_LIB);
+            goto err;
+        }
+    } while (BN_is_zero(lambda));
+
+    /* if field_encode defined convert between representations */
+    if (group->meth->field_encode != NULL
+        && !group->meth->field_encode(group, lambda, lambda, ctx))
+        goto err;
+    if (!group->meth->field_mul(group, p->Z, p->Z, lambda, ctx))
+        goto err;
+    if (!group->meth->field_sqr(group, temp, lambda, ctx))
+        goto err;
+    if (!group->meth->field_mul(group, p->X, p->X, temp, ctx))
+        goto err;
+    if (!group->meth->field_mul(group, temp, temp, lambda, ctx))
+        goto err;
+    if (!group->meth->field_mul(group, p->Y, p->Y, temp, ctx))
+        goto err;
+    p->Z_is_one = 0;
+
+    ret = 1;
+
+ err:
+     BN_CTX_end(ctx);
+     return ret;
+}
+
index f06680a78867e02a9ab5798db9d414c31478f102..9dbc172fb4860fe6b720c2a309edf40a2f31e61c 100644 (file)
@@ -1424,6 +1424,7 @@ int ERR_load_EC_strings(void);
 # define EC_F_EC_GFP_NIST_FIELD_MUL                       200
 # define EC_F_EC_GFP_NIST_FIELD_SQR                       201
 # define EC_F_EC_GFP_NIST_GROUP_SET_CURVE                 202
+# define EC_F_EC_GFP_SIMPLE_BLIND_COORDINATES             287
 # define EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT      165
 # define EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE               166
 # define EC_F_EC_GFP_SIMPLE_MAKE_AFFINE                   102