Skip to content

Commit

Permalink
Curve25519: add blinding when using private key
Browse files Browse the repository at this point in the history
XOR in random value to scalar and perform special scalar multiplication.
  • Loading branch information
SparkiDev committed Jan 29, 2025
1 parent 45b385a commit ce2aaef
Show file tree
Hide file tree
Showing 6 changed files with 248 additions and 20 deletions.
3 changes: 3 additions & 0 deletions tests/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -24923,6 +24923,9 @@ static int test_wc_curve25519_shared_secret_ex(void)
int endian = EC25519_BIG_ENDIAN;

ExpectIntEQ(wc_curve25519_init(&private_key), 0);
#ifdef WOLFSSL_CURVE25519_BLINDING
ExpectIntEQ(wc_curve25519_set_rng(&private_key, &rng), 0);
#endif
ExpectIntEQ(wc_curve25519_init(&public_key), 0);
ExpectIntEQ(wc_InitRng(&rng), 0);

Expand Down
141 changes: 141 additions & 0 deletions wolfcrypt/src/curve25519.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,75 @@ int wc_curve25519_make_pub(int public_size, byte* pub, int private_size,
return ret;
}

#ifdef WOLFSSL_CURVE25519_BLINDING
#ifndef FREESCALE_LTC_ECC
static int curve25519_smul_blind(byte* rp, const byte* n, const byte* p,
WC_RNG* rng)
{
int ret;
byte a[CURVE25519_KEYSIZE];
byte n_a[CURVE25519_KEYSIZE];
int i;

SAVE_VECTOR_REGISTERS(return _svr_ret;);

/* Generate 253 random bits. */
ret = wc_RNG_GenerateBlock(rng, a, sizeof(a));
if (ret != 0)
return ret;
a[CURVE25519_KEYSIZE-1] &= 0x7f;
/* k' = k ^ 2k ^ a */
n_a[0] = n[0] ^ (n[0] << 1) ^ a[0];
for (i = 1; i < CURVE25519_KEYSIZE; i++) {
n_a[i] = n[i] ^ (n[i] << 1) ^ (n[i-1] >> 7) ^ a[i];
}
/* Scalar multiple blinded scalar with blinding value. */
ret = curve25519_blind(rp, n_a, a, p);

RESTORE_VECTOR_REGISTERS();

return ret;
}
#endif

int wc_curve25519_make_pub_blind(int public_size, byte* pub, int private_size,
const byte* priv, WC_RNG* rng)
{
int ret;
#ifdef FREESCALE_LTC_ECC
const ECPoint* basepoint = nxp_ltc_curve25519_GetBasePoint();
ECPoint wc_pub;
#endif

if ( (public_size != CURVE25519_KEYSIZE) ||
(private_size != CURVE25519_KEYSIZE)) {
return ECC_BAD_ARG_E;
}
if ((pub == NULL) || (priv == NULL)) {
return ECC_BAD_ARG_E;
}

/* check clamping */
ret = curve25519_priv_clamp_check(priv);
if (ret != 0)
return ret;

#ifdef FREESCALE_LTC_ECC
/* input basepoint on Weierstrass curve */
ret = nxp_ltc_curve25519(&wc_pub, priv, basepoint, kLTC_Weierstrass);
if (ret == 0) {
XMEMCPY(pub, wc_pub.point, CURVE25519_KEYSIZE);
}
#else
fe_init();

ret = curve25519_smul_blind(pub, priv, (byte*)kCurve25519BasePoint, rng);
#endif

return ret;
}
#endif

/* compute the public key from an existing private key, with supplied basepoint,
* using bare vectors.
*
Expand Down Expand Up @@ -197,6 +266,51 @@ int wc_curve25519_generic(int public_size, byte* pub,
#endif /* FREESCALE_LTC_ECC */
}

#ifdef WOLFSSL_CURVE25519_BLINDING
/* compute the public key from an existing private key, with supplied basepoint,
* using bare vectors.
*
* return value is propagated from curve25519() (0 on success),
* and the byte vectors are little endian.
*/
int wc_curve25519_generic_blind(int public_size, byte* pub,
int private_size, const byte* priv,
int basepoint_size, const byte* basepoint,
WC_RNG* rng)
{
#ifdef FREESCALE_LTC_ECC
/* unsupported with NXP LTC, only supports single basepoint with
* nxp_ltc_curve25519_GetBasePoint() */
return WC_HW_E;
#else
int ret;

if ((public_size != CURVE25519_KEYSIZE) ||
(private_size != CURVE25519_KEYSIZE) ||
(basepoint_size != CURVE25519_KEYSIZE)) {
return ECC_BAD_ARG_E;
}
if ((pub == NULL) || (priv == NULL) || (basepoint == NULL))
return ECC_BAD_ARG_E;

/* check clamping */
ret = curve25519_priv_clamp_check(priv);
if (ret != 0)
return ret;

fe_init();

SAVE_VECTOR_REGISTERS(return _svr_ret;);

ret = curve25519_smul_blind(pub, priv, basepoint, rng);

RESTORE_VECTOR_REGISTERS();

return ret;
#endif /* FREESCALE_LTC_ECC */
}
#endif

