Skip to content

Commit

Permalink
Implement blinding for EC scalar multiplication
Browse files Browse the repository at this point in the history
This commit implements coordinate blinding for the generic
implementations of both binary and prime elliptic curves in 1.0.2, to
avoid leaking bits of the scalar and, potentially, bug attacks.

While blinding is implemented in the 1.1.1 and master branches, it was
deliberately decided to avoid backporting those changes as they were
originally written for the newer branches, as the solution adopted there
required major restructuring of code and structures that was deemed not
suitable for 1.0.2.

A group of security researchers and cryptographers from academia and
industry, listed below, reported a successful cache timing attack
in OpenSSL 1.0.2u against specific prime and binary curves whose order
or field length is close to a word boundary.

In this commit, as a possible fix, the authors propose implementing
coordinate randomization to balance the two possibilities for the key
bit in the first loop iteration of the Montgomery ladder. This way, the
Z coordinates of both accumulator points will be non-trivial and the
multiplication latency will be similar, with a tiny performance penalty.

The original GitHub Pull Request openssl#11361 includes more details about the
reported attack, literature references and discussions on how the
originally proposed fix was incrementally edited to reflect the relevant
details of the 1.1.1 and master branches regarding coordinate blinding.

The authors of the original report and fix are Diego F. Aranha and
Akira Takahashi (both from Aarhus University), Mehdi Tibouchi (NTT
Corporation) and Yuval Yarom (University of Adelaide).

Co-authored-by: Akira Takahashi <takahashi@cs.au.dk>
Co-authored-by: Mehdi Tibouchi <tibouchi.mehdi@lab.ntt.co.jp>
Co-authored-by: Yuval Yarom <yval@cs.adelaide.edu.au>
  • Loading branch information
