diff options
author | jsing <> | 2025-08-03 15:44:00 +0000 |
---|---|---|
committer | jsing <> | 2025-08-03 15:44:00 +0000 |
commit | fc8be960288820947950f2a89a6dfaa165995605 (patch) | |
tree | 0883803e254aa25ae2a1d2f5d4b64a3b1352d9c1 /src | |
parent | b808ee87049b240dc3459eb95aed3179e2968511 (diff) | |
download | openbsd-fc8be960288820947950f2a89a6dfaa165995605.tar.gz openbsd-fc8be960288820947950f2a89a6dfaa165995605.tar.bz2 openbsd-fc8be960288820947950f2a89a6dfaa165995605.zip |
Implement constant time EC scalar multiplication.
Replace simplistic non-constant time scalar multiplication with a constant
time version. This is actually faster since we compute multiples of the
point, then double four times and add once. The multiple to add is selected
conditionally, ensuring that the access patterns remain the same regardless
of value.
Inspired by Go's scalar multiplication code.
ok tb@
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/libcrypto/ec/ecp_hp_methods.c | 119 |
1 files changed, 103 insertions, 16 deletions
diff --git a/src/lib/libcrypto/ec/ecp_hp_methods.c b/src/lib/libcrypto/ec/ecp_hp_methods.c index bd414f49aa..0b34a55b9d 100644 --- a/src/lib/libcrypto/ec/ecp_hp_methods.c +++ b/src/lib/libcrypto/ec/ecp_hp_methods.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ecp_hp_methods.c,v 1.4 2025/08/03 15:08:28 jsing Exp $ */ | 1 | /* $OpenBSD: ecp_hp_methods.c,v 1.5 2025/08/03 15:44:00 jsing Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2024-2025 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2024-2025 Joel Sing <jsing@openbsd.org> |
4 | * | 4 | * |
@@ -22,15 +22,11 @@ | |||
22 | #include <openssl/err.h> | 22 | #include <openssl/err.h> |
23 | 23 | ||
24 | #include "bn_internal.h" | 24 | #include "bn_internal.h" |
25 | #include "crypto_internal.h" | ||
25 | #include "ec_local.h" | 26 | #include "ec_local.h" |
26 | #include "ec_internal.h" | 27 | #include "ec_internal.h" |
27 | #include "err_local.h" | 28 | #include "err_local.h" |
28 | 29 | ||
29 | /* | ||
30 | * TODO: | ||
31 | * - Constant time and blinding for scalar multiplication | ||
32 | */ | ||
33 | |||
34 | static int | 30 | static int |
35 | ec_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, | 31 | ec_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, |
36 | const BIGNUM *b, BN_CTX *ctx) | 32 | const BIGNUM *b, BN_CTX *ctx) |
@@ -781,38 +777,129 @@ ec_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], | |||
781 | } | 777 | } |
782 | #endif | 778 | #endif |
783 | 779 | ||
780 | static void | ||
781 | ec_point_select(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, | ||
782 | const EC_POINT *b, int conditional) | ||
783 | { | ||
784 | ec_field_element_select(&group->fm, &r->fe_x, &a->fe_x, &b->fe_x, conditional); | ||
785 | ec_field_element_select(&group->fm, &r->fe_y, &a->fe_y, &b->fe_y, conditional); | ||
786 | ec_field_element_select(&group->fm, &r->fe_z, &a->fe_z, &b->fe_z, conditional); | ||
787 | } | ||
788 | |||
784 | static int | 789 | static int |
785 | ec_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, const EC_POINT *point, | 790 | ec_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, const EC_POINT *point, |
786 | BN_CTX *ctx) | 791 | BN_CTX *ctx) |
787 | { | 792 | { |
788 | EC_POINT *rr; | 793 | BIGNUM *cardinality; |
789 | int bits, i; | 794 | EC_POINT *multiples[15]; |
795 | EC_POINT *rr = NULL, *t = NULL; | ||
796 | uint8_t *scalar_bytes = NULL; | ||
797 | int scalar_len = 0; | ||
798 | uint8_t j, wv; | ||
799 | int conditional, i; | ||
790 | int ret = 0; | 800 | int ret = 0; |
791 | 801 | ||
792 | /* XXX - need constant time and blinding. */ | 802 | memset(multiples, 0, sizeof(multiples)); |
803 | |||
804 | BN_CTX_start(ctx); | ||
805 | |||
806 | /* XXX - consider blinding. */ | ||
807 | |||
808 | if ((cardinality = BN_CTX_get(ctx)) == NULL) | ||
809 | goto err; | ||
810 | if (!BN_mul(cardinality, group->order, group->cofactor, ctx)) | ||
811 | goto err; | ||
812 | |||
813 | /* XXX - handle scalar > cardinality and/or negative. */ | ||
814 | |||
815 | /* Convert scalar into big endian bytes. */ | ||
816 | scalar_len = BN_num_bytes(cardinality); | ||
817 | if ((scalar_bytes = calloc(1, scalar_len)) == NULL) | ||
818 | goto err; | ||
819 | if (!BN_bn2binpad(scalar, scalar_bytes, scalar_len)) | ||
820 | goto err; | ||
821 | |||
822 | /* Compute multiples of point. */ | ||
823 | if ((multiples[0] = EC_POINT_dup(point, group)) == NULL) | ||
824 | goto err; | ||
825 | for (i = 1; i < 15; i += 2) { | ||
826 | if ((multiples[i] = EC_POINT_new(group)) == NULL) | ||
827 | goto err; | ||
828 | if (!EC_POINT_dbl(group, multiples[i], multiples[i / 2], ctx)) | ||
829 | goto err; | ||
830 | if ((multiples[i + 1] = EC_POINT_new(group)) == NULL) | ||
831 | goto err; | ||
832 | if (!EC_POINT_add(group, multiples[i + 1], multiples[i], point, ctx)) | ||
833 | goto err; | ||
834 | } | ||
793 | 835 | ||
794 | if ((rr = EC_POINT_new(group)) == NULL) | 836 | if ((rr = EC_POINT_new(group)) == NULL) |
795 | goto err; | 837 | goto err; |
838 | if ((t = EC_POINT_new(group)) == NULL) | ||
839 | goto err; | ||
796 | 840 | ||
797 | bits = BN_num_bits(scalar); | 841 | if (!EC_POINT_set_to_infinity(group, rr)) |
842 | goto err; | ||
798 | 843 | ||
799 | EC_POINT_copy(rr, point); | 844 | for (i = 0; i < scalar_len; i++) { |
845 | if (i != 0) { | ||
846 | if (!EC_POINT_dbl(group, rr, rr, ctx)) | ||
847 | goto err; | ||
848 | if (!EC_POINT_dbl(group, rr, rr, ctx)) | ||
849 | goto err; | ||
850 | if (!EC_POINT_dbl(group, rr, rr, ctx)) | ||
851 | goto err; | ||
852 | if (!EC_POINT_dbl(group, rr, rr, ctx)) | ||
853 | goto err; | ||
854 | } | ||
855 | |||
856 | if (!EC_POINT_set_to_infinity(group, t)) | ||
857 | goto err; | ||
858 | |||
859 | wv = scalar_bytes[i] >> 4; | ||
860 | for (j = 1; j < 16; j++) { | ||
861 | conditional = crypto_ct_eq_u8(j, wv); | ||
862 | ec_point_select(group, t, t, multiples[j - 1], conditional); | ||
863 | } | ||
864 | if (!EC_POINT_add(group, rr, rr, t, ctx)) | ||
865 | goto err; | ||
800 | 866 | ||
801 | for (i = bits - 2; i >= 0; i--) { | ||
802 | if (!EC_POINT_dbl(group, rr, rr, ctx)) | 867 | if (!EC_POINT_dbl(group, rr, rr, ctx)) |
803 | goto err; | 868 | goto err; |
804 | if (BN_is_bit_set(scalar, i)) { | 869 | if (!EC_POINT_dbl(group, rr, rr, ctx)) |
805 | if (!EC_POINT_add(group, rr, rr, point, ctx)) | 870 | goto err; |
806 | goto err; | 871 | if (!EC_POINT_dbl(group, rr, rr, ctx)) |
872 | goto err; | ||
873 | if (!EC_POINT_dbl(group, rr, rr, ctx)) | ||
874 | goto err; | ||
875 | |||
876 | if (!EC_POINT_set_to_infinity(group, t)) | ||
877 | goto err; | ||
878 | |||
879 | wv = scalar_bytes[i] & 0xf; | ||
880 | for (j = 1; j < 16; j++) { | ||
881 | conditional = crypto_ct_eq_u8(j, wv); | ||
882 | ec_point_select(group, t, t, multiples[j - 1], conditional); | ||
807 | } | 883 | } |
884 | if (!EC_POINT_add(group, rr, rr, t, ctx)) | ||
885 | goto err; | ||
808 | } | 886 | } |
809 | 887 | ||
810 | EC_POINT_copy(r, rr); | 888 | if (!EC_POINT_copy(r, rr)) |
889 | goto err; | ||
811 | 890 | ||
812 | ret = 1; | 891 | ret = 1; |
813 | 892 | ||
814 | err: | 893 | err: |
894 | for (i = 0; i < 15; i++) | ||
895 | EC_POINT_free(multiples[i]); | ||
896 | |||
815 | EC_POINT_free(rr); | 897 | EC_POINT_free(rr); |
898 | EC_POINT_free(t); | ||
899 | |||
900 | freezero(scalar_bytes, scalar_len); | ||
901 | |||
902 | BN_CTX_end(ctx); | ||
816 | 903 | ||
817 | return ret; | 904 | return ret; |
818 | } | 905 | } |