/* generate a new private key, as a bare vector.
*
* return value is propagated from wc_RNG_GenerateBlock(() (0 on success),
Expand Down Expand Up @@ -250,8 +364,14 @@ int wc_curve25519_make_key(WC_RNG* rng, int keysize, curve25519_key* key)
ret = wc_curve25519_make_priv(rng, keysize, key->k);
if (ret == 0) {
key->privSet = 1;
#ifdef WOLFSSL_CURVE25519_BLINDING
ret = wc_curve25519_make_pub_blind((int)sizeof(key->p.point),
key->p.point, (int)sizeof(key->k),
key->k, rng);
#else
ret = wc_curve25519_make_pub((int)sizeof(key->p.point), key->p.point,
(int)sizeof(key->k), key->k);
#endif
key->pubSet = (ret == 0);
}
#endif
Expand Down Expand Up @@ -322,7 +442,12 @@ int wc_curve25519_shared_secret_ex(curve25519_key* private_key,
{
SAVE_VECTOR_REGISTERS(return _svr_ret;);

#ifndef WOLFSSL_CURVE25519_BLINDING
ret = curve25519(o.point, private_key->k, public_key->p.point);
#else
ret = curve25519_smul_blind(o.point, private_key->k, public_key->p.point,
private_key->rng);
#endif

RESTORE_VECTOR_REGISTERS();
}
Expand Down Expand Up @@ -379,8 +504,14 @@ int wc_curve25519_export_public_ex(curve25519_key* key, byte* out,

/* calculate public if missing */
if (!key->pubSet) {
#ifdef WOLFSSL_CURVE25519_BLINDING
ret = wc_curve25519_make_pub_blind((int)sizeof(key->p.point),
key->p.point, (int)sizeof(key->k),
key->k, key->rng);
#else
ret = wc_curve25519_make_pub((int)sizeof(key->p.point), key->p.point,
(int)sizeof(key->k), key->k);
#endif
key->pubSet = (ret == 0);
}
/* export public point with endianness */
Expand Down Expand Up @@ -739,6 +870,16 @@ void wc_curve25519_free(curve25519_key* key)
#endif
}

#ifdef WOLFSSL_CURVE25519_BLINDING
int wc_curve25519_set_rng(curve25519_key* key, WC_RNG* rng)
{
if (key == NULL)
return BAD_FUNC_ARG;
key->rng = rng;
return 0;
}
#endif