4 people authored and romen committed Apr 24, 2020
1 parent 12ad22d commit 0548c88
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 8 deletions.
1 change: 1 addition & 0 deletions crypto/ec/ec.h
Expand Up @@ -1182,6 +1182,7 @@ void ERR_load_EC_strings(void);
# define EC_F_EC_KEY_PRINT 180
# define EC_F_EC_KEY_PRINT_FP 181
# define EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES 229
# define EC_F_EC_MUL_CONSTTIME 246
# define EC_F_EC_POINTS_MAKE_AFFINE 136
# define EC_F_EC_POINT_ADD 112
# define EC_F_EC_POINT_CMP 113
Expand Down
34 changes: 30 additions & 4 deletions crypto/ec/ec2_mult.c
Expand Up @@ -315,6 +315,34 @@ static int ec_GF2m_montgomery_point_multiply(const EC_GROUP *group,
if (!BN_GF2m_add(x2, x2, &group->b))
goto err; /* x2 = x^4 + b */

/* blinding: make sure z1 and z2 are independently blinded. */
do {
if (!BN_rand(z1, BN_num_bits(&group->field) - 1, -1, 0)) {
ECerr(EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY, ERR_R_BN_LIB);
return 0;
}
} while (BN_is_zero(z1));

/* first blind (x2,z2) using z1 as the random field element. */
if ((group->meth->field_encode != NULL
&& !group->meth->field_encode(group, z1, z1, ctx))
|| !group->meth->field_mul(group, x2, x2, z1, ctx)
|| !group->meth->field_mul(group, z2, z2, z1, ctx))
return 0;

/* now generate another random field element to blind (x1,z1) */
do {
if (!BN_rand(z1, BN_num_bits(&group->field) - 1, -1, 0)) {
ECerr(EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY, ERR_R_BN_LIB);
return 0;
}
} while (BN_is_zero(z1));

if ((group->meth->field_encode != NULL
&& !group->meth->field_encode(group, z1, z1, ctx))
|| !group->meth->field_mul(group, x1, x1, z1, ctx))
return 0;

/* find top most bit and go one past it */
i = scalar->top - 1;
mask = BN_TBIT;
Expand Down Expand Up @@ -393,11 +421,9 @@ int ec_GF2m_simple_mul(const EC_GROUP *group, EC_POINT *r,
/*
* This implementation is more efficient than the wNAF implementation for
* 2 or fewer points. Use the ec_wNAF_mul implementation for 3 or more
* points, or if we can perform a fast multiplication based on
* precomputation.
* points.
*/
if ((scalar && (num > 1)) || (num > 2)
|| (num == 0 && EC_GROUP_have_precompute_mult(group))) {
if ((scalar && (num > 1)) || (num > 2)) {
ret = ec_wNAF_mul(group, r, scalar, num, points, scalars, ctx);
goto err;
}
Expand Down
3 changes: 2 additions & 1 deletion crypto/ec/ec_err.c
@@ -1,6 +1,6 @@
/* crypto/ec/ec_err.c */
/* ====================================================================
* Copyright (c) 1999-2019 The OpenSSL Project. All rights reserved.
* Copyright (c) 1999-2020 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
Expand Down Expand Up @@ -205,6 +205,7 @@ static ERR_STRING_DATA EC_str_functs[] = {
{ERR_FUNC(EC_F_EC_KEY_PRINT_FP), "EC_KEY_print_fp"},
{ERR_FUNC(EC_F_EC_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES),
"EC_KEY_set_public_key_affine_coordinates"},
{ERR_FUNC(EC_F_EC_MUL_CONSTTIME), "EC_MUL_CONSTTIME"},
{ERR_FUNC(EC_F_EC_POINTS_MAKE_AFFINE), "EC_POINTs_make_affine"},
{ERR_FUNC(EC_F_EC_POINT_ADD), "EC_POINT_add"},
{ERR_FUNC(EC_F_EC_POINT_CMP), "EC_POINT_cmp"},
Expand Down
77 changes: 74 additions & 3 deletions crypto/ec/ec_mult.c
Expand Up @@ -421,9 +421,80 @@ static int ec_mul_consttime(const EC_GROUP *group, EC_POINT *r,
|| (bn_wexpand(&r->Z, group_top) == NULL))
goto err;

/* top bit is a 1, in a fixed pos */
if (!EC_POINT_copy(r, s))
goto err;
if (group->meth->field_type == NID_X9_62_prime_field) {
/*
* Apply blinding independently to r and s: use point r as temporary
* variable.
*
* Blinding requires using a projective representation, and later we
* implement the ladder step using EC_POINT_add() and EC_POINT_dbl():
* this requires EC_METHODs that support projective coordinates in their
* point addition and point doubling implementations.
*
* All the built-in EC_METHODs for prime curves at the moment satisfy
* this condition, while the EC_METHOD for binary curves does not.
*
* This is why we check for a prime field to apply blinding.
*/

/* first randomize r->Z to blind s. */
do {
if (!BN_rand_range(&r->Z, &group->field)) {
ECerr(EC_F_EC_MUL_CONSTTIME, ERR_R_BN_LIB);
goto err;
}
} while (BN_is_zero(&r->Z));

/* convert r->Z to the correct field representation. */
if (group->meth->field_encode != NULL
&& !group->meth->field_encode(group, &r->Z, &r->Z, ctx)) {
goto err;
}

/* scale s->X and s->Y by r->Z^2 and r->Z^3, respectively. */
if (!group->meth->field_sqr(group, &r->X, &r->Z, ctx)
|| !group->meth->field_mul(group, &r->Y, &r->X, &r->Z, ctx)) {
goto err;
}
if (!group->meth->field_mul(group, &s->X, &s->X, &r->X, ctx)
|| !group->meth->field_mul(group, &s->Y, &s->Y, &r->Y, ctx)
|| !group->meth->field_mul(group, &s->Z, &s->Z, &r->Z, ctx)) {
goto err;
}
/* mark the flag in s to full projective coordinates. */
s->Z_is_one = 0;

/* blinding: now rerandomize r->Z to make r a blinded copy of s. */
do {
if (!BN_rand_range(&r->Z, &group->field)) {
ECerr(EC_F_EC_MUL_CONSTTIME, ERR_R_BN_LIB);
goto err;
}
} while (BN_is_zero(&r->Z));

/* convert r->Z to the correct field representation. */
if (group->meth->field_encode != NULL
&& !group->meth->field_encode(group, &r->Z, &r->Z, ctx)) {
goto err;
}

/* scale r->X and r->Y by r->Z^2 and r->Z^3, respectively. */
if (!group->meth->field_sqr(group, &r->X, &r->Z, ctx)
|| !group->meth->field_mul(group, &r->Y, &r->X, &r->Z, ctx)) {
goto err;
}
if (!group->meth->field_mul(group, &r->X, &s->X, &r->X, ctx)
|| !group->meth->field_mul(group, &r->Y, &s->Y, &r->Y, ctx)
|| !group->meth->field_mul(group, &r->Z, &s->Z, &r->Z, ctx)) {
goto err;
}
/* mark the flag in s to full projective coordinates. */
r->Z_is_one = 0;
} else {
/* top bit is a 1, in a fixed pos; binary curves are not blinded here */
if (!EC_POINT_copy(r, s))
goto err;
}

EC_POINT_BN_set_flags(r, BN_FLG_CONSTTIME);

Expand Down

0 comments on commit 0548c88

Please sign in to comment.