From 9c165791b68a204678b48ec11e4e579754c2ea49 Mon Sep 17 00:00:00 2001 From: Alexander Scheel Date: Wed, 13 Mar 2024 15:15:58 -0400 Subject: [PATCH] Fix for EdDSA verification infinite loop Resolves: https://github.com/bcgit/bc-java/issues/1599 Signed-off-by: Alexander Scheel --- .../math/ec/rfc8032/Scalar25519.java | 5 +- .../math/ec/rfc8032/Scalar448.java | 5 +- .../math/ec/rfc8032/ScalarUtil.java | 208 +++++++++++++----- 3 files changed, 164 insertions(+), 54 deletions(-) diff --git a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar25519.java b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar25519.java index 8018ad4f1c..a760625798 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar25519.java +++ b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar25519.java @@ -306,6 +306,7 @@ static void reduceBasisVar(int[] k, int[] z0, int[] z1) int[] Nu = new int[16]; System.arraycopy(LSq, 0, Nu, 0, 16); int[] Nv = new int[16]; Nat256.square(k, Nv); ++Nv[0]; int[] p = new int[16]; Nat256.mul(L, k, p); + int[] t = new int[16]; // temp array int[] u0 = new int[4]; System.arraycopy(L, 0, u0, 0, 4); int[] u1 = new int[4]; int[] v0 = new int[4]; System.arraycopy(k, 0, v0, 0, 4); @@ -322,12 +323,12 @@ static void reduceBasisVar(int[] k, int[] z0, int[] z1) if (p[last] < 0) { - ScalarUtil.addShifted_NP(last, s, Nu, Nv, p); + ScalarUtil.addShifted_NP(last, s, Nu, Nv, p, t); ScalarUtil.addShifted_UV(3, s, u0, u1, v0, v1); } else { - ScalarUtil.subShifted_NP(last, s, Nu, Nv, p); + ScalarUtil.subShifted_NP(last, s, Nu, Nv, p, t); ScalarUtil.subShifted_UV(3, s, u0, u1, v0, v1); } diff --git a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar448.java b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar448.java index 5272e4eba2..edac5c02da 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar448.java +++ b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar448.java @@ -571,6 +571,7 @@ static void reduceBasisVar(int[] k, int[] z0, int[] z1) int[] Nu = new int[28]; System.arraycopy(LSq, 0, Nu, 0, 28); int[] Nv = new int[28]; Nat448.square(k, Nv); ++Nv[0]; int[] p = new int[28]; Nat448.mul(L, k, p); + int[] t = new int[28]; // temp array int[] u0 = new int[8]; System.arraycopy(L, 0, u0, 0, 8); int[] u1 = new int[8]; int[] v0 = new int[8]; System.arraycopy(k, 0, v0, 0, 8); @@ -587,12 +588,12 @@ static void reduceBasisVar(int[] k, int[] z0, int[] z1) if (p[last] < 0) { - ScalarUtil.addShifted_NP(last, s, Nu, Nv, p); + ScalarUtil.addShifted_NP(last, s, Nu, Nv, p, t); ScalarUtil.addShifted_UV(7, s, u0, u1, v0, v1); } else { - ScalarUtil.subShifted_NP(last, s, Nu, Nv, p); + ScalarUtil.subShifted_NP(last, s, Nu, Nv, p, t); ScalarUtil.subShifted_UV(7, s, u0, u1, v0, v1); } diff --git a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/ScalarUtil.java b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/ScalarUtil.java index 81d8fd9638..100fd485e7 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/ScalarUtil.java +++ b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/ScalarUtil.java @@ -6,57 +6,111 @@ abstract class ScalarUtil { private static final long M = 0xFFFFFFFFL; - static void addShifted_NP(int last, int s, int[] Nu, int[] Nv, int[] _p) + static void addShifted_NP(int last, int s, int[] Nu, int[] Nv, int[] p, int[] t) { - int sWords = s >>> 5, sBits = s & 31; - - long cc__p = 0L; + long cc_p = 0L; long cc_Nu = 0L; - if (sBits == 0) + if (s == 0) { - for (int i = sWords; i <= last; ++i) + for (int i = 0; i <= last; ++i) { + int p_i = p[i]; + cc_Nu += Nu[i] & M; - cc_Nu += _p[i - sWords] & M; + cc_Nu += p_i & M; - cc__p += _p[i] & M; - cc__p += Nv[i - sWords] & M; - _p[i] = (int)cc__p; cc__p >>>= 32; + cc_p += p_i & M; + cc_p += Nv[i] & M; + p_i = (int)cc_p; cc_p >>= 32; + p[i] = p_i; - cc_Nu += _p[i - sWords] & M; - Nu[i] = (int)cc_Nu; cc_Nu >>>= 32; + cc_Nu += p_i & M; + Nu[i] = (int)cc_Nu; cc_Nu >>= 32; } } - else + else if (s < 32) { int prev_p = 0; int prev_q = 0; int prev_v = 0; - for (int i = sWords; i <= last; ++i) + for (int i = 0; i <= last; ++i) { - int next_p = _p[i - sWords]; - int p_s = (next_p << sBits) | (prev_p >>> -sBits); - prev_p = next_p; + int p_i = p[i]; + int p_s = (p_i << s) | (prev_p >>> -s); + prev_p = p_i; cc_Nu += Nu[i] & M; cc_Nu += p_s & M; - int next_v = Nv[i - sWords]; - int v_s = (next_v << sBits) | (prev_v >>> -sBits); + int next_v = Nv[i]; + int v_s = (next_v << s) | (prev_v >>> -s); prev_v = next_v; - cc__p += _p[i] & M; - cc__p += v_s & M; - _p[i] = (int)cc__p; cc__p >>>= 32; + cc_p += p_i & M; + cc_p += v_s & M; + p_i = (int)cc_p; cc_p >>= 32; + p[i] = p_i; - int next_q = _p[i - sWords]; - int q_s = (next_q << sBits) | (prev_q >>> -sBits); - prev_q = next_q; + int q_s = (p_i << s) | (prev_q >>> -s); + prev_q =p_i; cc_Nu += q_s & M; - Nu[i] = (int)cc_Nu; cc_Nu >>>= 32; + Nu[i] = (int)cc_Nu; cc_Nu >>= 32; + } + } + else + { + // Keep the original value of p in t. + System.arraycopy(p, 0, t, 0, p.length); + + int sWords = s >>> 5; int sBits = s & 31; + if (sBits == 0) + { + for (int i = sWords; i <= last; ++i) + { + cc_Nu += Nu[i] & M; + cc_Nu += t[i - sWords] & M; + + cc_p += p[i] & M; + cc_p += Nv[i - sWords] & M; + p[i] = (int)cc_p; cc_p >>= 32; + + cc_Nu += p[i - sWords] & M; + Nu[i] = (int)cc_Nu; cc_Nu >>= 32; + } + } + else + { + int prev_t = 0; + int prev_q = 0; + int prev_v = 0; + + for (int i = sWords; i <= last; ++i) + { + int next_t = t[i - sWords]; + int t_s = (next_t << sBits) | (prev_t >>> -sBits); + prev_t = next_t; + + cc_Nu += Nu[i] & M; + cc_Nu += t_s & M; + + int next_v = Nv[i - sWords]; + int v_s = (next_v << sBits) | (prev_v >>> -sBits); + prev_v = next_v; + + cc_p += p[i] & M; + cc_p += v_s & M; + p[i] = (int)cc_p; cc_p >>= 32; + + int next_q = p[i - sWords]; + int q_s = (next_q << sBits) | (prev_q >>> -sBits); + prev_q = next_q; + + cc_Nu += q_s & M; + Nu[i] = (int)cc_Nu; cc_Nu >>= 32; + } } } } @@ -141,59 +195,113 @@ static boolean lessThan(int last, int[] x, int[] y) return false; } - static void subShifted_NP(int last, int s, int[] Nu, int[] Nv, int[] _p) + static void subShifted_NP(int last, int s, int[] Nu, int[] Nv, int[] p, int[] t) { - int sWords = s >>> 5, sBits = s & 31; - - long cc__p = 0L; + long cc_p = 0L; long cc_Nu = 0L; - if (sBits == 0) + if (s == 0) { - for (int i = sWords; i <= last; ++i) + for (int i = 0; i <= last; ++i) { + int p_i = p[i]; + cc_Nu += Nu[i] & M; - cc_Nu -= _p[i - sWords] & M; + cc_Nu -= p_i & M; - cc__p += _p[i] & M; - cc__p -= Nv[i - sWords] & M; - _p[i] = (int)cc__p; cc__p >>= 32; + cc_p += p_i & M; + cc_p -= Nv[i] & M; + p_i = (int)cc_p; cc_p >>= 32; + p[i] = p_i; - cc_Nu -= _p[i - sWords] & M; + cc_Nu -= p_i & M; Nu[i] = (int)cc_Nu; cc_Nu >>= 32; } } - else + else if (s < 32) { int prev_p = 0; int prev_q = 0; int prev_v = 0; - for (int i = sWords; i <= last; ++i) + for (int i = 0; i <= last; ++i) { - int next_p = _p[i - sWords]; - int p_s = (next_p << sBits) | (prev_p >>> -sBits); - prev_p = next_p; + int p_i = p[i]; + int p_s = (p_i << s) | (prev_p >>> -s); + prev_p = p_i; cc_Nu += Nu[i] & M; cc_Nu -= p_s & M; - int next_v = Nv[i - sWords]; - int v_s = (next_v << sBits) | (prev_v >>> -sBits); + int next_v = Nv[i]; + int v_s = (next_v << s) | (prev_v >>> -s); prev_v = next_v; - cc__p += _p[i] & M; - cc__p -= v_s & M; - _p[i] = (int)cc__p; cc__p >>= 32; + cc_p += p_i & M; + cc_p -= v_s & M; + p_i = (int)cc_p; cc_p >>= 32; + p[i] = p_i; - int next_q = _p[i - sWords]; - int q_s = (next_q << sBits) | (prev_q >>> -sBits); - prev_q = next_q; + int q_s = (p_i << s) | (prev_q >>> -s); + prev_q = p_i; cc_Nu -= q_s & M; Nu[i] = (int)cc_Nu; cc_Nu >>= 32; } } + else + { + // Keep the original value of p in t. + System.arraycopy(p, 0, t, 0, p.length); + + int sWords = s >>> 5; int sBits = s & 31; + if (sBits == 0) + { + for (int i = sWords; i <= last; ++i) + { + cc_Nu += Nu[i] & M; + cc_Nu -= t[i - sWords] & M; + + cc_p += p[i] & M; + cc_p -= Nv[i - sWords] & M; + p[i] = (int)cc_p; cc_p >>= 32; + + cc_Nu -= p[i - sWords] & M; + Nu[i] = (int)cc_Nu; cc_Nu >>= 32; + } + } + else + { + int prev_t = 0; + int prev_q = 0; + int prev_v = 0; + + for (int i = sWords; i <= last; ++i) + { + int next_t = t[i - sWords]; + int t_s = (next_t << sBits) | (prev_t >>> -sBits); + prev_t = next_t; + + cc_Nu += Nu[i] & M; + cc_Nu -= t_s & M; + + int next_v = Nv[i - sWords]; + int v_s = (next_v << sBits) | (prev_v >>> -sBits); + prev_v = next_v; + + cc_p += p[i] & M; + cc_p -= v_s & M; + p[i] = (int)cc_p; cc_p >>= 32; + + int next_q = p[i - sWords]; + int q_s = (next_q << sBits) | (prev_q >>> -sBits); + prev_q = next_q; + + cc_Nu -= q_s & M; + Nu[i] = (int)cc_Nu; cc_Nu >>= 32; + } + } + } } static void subShifted_UV(int last, int s, int[] u0, int[] u1, int[] v0, int[] v1)