/* get key size */
int wc_curve25519_size(curve25519_key* key)
{
Expand Down
85 changes: 67 additions & 18 deletions wolfcrypt/src/fe_operations.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,6 @@ void fe_init(void)
!defined(FREESCALE_LTC_ECC)
int curve25519(byte* q, const byte* n, const byte* p)
{
#if 0
unsigned char e[32];
#endif
fe x1 = {0};
fe x2 = {0};
fe z2 = {0};
Expand All @@ -143,17 +140,6 @@ int curve25519(byte* q, const byte* n, const byte* p)
int pos = 0;
unsigned int swap = 0;

/* Clamp already done during key generation and import */
#if 0
{
unsigned int i;
for (i = 0;i < 32;++i) e[i] = n[i];
e[0] &= 248;
e[31] &= 127;
e[31] |= 64;
}
#endif

fe_frombytes(x1,p);
fe_1(x2);
fe_0(z2);
Expand All @@ -163,11 +149,7 @@ int curve25519(byte* q, const byte* n, const byte* p)
swap = 0;
for (pos = 254;pos >= 0;--pos) {
unsigned int b;
#if 0
b = e[pos / 8] >> (pos & 7);
#else
b = n[pos / 8] >> (pos & 7);
#endif
b &= 1;
swap ^= b;
fe_cswap(x2,x3,(int)swap);
Expand Down Expand Up @@ -203,6 +185,73 @@ int curve25519(byte* q, const byte* n, const byte* p)

return 0;
}

#ifdef WOLFSSL_CURVE25519_BLINDING
int curve25519_blind(byte* q, const byte* n, const byte* mask, const byte* p)
{
fe x1 = {0};
fe x2 = {0};
fe z2 = {0};
fe x3 = {0};
fe z3 = {0};
fe tmp0 = {0};
fe tmp1 = {0};
int pos = 0;
unsigned int b;

fe_frombytes(x1,p);
fe_1(x2);
fe_0(z2);
fe_copy(x3,x1);
fe_1(z3);

/* mask_bits[252] */
b = mask[31] >> 7;
b &= 1;
fe_cswap(x2,x3,(int)b);
fe_cswap(z2,z3,(int)b);
for (pos = 255;pos >= 1;--pos) {
b = n[pos / 8] >> (pos & 7);
b &= 1;
fe_cswap(x2,x3,(int)b);
fe_cswap(z2,z3,(int)b);

/* montgomery */
fe_sub(tmp0,x3,z3);
fe_sub(tmp1,x2,z2);
fe_add(x2,x2,z2);
fe_add(z2,x3,z3);
fe_mul(z3,tmp0,x2);
fe_mul(z2,z2,tmp1);
fe_sq(tmp0,tmp1);
fe_sq(tmp1,x2);
fe_add(x3,z3,z2);
fe_sub(z2,z3,z2);
fe_mul(x2,tmp1,tmp0);
fe_sub(tmp1,tmp1,tmp0);
fe_sq(z2,z2);
fe_mul121666(z3,tmp1);
fe_sq(x3,x3);
fe_add(tmp0,tmp0,z3);
fe_mul(z3,x1,z2);
fe_mul(z2,tmp1,tmp0);

b = mask[(pos-1) / 8] >> ((pos-1) & 7);
b &= 1;
fe_cswap(x2,x3,(int)b);
fe_cswap(z2,z3,(int)b);
}
b = n[0] & 1;
fe_cswap(x2,x3,(int)b);
fe_cswap(z2,z3,(int)b);

fe_invert(z2,z2);
fe_mul(x2,x2,z2);
fe_tobytes(q,x2);

return 0;
}
#endif
#endif /* HAVE_CURVE25519 && !CURVE25519_SMALL && !FREESCALE_LTC_ECC */


Expand Down
15 changes: 13 additions & 2 deletions wolfcrypt/test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -34706,7 +34706,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ecc_test_buffers(void)
#else
#define X25519_TEST_CNT 1
#endif
static wc_test_ret_t curve25519_overflow_test(void)
static wc_test_ret_t curve25519_overflow_test(WC_RNG* rng)
{
/* secret key for party a */
byte sa[X25519_TEST_CNT][32] = {
Expand Down Expand Up @@ -34824,6 +34824,10 @@ static wc_test_ret_t curve25519_overflow_test(void)
curve25519_key userA;

wc_curve25519_init_ex(&userA, HEAP_HINT, devId);
#ifdef WOLFSSL_CURVE25519_BLINDING
wc_curve25519_set_rng(&userA, rng);
#endif
(void)rng;

for (i = 0; i < X25519_TEST_CNT; i++) {
if (wc_curve25519_import_private_raw(sa[i], sizeof(sa[i]), pb[i],
Expand Down Expand Up @@ -35302,6 +35306,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t curve25519_test(void)
wc_curve25519_init_ex(userB, HEAP_HINT, devId);
wc_curve25519_init_ex(pubKey, HEAP_HINT, devId);
#endif
#ifdef WOLFSSL_CURVE25519_BLINDING
wc_curve25519_set_rng(userA, &rng);
wc_curve25519_set_rng(userB, &rng);
#endif

/* make curve25519 keys */
ret = wc_curve25519_make_key(&rng, 32, userA);
Expand Down Expand Up @@ -35399,6 +35407,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t curve25519_test(void)

wc_curve25519_free(userB);
wc_curve25519_init_ex(userB, HEAP_HINT, devId);
#ifdef WOLFSSL_CURVE25519_BLINDING
wc_curve25519_set_rng(userB, &rng);
#endif

ret = wc_curve25519_make_key(&rng, 32, userB);
if (ret != 0)
Expand All @@ -35421,7 +35432,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t curve25519_test(void)
if (XMEMCMP(sharedA, sharedB, x))
ERROR_OUT(WC_TEST_RET_ENC_NC, cleanup);

ret = curve25519_overflow_test();
ret = curve25519_overflow_test(&rng);
if (ret != 0)
goto cleanup;
ret = curve25519_check_public_test();
Expand Down
Loading

0 comments on commit ce2aaef

Please sign in to comment.