CVE-2016-1000340
Description
In the Bouncy Castle JCE Provider versions 1.51 to 1.55, a carry propagation bug was introduced in the implementation of squaring for several raw math classes have been fixed (org.bouncycastle.math.raw.Nat???). These classes are used by our custom elliptic curve implementations (org.bouncycastle.math.ec.custom.**), so there was the possibility of rare (in general usage) spurious calculations for elliptic curve scalar multiplications. Such errors would have been detected with high probability by the output validation for our scalar multipliers.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Bouncy Castle JCE Provider versions 1.51 to 1.55 contain a carry propagation bug in squaring operations for raw math classes, causing rare spurious elliptic curve scalar multiplication results.
Vulnerability
Version 1.51 through 1.55 of the Bouncy Castle JCE Provider (org.bouncycastle.math.raw classes) contain a carry propagation bug introduced in the implementation of squaring for the raw math classes (org.bouncycastle.math.raw.Nat???). These classes are used by the custom elliptic curve implementations (org.bouncycastle.math.ec.custom.**). The bug can lead to rare (in general usage) spurious calculations for elliptic curve scalar multiplications [1][2][4].
Exploitation
An attacker would need to trigger an affected elliptic curve scalar multiplication operation. The bug would manifest in rare, unpredictable errors during such calculations; these errors would be detected with high probability by the output validation built into the scalar multipliers. No specific attacker network position, authentication, or user interaction is required beyond being able to supply inputs that exercise the flawed arithmetic path [1][4].
Impact
If the spurious calculation is not caught by the output validation, the attacker could potentially obtain an incorrect elliptic curve multiplication result. This could lead to a compromise of cryptographic operations relying on correct EC scalar multiplication, such as ECDH key agreement or ECDSA signature generation, potentially resulting in information disclosure or other cryptographic weaknesses. The official description notes that such errors would be detected with high probability by the output validation, so successful exploitation is unlikely [1][2][4].
Mitigation
The fix was introduced in Bouncy Castle JCE Provider version 1.56 (released 2016-09-01) [1][2]. Red Hat Satellite 6.4 was updated via RHSA-2018:2927, and Red Hat Fuse 7.1 was updated via RHSA-2018:2669 to include the corrected version [1][3]. Users of affected versions (1.51–1.55) should upgrade to version 1.56 or later. No workaround is available beyond upgrading.
AI Insight generated on May 22, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.bouncycastle:bcprov-jdk14Maven | >= 1.51, < 1.56 | 1.56 |
org.bouncycastle:bcprov-jdk15Maven | >= 1.51, < 1.56 | 1.56 |
org.bouncycastle:bcprov-jdk15onMaven | >= 1.51, < 1.56 | 1.56 |
Affected products
4- ghsa-coords4 versionspkg:maven/org.bouncycastle/bcprov-jdk14pkg:maven/org.bouncycastle/bcprov-jdk15pkg:maven/org.bouncycastle/bcprov-jdk15onpkg:rpm/opensuse/bouncycastle&distro=openSUSE%20Tumbleweed
>= 1.51, < 1.56+ 3 more
- (no CPE)range: >= 1.51, < 1.56
- (no CPE)range: >= 1.51, < 1.56
- (no CPE)range: >= 1.51, < 1.56
- (no CPE)range: < 1.68-3.2
Patches
1790642084c4eFix carry propagation bug in Nat???.square methods
7 files changed · +385 −70
core/src/main/java/org/bouncycastle/math/raw/Nat128.java+6 −6 modified@@ -636,8 +636,8 @@ public static void square(int[] x, int[] zz) } long x_3 = x[3] & M; - long zz_5 = zz[5] & M; - long zz_6 = zz[6] & M; + long zz_5 = (zz[5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -658,7 +658,7 @@ public static void square(int[] x, int[] zz) w = (int)zz_6; zz[6] = (w << 1) | c; c = w >>> 31; - w = zz[7] + (int)(zz_6 >> 32); + w = zz[7] + (int)(zz_6 >>> 32); zz[7] = (w << 1) | c; } @@ -713,8 +713,8 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) } long x_3 = x[xOff + 3] & M; - long zz_5 = zz[zzOff + 5] & M; - long zz_6 = zz[zzOff + 6] & M; + long zz_5 = (zz[zzOff + 5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[zzOff + 6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -734,7 +734,7 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) w = (int)zz_6; zz[zzOff + 6] = (w << 1) | c; c = w >>> 31; - w = zz[zzOff + 7] + (int)(zz_6 >> 32); + w = zz[zzOff + 7] + (int)(zz_6 >>> 32); zz[zzOff + 7] = (w << 1) | c; }
core/src/main/java/org/bouncycastle/math/raw/Nat160.java+10 −10 modified@@ -609,8 +609,8 @@ public static void square(int[] x, int[] zz) } long x_3 = x[3] & M; - long zz_5 = zz[5] & M; - long zz_6 = zz[6] & M; + long zz_5 = (zz[5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -624,8 +624,8 @@ public static void square(int[] x, int[] zz) } long x_4 = x[4] & M; - long zz_7 = zz[7] & M; - long zz_8 = zz[8] & M; + long zz_7 = (zz[7] & M) + (zz_6 >>> 32); zz_6 &= M; + long zz_8 = (zz[8] & M) + (zz_7 >>> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (int)zz_4; @@ -649,7 +649,7 @@ public static void square(int[] x, int[] zz) w = (int)zz_8; zz[8] = (w << 1) | c; c = w >>> 31; - w = zz[9] + (int)(zz_8 >> 32); + w = zz[9] + (int)(zz_8 >>> 32); zz[9] = (w << 1) | c; } @@ -704,8 +704,8 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) } long x_3 = x[xOff + 3] & M; - long zz_5 = zz[zzOff + 5] & M; - long zz_6 = zz[zzOff + 6] & M; + long zz_5 = (zz[zzOff + 5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[zzOff + 6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -719,8 +719,8 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) } long x_4 = x[xOff + 4] & M; - long zz_7 = zz[zzOff + 7] & M; - long zz_8 = zz[zzOff + 8] & M; + long zz_7 = (zz[zzOff + 7] & M) + (zz_6 >>> 32); zz_6 &= M; + long zz_8 = (zz[zzOff + 8] & M) + (zz_7 >>> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (int)zz_4; @@ -744,7 +744,7 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) w = (int)zz_8; zz[zzOff + 8] = (w << 1) | c; c = w >>> 31; - w = zz[zzOff + 9] + (int)(zz_8 >> 32); + w = zz[zzOff + 9] + (int)(zz_8 >>> 32); zz[zzOff + 9] = (w << 1) | c; }
core/src/main/java/org/bouncycastle/math/raw/Nat192.java+14 −14 modified@@ -715,8 +715,8 @@ public static void square(int[] x, int[] zz) } long x_3 = x[3] & M; - long zz_5 = zz[5] & M; - long zz_6 = zz[6] & M; + long zz_5 = (zz[5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -730,8 +730,8 @@ public static void square(int[] x, int[] zz) } long x_4 = x[4] & M; - long zz_7 = zz[7] & M; - long zz_8 = zz[8] & M; + long zz_7 = (zz[7] & M) + (zz_6 >>> 32); zz_6 &= M; + long zz_8 = (zz[8] & M) + (zz_7 >>> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (int)zz_4; @@ -747,8 +747,8 @@ public static void square(int[] x, int[] zz) } long x_5 = x[5] & M; - long zz_9 = zz[9] & M; - long zz_10 = zz[10] & M; + long zz_9 = (zz[9] & M) + (zz_8 >>> 32); zz_8 &= M; + long zz_10 = (zz[10] & M) + (zz_9 >>> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (int)zz_5; @@ -776,7 +776,7 @@ public static void square(int[] x, int[] zz) w = (int)zz_10; zz[10] = (w << 1) | c; c = w >>> 31; - w = zz[11] + (int)(zz_10 >> 32); + w = zz[11] + (int)(zz_10 >>> 32); zz[11] = (w << 1) | c; } @@ -831,8 +831,8 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) } long x_3 = x[xOff + 3] & M; - long zz_5 = zz[zzOff + 5] & M; - long zz_6 = zz[zzOff + 6] & M; + long zz_5 = (zz[zzOff + 5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[zzOff + 6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -846,8 +846,8 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) } long x_4 = x[xOff + 4] & M; - long zz_7 = zz[zzOff + 7] & M; - long zz_8 = zz[zzOff + 8] & M; + long zz_7 = (zz[zzOff + 7] & M) + (zz_6 >>> 32); zz_6 &= M; + long zz_8 = (zz[zzOff + 8] & M) + (zz_7 >>> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (int)zz_4; @@ -863,8 +863,8 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) } long x_5 = x[xOff + 5] & M; - long zz_9 = zz[zzOff + 9] & M; - long zz_10 = zz[zzOff + 10] & M; + long zz_9 = (zz[zzOff + 9] & M) + (zz_8 >>> 32); zz_8 &= M; + long zz_10 = (zz[zzOff + 10] & M) + (zz_9 >>> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (int)zz_5; @@ -892,7 +892,7 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) w = (int)zz_10; zz[zzOff + 10] = (w << 1) | c; c = w >>> 31; - w = zz[zzOff + 11] + (int)(zz_10 >> 32); + w = zz[zzOff + 11] + (int)(zz_10 >>> 32); zz[zzOff + 11] = (w << 1) | c; }
core/src/main/java/org/bouncycastle/math/raw/Nat224.java+18 −18 modified@@ -793,8 +793,8 @@ public static void square(int[] x, int[] zz) } long x_3 = x[3] & M; - long zz_5 = zz[5] & M; - long zz_6 = zz[6] & M; + long zz_5 = (zz[5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -808,8 +808,8 @@ public static void square(int[] x, int[] zz) } long x_4 = x[4] & M; - long zz_7 = zz[7] & M; - long zz_8 = zz[8] & M; + long zz_7 = (zz[7] & M) + (zz_6 >>> 32); zz_6 &= M; + long zz_8 = (zz[8] & M) + (zz_7 >>> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (int)zz_4; @@ -825,8 +825,8 @@ public static void square(int[] x, int[] zz) } long x_5 = x[5] & M; - long zz_9 = zz[9] & M; - long zz_10 = zz[10] & M; + long zz_9 = (zz[9] & M) + (zz_8 >>> 32); zz_8 &= M; + long zz_10 = (zz[10] & M) + (zz_9 >>> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (int)zz_5; @@ -844,8 +844,8 @@ public static void square(int[] x, int[] zz) } long x_6 = x[6] & M; - long zz_11 = zz[11] & M; - long zz_12 = zz[12] & M; + long zz_11 = (zz[11] & M) + (zz_10 >>> 32); zz_10 &= M; + long zz_12 = (zz[12] & M) + (zz_11 >>> 32); zz_11 &= M; { zz_6 += x_6 * x_0; w = (int)zz_6; @@ -877,7 +877,7 @@ public static void square(int[] x, int[] zz) w = (int)zz_12; zz[12] = (w << 1) | c; c = w >>> 31; - w = zz[13] + (int)(zz_12 >> 32); + w = zz[13] + (int)(zz_12 >>> 32); zz[13] = (w << 1) | c; } @@ -932,8 +932,8 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) } long x_3 = x[xOff + 3] & M; - long zz_5 = zz[zzOff + 5] & M; - long zz_6 = zz[zzOff + 6] & M; + long zz_5 = (zz[zzOff + 5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[zzOff + 6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -947,8 +947,8 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) } long x_4 = x[xOff + 4] & M; - long zz_7 = zz[zzOff + 7] & M; - long zz_8 = zz[zzOff + 8] & M; + long zz_7 = (zz[zzOff + 7] & M) + (zz_6 >>> 32); zz_6 &= M; + long zz_8 = (zz[zzOff + 8] & M) + (zz_7 >>> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (int)zz_4; @@ -964,8 +964,8 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) } long x_5 = x[xOff + 5] & M; - long zz_9 = zz[zzOff + 9] & M; - long zz_10 = zz[zzOff + 10] & M; + long zz_9 = (zz[zzOff + 9] & M) + (zz_8 >>> 32); zz_8 &= M; + long zz_10 = (zz[zzOff + 10] & M) + (zz_9 >>> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (int)zz_5; @@ -983,8 +983,8 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) } long x_6 = x[xOff + 6] & M; - long zz_11 = zz[zzOff + 11] & M; - long zz_12 = zz[zzOff + 12] & M; + long zz_11 = (zz[zzOff + 11] & M) + (zz_10 >>> 32); zz_10 &= M; + long zz_12 = (zz[zzOff + 12] & M) + (zz_11 >>> 32); zz_11 &= M; { zz_6 += x_6 * x_0; w = (int)zz_6; @@ -1016,7 +1016,7 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) w = (int)zz_12; zz[zzOff + 12] = (w << 1) | c; c = w >>> 31; - w = zz[zzOff + 13] + (int)(zz_12 >> 32); + w = zz[zzOff + 13] + (int)(zz_12 >>> 32); zz[zzOff + 13] = (w << 1) | c; }
core/src/main/java/org/bouncycastle/math/raw/Nat256.java+22 −22 modified@@ -926,8 +926,8 @@ public static void square(int[] x, int[] zz) } long x_3 = x[3] & M; - long zz_5 = zz[5] & M; - long zz_6 = zz[6] & M; + long zz_5 = (zz[5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -941,8 +941,8 @@ public static void square(int[] x, int[] zz) } long x_4 = x[4] & M; - long zz_7 = zz[7] & M; - long zz_8 = zz[8] & M; + long zz_7 = (zz[7] & M) + (zz_6 >>> 32); zz_6 &= M; + long zz_8 = (zz[8] & M) + (zz_7 >>> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (int)zz_4; @@ -958,8 +958,8 @@ public static void square(int[] x, int[] zz) } long x_5 = x[5] & M; - long zz_9 = zz[9] & M; - long zz_10 = zz[10] & M; + long zz_9 = (zz[9] & M) + (zz_8 >>> 32); zz_8 &= M; + long zz_10 = (zz[10] & M) + (zz_9 >>> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (int)zz_5; @@ -977,8 +977,8 @@ public static void square(int[] x, int[] zz) } long x_6 = x[6] & M; - long zz_11 = zz[11] & M; - long zz_12 = zz[12] & M; + long zz_11 = (zz[11] & M) + (zz_10 >>> 32); zz_10 &= M; + long zz_12 = (zz[12] & M) + (zz_11 >>> 32); zz_11 &= M; { zz_6 += x_6 * x_0; w = (int)zz_6; @@ -998,8 +998,8 @@ public static void square(int[] x, int[] zz) } long x_7 = x[7] & M; - long zz_13 = zz[13] & M; - long zz_14 = zz[14] & M; + long zz_13 = (zz[13] & M) + (zz_12 >>> 32); zz_12 &= M; + long zz_14 = (zz[14] & M) + (zz_13 >>> 32); zz_13 &= M; { zz_7 += x_7 * x_0; w = (int)zz_7; @@ -1035,7 +1035,7 @@ public static void square(int[] x, int[] zz) w = (int)zz_14; zz[14] = (w << 1) | c; c = w >>> 31; - w = zz[15] + (int)(zz_14 >> 32); + w = zz[15] + (int)(zz_14 >>> 32); zz[15] = (w << 1) | c; } @@ -1090,8 +1090,8 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) } long x_3 = x[xOff + 3] & M; - long zz_5 = zz[zzOff + 5] & M; - long zz_6 = zz[zzOff + 6] & M; + long zz_5 = (zz[zzOff + 5] & M) + (zz_4 >>> 32); zz_4 &= M; + long zz_6 = (zz[zzOff + 6] & M) + (zz_5 >>> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (int)zz_3; @@ -1105,8 +1105,8 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) } long x_4 = x[xOff + 4] & M; - long zz_7 = zz[zzOff + 7] & M; - long zz_8 = zz[zzOff + 8] & M; + long zz_7 = (zz[zzOff + 7] & M) + (zz_6 >>> 32); zz_6 &= M; + long zz_8 = (zz[zzOff + 8] & M) + (zz_7 >>> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (int)zz_4; @@ -1122,8 +1122,8 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) } long x_5 = x[xOff + 5] & M; - long zz_9 = zz[zzOff + 9] & M; - long zz_10 = zz[zzOff + 10] & M; + long zz_9 = (zz[zzOff + 9] & M) + (zz_8 >>> 32); zz_8 &= M; + long zz_10 = (zz[zzOff + 10] & M) + (zz_9 >>> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (int)zz_5; @@ -1141,8 +1141,8 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) } long x_6 = x[xOff + 6] & M; - long zz_11 = zz[zzOff + 11] & M; - long zz_12 = zz[zzOff + 12] & M; + long zz_11 = (zz[zzOff + 11] & M) + (zz_10 >>> 32); zz_10 &= M; + long zz_12 = (zz[zzOff + 12] & M) + (zz_11 >>> 32); zz_11 &= M; { zz_6 += x_6 * x_0; w = (int)zz_6; @@ -1162,8 +1162,8 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) } long x_7 = x[xOff + 7] & M; - long zz_13 = zz[zzOff + 13] & M; - long zz_14 = zz[zzOff + 14] & M; + long zz_13 = (zz[zzOff + 13] & M) + (zz_12 >>> 32); zz_12 &= M; + long zz_14 = (zz[zzOff + 14] & M) + (zz_13 >>> 32); zz_13 &= M; { zz_7 += x_7 * x_0; w = (int)zz_7; @@ -1199,7 +1199,7 @@ public static void square(int[] x, int xOff, int[] zz, int zzOff) w = (int)zz_14; zz[zzOff + 14] = (w << 1) | c; c = w >>> 31; - w = zz[zzOff + 15] + (int)(zz_14 >> 32); + w = zz[zzOff + 15] + (int)(zz_14 >>> 32); zz[zzOff + 15] = (w << 1) | c; }
core/src/test/java/org/bouncycastle/math/ec/custom/sec/test/SecP256R1FieldTest.java+175 −0 added@@ -0,0 +1,175 @@ +package org.bouncycastle.math.ec.custom.sec.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.asn1.sec.SECObjectIdentifiers; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.ec.CustomNamedCurves; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.raw.Nat256; + +import junit.framework.TestCase; + +public class SecP256R1FieldTest extends TestCase +{ + private static final SecureRandom RANDOM = new SecureRandom(); + + private static final X9ECParameters DP = CustomNamedCurves + .getByOID(SECObjectIdentifiers.secp256r1); + private static final BigInteger Q = DP.getCurve().getField().getCharacteristic(); + + public void testMultiply1() + { + int COUNT = 1000; + + for (int i = 0; i < COUNT; ++i) + { + ECFieldElement x = generateMultiplyInput_Random(); + ECFieldElement y = generateMultiplyInput_Random(); + + BigInteger X = x.toBigInteger(), Y = y.toBigInteger(); + BigInteger R = X.multiply(Y).mod(Q); + + ECFieldElement z = x.multiply(y); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + } + + public void testMultiply2() + { + int COUNT = 100; + ECFieldElement[] inputs = new ECFieldElement[COUNT]; + BigInteger[] INPUTS = new BigInteger[COUNT]; + + for (int i = 0; i < inputs.length; ++i) + { + inputs[i] = generateMultiplyInput_Random(); + INPUTS[i] = inputs[i].toBigInteger(); + } + + for (int j = 0; j < inputs.length; ++j) + { + for (int k = 0; k < inputs.length; ++k) + { + BigInteger R = INPUTS[j].multiply(INPUTS[k]).mod(Q); + + ECFieldElement z = inputs[j].multiply(inputs[k]); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + } + } + + public void testSquare() + { + int COUNT = 1000; + + for (int i = 0; i < COUNT; ++i) + { + ECFieldElement x = generateMultiplyInput_Random(); + + BigInteger X = x.toBigInteger(); + BigInteger R = X.multiply(X).mod(Q); + + ECFieldElement z = x.square(); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + } + + /** + * Test multiplication with specifically selected values that triggered a bug in the modular + * reduction in OpenSSL (last affected version 0.9.8g). + * + * See "Practical realisation and elimination of an ECC-related software bug attack", B. B. + * Brumley, M. Barbarosa, D. Page, F. Vercauteren. + */ + public void testMultiply_OpenSSLBug() + { + int COUNT = 100; + + for (int i = 0; i < COUNT; ++i) + { + ECFieldElement x = generateMultiplyInputA_OpenSSLBug(); + ECFieldElement y = generateMultiplyInputB_OpenSSLBug(); + + BigInteger X = x.toBigInteger(), Y = y.toBigInteger(); + BigInteger R = X.multiply(Y).mod(Q); + + ECFieldElement z = x.multiply(y); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + } + + /** + * Test squaring with specifically selected values that triggered a bug in the modular reduction + * in OpenSSL (last affected version 0.9.8g). + * + * See "Practical realisation and elimination of an ECC-related software bug attack", B. B. + * Brumley, M. Barbarosa, D. Page, F. Vercauteren. + */ + public void testSquare_OpenSSLBug() + { + int COUNT = 100; + + for (int i = 0; i < COUNT; ++i) + { + ECFieldElement x = generateSquareInput_OpenSSLBug(); + + BigInteger X = x.toBigInteger(); + BigInteger R = X.multiply(X).mod(Q); + + ECFieldElement z = x.square(); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + } + + private ECFieldElement fe(BigInteger x) + { + return DP.getCurve().fromBigInteger(x); + } + + private ECFieldElement generateMultiplyInput_Random() + { + return fe(new BigInteger(DP.getCurve().getFieldSize() + 32, RANDOM).mod(Q)); + } + + private ECFieldElement generateMultiplyInputA_OpenSSLBug() + { + int[] x = Nat256.create(); + x[0] = RANDOM.nextInt() >>> 1; + x[4] = 3; + x[7] = -1; + + return fe(Nat256.toBigInteger(x)); + } + + private ECFieldElement generateMultiplyInputB_OpenSSLBug() + { + int[] x = Nat256.create(); + x[0] = RANDOM.nextInt() >>> 1; + x[3] = 1; + x[7] = -1; + + return fe(Nat256.toBigInteger(x)); + } + + private ECFieldElement generateSquareInput_OpenSSLBug() + { + int[] x = Nat256.create(); + x[0] = RANDOM.nextInt() >>> 1; + x[4] = 2; + x[7] = -1; + + return fe(Nat256.toBigInteger(x)); + } +}
core/src/test/java/org/bouncycastle/math/ec/custom/sec/test/SecP384R1FieldTest.java+140 −0 added@@ -0,0 +1,140 @@ +package org.bouncycastle.math.ec.custom.sec.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.asn1.sec.SECObjectIdentifiers; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.ec.CustomNamedCurves; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.raw.Nat; + +import junit.framework.TestCase; + +public class SecP384R1FieldTest extends TestCase +{ + private static final SecureRandom RANDOM = new SecureRandom(); + + private static final X9ECParameters DP = CustomNamedCurves + .getByOID(SECObjectIdentifiers.secp384r1); + private static final BigInteger Q = DP.getCurve().getField().getCharacteristic(); + + public void testMultiply1() + { + int COUNT = 1000; + + for (int i = 0; i < COUNT; ++i) + { + ECFieldElement x = generateMultiplyInput_Random(); + ECFieldElement y = generateMultiplyInput_Random(); + + BigInteger X = x.toBigInteger(), Y = y.toBigInteger(); + BigInteger R = X.multiply(Y).mod(Q); + + ECFieldElement z = x.multiply(y); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + } + + public void testMultiply2() + { + int COUNT = 100; + ECFieldElement[] inputs = new ECFieldElement[COUNT]; + BigInteger[] INPUTS = new BigInteger[COUNT]; + + for (int i = 0; i < inputs.length; ++i) + { + inputs[i] = generateMultiplyInput_Random(); + INPUTS[i] = inputs[i].toBigInteger(); + } + + for (int j = 0; j < inputs.length; ++j) + { + for (int k = 0; k < inputs.length; ++k) + { + BigInteger R = INPUTS[j].multiply(INPUTS[k]).mod(Q); + + ECFieldElement z = inputs[j].multiply(inputs[k]); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + } + } + + public void testSquare() + { + int COUNT = 1000; + + for (int i = 0; i < COUNT; ++i) + { + ECFieldElement x = generateMultiplyInput_Random(); + + BigInteger X = x.toBigInteger(); + BigInteger R = X.multiply(X).mod(Q); + + ECFieldElement z = x.square(); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + } + + public void testSquare_CarryBug() + { + int COUNT = 100; + + for (int i = 0; i < COUNT; ++i) + { + ECFieldElement x = generateSquareInput_CarryBug(); + + BigInteger X = x.toBigInteger(); + BigInteger R = X.multiply(X).mod(Q); + + ECFieldElement z = x.square(); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + } + + /* + * Based on another example input demonstrating the carry propagation bug in Nat192.square, as + * reported by Joseph Friel on dev-crypto. + */ + public void testSquare_CarryBug_Reported() + { + ECFieldElement x = fe(new BigInteger("2fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", 16)); + + BigInteger X = x.toBigInteger(); + BigInteger R = X.multiply(X).mod(Q); + + ECFieldElement z = x.square(); + BigInteger Z = z.toBigInteger(); + + assertEquals(R, Z); + } + + private ECFieldElement fe(BigInteger x) + { + return DP.getCurve().fromBigInteger(x); + } + + private ECFieldElement generateMultiplyInput_Random() + { + return fe(new BigInteger(DP.getCurve().getFieldSize() + 32, RANDOM).mod(Q)); + } + + private ECFieldElement generateSquareInput_CarryBug() + { + int[] x = Nat.create(12); + x[0] = RANDOM.nextInt() >>> 1; + x[6] = 2; + x[10] = -1 << 16; + x[11] = -1; + + return fe(Nat.toBigInteger(12, x)); + } +}
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- access.redhat.com/errata/RHSA-2018:2669ghsavendor-advisoryx_refsource_REDHATWEB
- access.redhat.com/errata/RHSA-2018:2927ghsavendor-advisoryx_refsource_REDHATWEB
- github.com/advisories/GHSA-r97x-3g8f-gx3mghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2016-1000340ghsaADVISORY
- github.com/bcgit/bc-java/commit/790642084c4e0cadd47352054f868cc8397e2c00ghsax_refsource_CONFIRMWEB
- security.netapp.com/advisory/ntap-20181127-0004ghsaWEB
- security.netapp.com/advisory/ntap-20181127-0004/mitrex_refsource_CONFIRM
- www.oracle.com/security-alerts/cpuoct2020.htmlghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.