diff options
-rw-r--r-- | crypto/Readme.html | 14 | ||||
-rw-r--r-- | crypto/crypto.csproj | 10 | ||||
-rw-r--r-- | crypto/src/math/raw/Nat128.cs | 8 | ||||
-rw-r--r-- | crypto/src/math/raw/Nat160.cs | 16 | ||||
-rw-r--r-- | crypto/src/math/raw/Nat192.cs | 24 | ||||
-rw-r--r-- | crypto/src/math/raw/Nat224.cs | 32 | ||||
-rw-r--r-- | crypto/src/math/raw/Nat256.cs | 40 | ||||
-rw-r--r-- | crypto/test/UnitTests.csproj | 2 | ||||
-rw-r--r-- | crypto/test/src/math/ec/custom/sec/test/SecP256R1FieldTest.cs | 181 | ||||
-rw-r--r-- | crypto/test/src/math/ec/custom/sec/test/SecP384R1FieldTest.cs | 146 |
10 files changed, 412 insertions, 61 deletions
diff --git a/crypto/Readme.html b/crypto/Readme.html index 0cbd91daa..b26937714 100644 --- a/crypto/Readme.html +++ b/crypto/Readme.html @@ -294,6 +294,18 @@ We state, where EC MQV has not otherwise been disabled or removed: <h4><a class="mozTocH4" name="mozTocId85316"></a>Release 1.8.2, Release Date TBD</h4> + <h5>Security Advisory</h5> + <ul> + <li> + Carry propagation bugs 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. We consider these bugs to be exploitable for static ECDH with + long-term keys, per <a href="https://eprint.iacr.org/2011/633">"Practical realisation and elimination of an ECC-related software bug attack", + Brumley et.al.</a> + </li> + </ul> + <h5>IMPORTANT</h5> <ul> <li> @@ -381,7 +393,7 @@ We state, where EC MQV has not otherwise been disabled or removed: <li>RFC 6637 ECDSA and ECDH support has been added to the OpenPGP API.</li> <li>Implementations of Threefish and Skein have been added.</li> <li>Implementation of the SM3 digest has been added.</li> - <li>Implementations of XSalsa20 and ChaCha have been added. Support for reduced round Salas20 has been added.</li> + <li>Implementations of XSalsa20 and ChaCha have been added. Support for reduced round Salsa20 has been added.</li> <li>Support has been added for RFC 6979 Deterministic DSA/ECDSA.</li> <li>Support for the Poly1305 MAC has been added.</li> <li>GCM and GMAC now support tag lengths down to 32 bits.</li> diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj index fcb52bb20..6f1fdcf61 100644 --- a/crypto/crypto.csproj +++ b/crypto/crypto.csproj @@ -12055,6 +12055,16 @@ BuildAction = "Compile" /> <File + RelPath = "test\src\math\ec\custom\sec\test\SecP256R1FieldTest.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File + RelPath = "test\src\math\ec\custom\sec\test\SecP384R1FieldTest.cs" + SubType = "Code" + BuildAction = "Compile" + /> + <File RelPath = "test\src\math\ec\test\AllTests.cs" SubType = "Code" BuildAction = "Compile" diff --git a/crypto/src/math/raw/Nat128.cs b/crypto/src/math/raw/Nat128.cs index 819c52062..1d3b64d32 100644 --- a/crypto/src/math/raw/Nat128.cs +++ b/crypto/src/math/raw/Nat128.cs @@ -626,8 +626,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[3]; - ulong zz_5 = zz[5]; - ulong zz_6 = zz[6]; + ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; @@ -702,8 +702,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[xOff + 3]; - ulong zz_5 = zz[zzOff + 5]; - ulong zz_6 = zz[zzOff + 6]; + ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; diff --git a/crypto/src/math/raw/Nat160.cs b/crypto/src/math/raw/Nat160.cs index 153ac0a43..1fd00e576 100644 --- a/crypto/src/math/raw/Nat160.cs +++ b/crypto/src/math/raw/Nat160.cs @@ -604,8 +604,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[3]; - ulong zz_5 = zz[5]; - ulong zz_6 = zz[6]; + ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; @@ -619,8 +619,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_4 = x[4]; - ulong zz_7 = zz[7]; - ulong zz_8 = zz[8]; + ulong zz_7 = zz[7] + (zz_6 >> 32); zz_6 &= M; + ulong zz_8 = zz[8] + (zz_7 >> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (uint)zz_4; @@ -699,8 +699,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[xOff + 3]; - ulong zz_5 = zz[zzOff + 5]; - ulong zz_6 = zz[zzOff + 6]; + ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; @@ -714,8 +714,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_4 = x[xOff + 4]; - ulong zz_7 = zz[zzOff + 7]; - ulong zz_8 = zz[zzOff + 8]; + ulong zz_7 = zz[zzOff + 7] + (zz_6 >> 32); zz_6 &= M; + ulong zz_8 = zz[zzOff + 8] + (zz_7 >> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (uint)zz_4; diff --git a/crypto/src/math/raw/Nat192.cs b/crypto/src/math/raw/Nat192.cs index 4797609ee..3099bafab 100644 --- a/crypto/src/math/raw/Nat192.cs +++ b/crypto/src/math/raw/Nat192.cs @@ -706,8 +706,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[3]; - ulong zz_5 = zz[5]; - ulong zz_6 = zz[6]; + ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; @@ -721,8 +721,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_4 = x[4]; - ulong zz_7 = zz[7]; - ulong zz_8 = zz[8]; + ulong zz_7 = zz[7] + (zz_6 >> 32); zz_6 &= M; + ulong zz_8 = zz[8] + (zz_7 >> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (uint)zz_4; @@ -738,8 +738,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_5 = x[5]; - ulong zz_9 = zz[9]; - ulong zz_10 = zz[10]; + ulong zz_9 = zz[9] + (zz_8 >> 32); zz_8 &= M; + ulong zz_10 = zz[10] + (zz_9 >> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (uint)zz_5; @@ -822,8 +822,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[xOff + 3]; - ulong zz_5 = zz[zzOff + 5]; - ulong zz_6 = zz[zzOff + 6]; + ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; @@ -837,8 +837,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_4 = x[xOff + 4]; - ulong zz_7 = zz[zzOff + 7]; - ulong zz_8 = zz[zzOff + 8]; + ulong zz_7 = zz[zzOff + 7] + (zz_6 >> 32); zz_6 &= M; + ulong zz_8 = zz[zzOff + 8] + (zz_7 >> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (uint)zz_4; @@ -854,8 +854,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_5 = x[xOff + 5]; - ulong zz_9 = zz[zzOff + 9]; - ulong zz_10 = zz[zzOff + 10]; + ulong zz_9 = zz[zzOff + 9] + (zz_8 >> 32); zz_8 &= M; + ulong zz_10 = zz[zzOff + 10] + (zz_9 >> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (uint)zz_5; diff --git a/crypto/src/math/raw/Nat224.cs b/crypto/src/math/raw/Nat224.cs index 940e930ac..978caf265 100644 --- a/crypto/src/math/raw/Nat224.cs +++ b/crypto/src/math/raw/Nat224.cs @@ -786,8 +786,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[3]; - ulong zz_5 = zz[5]; - ulong zz_6 = zz[6]; + ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; @@ -801,8 +801,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_4 = x[4]; - ulong zz_7 = zz[7]; - ulong zz_8 = zz[8]; + ulong zz_7 = zz[7] + (zz_6 >> 32); zz_6 &= M; + ulong zz_8 = zz[8] + (zz_7 >> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (uint)zz_4; @@ -818,8 +818,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_5 = x[5]; - ulong zz_9 = zz[9]; - ulong zz_10 = zz[10]; + ulong zz_9 = zz[9] + (zz_8 >> 32); zz_8 &= M; + ulong zz_10 = zz[10] + (zz_9 >> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (uint)zz_5; @@ -837,8 +837,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_6 = x[6]; - ulong zz_11 = zz[11]; - ulong zz_12 = zz[12]; + ulong zz_11 = zz[11] + (zz_10 >> 32); zz_10 &= M; + ulong zz_12 = zz[12] + (zz_11 >> 32); zz_11 &= M; { zz_6 += x_6 * x_0; w = (uint)zz_6; @@ -925,8 +925,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[xOff + 3]; - ulong zz_5 = zz[zzOff + 5]; - ulong zz_6 = zz[zzOff + 6]; + ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; @@ -940,8 +940,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_4 = x[xOff + 4]; - ulong zz_7 = zz[zzOff + 7]; - ulong zz_8 = zz[zzOff + 8]; + ulong zz_7 = zz[zzOff + 7] + (zz_6 >> 32); zz_6 &= M; + ulong zz_8 = zz[zzOff + 8] + (zz_7 >> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (uint)zz_4; @@ -957,8 +957,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_5 = x[xOff + 5]; - ulong zz_9 = zz[zzOff + 9]; - ulong zz_10 = zz[zzOff + 10]; + ulong zz_9 = zz[zzOff + 9] + (zz_8 >> 32); zz_8 &= M; + ulong zz_10 = zz[zzOff + 10] + (zz_9 >> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (uint)zz_5; @@ -976,8 +976,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_6 = x[xOff + 6]; - ulong zz_11 = zz[zzOff + 11]; - ulong zz_12 = zz[zzOff + 12]; + ulong zz_11 = zz[zzOff + 11] + (zz_10 >> 32); zz_10 &= M; + ulong zz_12 = zz[zzOff + 12] + (zz_11 >> 32); zz_11 &= M; { zz_6 += x_6 * x_0; w = (uint)zz_6; diff --git a/crypto/src/math/raw/Nat256.cs b/crypto/src/math/raw/Nat256.cs index 19455031a..09c751a5a 100644 --- a/crypto/src/math/raw/Nat256.cs +++ b/crypto/src/math/raw/Nat256.cs @@ -917,8 +917,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[3]; - ulong zz_5 = zz[5]; - ulong zz_6 = zz[6]; + ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; @@ -932,8 +932,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_4 = x[4]; - ulong zz_7 = zz[7]; - ulong zz_8 = zz[8]; + ulong zz_7 = zz[7] + (zz_6 >> 32); zz_6 &= M; + ulong zz_8 = zz[8] + (zz_7 >> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (uint)zz_4; @@ -949,8 +949,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_5 = x[5]; - ulong zz_9 = zz[9]; - ulong zz_10 = zz[10]; + ulong zz_9 = zz[9] + (zz_8 >> 32); zz_8 &= M; + ulong zz_10 = zz[10] + (zz_9 >> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (uint)zz_5; @@ -968,8 +968,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_6 = x[6]; - ulong zz_11 = zz[11]; - ulong zz_12 = zz[12]; + ulong zz_11 = zz[11] + (zz_10 >> 32); zz_10 &= M; + ulong zz_12 = zz[12] + (zz_11 >> 32); zz_11 &= M; { zz_6 += x_6 * x_0; w = (uint)zz_6; @@ -989,8 +989,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_7 = x[7]; - ulong zz_13 = zz[13]; - ulong zz_14 = zz[14]; + ulong zz_13 = zz[13] + (zz_12 >> 32); zz_12 &= M; + ulong zz_14 = zz[14] + (zz_13 >> 32); zz_13 &= M; { zz_7 += x_7 * x_0; w = (uint)zz_7; @@ -1081,8 +1081,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[xOff + 3]; - ulong zz_5 = zz[zzOff + 5]; - ulong zz_6 = zz[zzOff + 6]; + ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; @@ -1096,8 +1096,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_4 = x[xOff + 4]; - ulong zz_7 = zz[zzOff + 7]; - ulong zz_8 = zz[zzOff + 8]; + ulong zz_7 = zz[zzOff + 7] + (zz_6 >> 32); zz_6 &= M; + ulong zz_8 = zz[zzOff + 8] + (zz_7 >> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (uint)zz_4; @@ -1113,8 +1113,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_5 = x[xOff + 5]; - ulong zz_9 = zz[zzOff + 9]; - ulong zz_10 = zz[zzOff + 10]; + ulong zz_9 = zz[zzOff + 9] + (zz_8 >> 32); zz_8 &= M; + ulong zz_10 = zz[zzOff + 10] + (zz_9 >> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (uint)zz_5; @@ -1132,8 +1132,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_6 = x[xOff + 6]; - ulong zz_11 = zz[zzOff + 11]; - ulong zz_12 = zz[zzOff + 12]; + ulong zz_11 = zz[zzOff + 11] + (zz_10 >> 32); zz_10 &= M; + ulong zz_12 = zz[zzOff + 12] + (zz_11 >> 32); zz_11 &= M; { zz_6 += x_6 * x_0; w = (uint)zz_6; @@ -1153,8 +1153,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_7 = x[xOff + 7]; - ulong zz_13 = zz[zzOff + 13]; - ulong zz_14 = zz[zzOff + 14]; + ulong zz_13 = zz[zzOff + 13] + (zz_12 >> 32); zz_12 &= M; + ulong zz_14 = zz[zzOff + 14] + (zz_13 >> 32); zz_13 &= M; { zz_7 += x_7 * x_0; w = (uint)zz_7; diff --git a/crypto/test/UnitTests.csproj b/crypto/test/UnitTests.csproj index b4c53092b..fe4dd9583 100644 --- a/crypto/test/UnitTests.csproj +++ b/crypto/test/UnitTests.csproj @@ -312,6 +312,8 @@ <Compile Include="src\crypto\tls\test\TlsTestSuite.cs" /> <Compile Include="src\crypto\tls\test\TlsTestUtilities.cs" /> <Compile Include="src\crypto\tls\test\UnreliableDatagramTransport.cs" /> + <Compile Include="src\math\ec\custom\sec\test\SecP256R1FieldTest.cs" /> + <Compile Include="src\math\ec\custom\sec\test\SecP384R1FieldTest.cs" /> <Compile Include="src\math\ec\test\AllTests.cs" /> <Compile Include="src\math\ec\test\ECAlgorithmsTest.cs" /> <Compile Include="src\math\ec\test\ECPointPerformanceTest.cs" /> diff --git a/crypto/test/src/math/ec/custom/sec/test/SecP256R1FieldTest.cs b/crypto/test/src/math/ec/custom/sec/test/SecP256R1FieldTest.cs new file mode 100644 index 000000000..374b1ecd1 --- /dev/null +++ b/crypto/test/src/math/ec/custom/sec/test/SecP256R1FieldTest.cs @@ -0,0 +1,181 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Asn1.Sec; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto.EC; +using Org.BouncyCastle.Math.Raw; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Math.EC.Custom.Sec.Tests +{ + [TestFixture] + public class SecP256R1FieldTest + { + private static readonly SecureRandom Random = new SecureRandom(); + + private static readonly X9ECParameters DP = CustomNamedCurves + .GetByOid(SecObjectIdentifiers.SecP256r1); + private static readonly BigInteger Q = DP.Curve.Field.Characteristic; + + [Test] + 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(); + + Assert.AreEqual(R, Z); + } + } + + [Test] + 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(); + + Assert.AreEqual(R, Z); + } + } + } + + [Test] + 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(); + + Assert.AreEqual(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. + */ + [Test] + 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(); + + Assert.AreEqual(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. + */ + [Test] + 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(); + + Assert.AreEqual(R, Z); + } + } + + private ECFieldElement FE(BigInteger x) + { + return DP.Curve.FromBigInteger(x); + } + + private ECFieldElement GenerateMultiplyInput_Random() + { + return FE(new BigInteger(DP.Curve.FieldSize + 32, Random).Mod(Q)); + } + + private ECFieldElement GenerateMultiplyInputA_OpenSSLBug() + { + uint[] x = Nat256.Create(); + x[0] = (uint)Random.NextInt() >> 1; + x[4] = 3; + x[7] = 0xFFFFFFFF; + + return FE(Nat256.ToBigInteger(x)); + } + + private ECFieldElement GenerateMultiplyInputB_OpenSSLBug() + { + uint[] x = Nat256.Create(); + x[0] = (uint)Random.NextInt() >> 1; + x[3] = 1; + x[7] = 0xFFFFFFFF; + + return FE(Nat256.ToBigInteger(x)); + } + + private ECFieldElement GenerateSquareInput_OpenSSLBug() + { + uint[] x = Nat256.Create(); + x[0] = (uint)Random.NextInt() >> 1; + x[4] = 2; + x[7] = 0xFFFFFFFF; + + return FE(Nat256.ToBigInteger(x)); + } + } +} diff --git a/crypto/test/src/math/ec/custom/sec/test/SecP384R1FieldTest.cs b/crypto/test/src/math/ec/custom/sec/test/SecP384R1FieldTest.cs new file mode 100644 index 000000000..86ec4894f --- /dev/null +++ b/crypto/test/src/math/ec/custom/sec/test/SecP384R1FieldTest.cs @@ -0,0 +1,146 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Asn1.Sec; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto.EC; +using Org.BouncyCastle.Math.Raw; +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Math.EC.Custom.Sec.Tests +{ + [TestFixture] + public class SecP384R1FieldTest + { + private static readonly SecureRandom Random = new SecureRandom(); + + private static readonly X9ECParameters DP = CustomNamedCurves + .GetByOid(SecObjectIdentifiers.SecP384r1); + private static readonly BigInteger Q = DP.Curve.Field.Characteristic; + + [Test] + 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(); + + Assert.AreEqual(R, Z); + } + } + + [Test] + 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(); + + Assert.AreEqual(R, Z); + } + } + } + + [Test] + 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(); + + Assert.AreEqual(R, Z); + } + } + + [Test] + 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(); + + Assert.AreEqual(R, Z); + } + } + + /* + * Based on another example input demonstrating the carry propagation bug in Nat192.square, as + * reported by Joseph Friel on dev-crypto. + */ + [Test] + 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(); + + Assert.AreEqual(R, Z); + } + + private ECFieldElement FE(BigInteger x) + { + return DP.Curve.FromBigInteger(x); + } + + private ECFieldElement GenerateMultiplyInput_Random() + { + return FE(new BigInteger(DP.Curve.FieldSize + 32, Random).Mod(Q)); + } + + private ECFieldElement GenerateSquareInput_CarryBug() + { + uint[] x = Nat.Create(12); + x[0] = (uint)Random.NextInt() >> 1; + x[6] = 2; + x[10] = 0xFFFF0000; + x[11] = 0xFFFFFFFF; + + return FE(Nat.ToBigInteger(12, x)); + } + } +} |