VYPR
High severityNVD Advisory· Published Jun 4, 2018· Updated Aug 6, 2024

CVE-2016-1000340

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.

PackageAffected versionsPatched versions
org.bouncycastle:bcprov-jdk14Maven
>= 1.51, < 1.561.56
org.bouncycastle:bcprov-jdk15Maven
>= 1.51, < 1.561.56
org.bouncycastle:bcprov-jdk15onMaven
>= 1.51, < 1.561.56

Affected products

4

Patches

1
790642084c4e

Fix carry propagation bug in Nat???.square methods

https://github.com/bcgit/bc-javaPeter DettmanNov 29, 2016via ghsa
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

News mentions

0

No linked articles in our index yet.