summary refs log tree commit diff
path: root/crypto
diff options
context:
space:
mode:
authorOren Novotny <oren@novotny.org>2019-08-01 16:38:06 -0400
committerOren Novotny <oren@novotny.org>2019-08-01 16:38:06 -0400
commitfa5d0cc3ad1a1f25a9fc54c6904a7469a49935cb (patch)
treeb3c5db1e7d83f557f86ee0cce3a676af00d4cacf /crypto
parentRename main (diff)
parentWork on EC parameters classes (diff)
downloadBouncyCastle.NET-ed25519-fa5d0cc3ad1a1f25a9fc54c6904a7469a49935cb.tar.xz
merge from master
Diffstat (limited to 'crypto')
-rw-r--r--crypto/crypto.csproj5
-rw-r--r--crypto/src/asn1/Asn1Set.cs37
-rw-r--r--crypto/src/crypto/generators/ECKeyPairGenerator.cs2
-rw-r--r--crypto/src/crypto/generators/SCrypt.cs28
-rw-r--r--crypto/src/crypto/parameters/ECDomainParameters.cs51
-rw-r--r--crypto/src/crypto/parameters/ECNamedDomainParameters.cs2
-rw-r--r--crypto/src/crypto/parameters/ECPrivateKeyParameters.cs15
-rw-r--r--crypto/src/crypto/parameters/ECPublicKeyParameters.cs15
-rw-r--r--crypto/src/math/ec/custom/sec/SecP128R1Field.cs5
-rw-r--r--crypto/src/math/raw/Nat.cs17
-rw-r--r--crypto/test/src/math/ec/custom/sec/test/SecP128R1FieldTest.cs61
11 files changed, 168 insertions, 70 deletions
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index 55fcf1704..1b4cccd52 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -12933,6 +12933,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "test\src\math\ec\custom\sec\test\SecP128R1FieldTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "test\src\math\ec\custom\sec\test\SecP256R1FieldTest.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
diff --git a/crypto/src/asn1/Asn1Set.cs b/crypto/src/asn1/Asn1Set.cs
index bf83dbdc1..7fa072c0d 100644
--- a/crypto/src/asn1/Asn1Set.cs
+++ b/crypto/src/asn1/Asn1Set.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Collections;
+using System.Diagnostics;
 using System.IO;
 
 #if PORTABLE
@@ -344,29 +345,35 @@ namespace Org.BouncyCastle.Asn1
             {
                 byte[] a = (byte[])x, b = (byte[])y;
 #endif
+                Debug.Assert(a.Length >= 2 && b.Length >= 2);
+
+                /*
+                 * NOTE: Set elements in DER encodings are ordered first according to their tags (class and
+                 * number); the CONSTRUCTED bit is not part of the tag.
+                 * 
+                 * For SET-OF, this is unimportant. All elements have the same tag and DER requires them to
+                 * either all be in constructed form or all in primitive form, according to that tag. The
+                 * elements are effectively ordered according to their content octets.
+                 * 
+                 * For SET, the elements will have distinct tags, and each will be in constructed or
+                 * primitive form accordingly. Failing to ignore the CONSTRUCTED bit could therefore lead to
+                 * ordering inversions.
+                 */
+                int a0 = a[0] & ~Asn1Tags.Constructed;
+                int b0 = b[0] & ~Asn1Tags.Constructed;
+                if (a0 != b0)
+                    return a0 < b0 ? -1 : 1;
+
                 int len = System.Math.Min(a.Length, b.Length);
-                for (int i = 0; i != len; ++i)
+                for (int i = 1; i < len; ++i)
                 {
                     byte ai = a[i], bi = b[i];
                     if (ai != bi)
                         return ai < bi ? -1 : 1;
                 }
-                if (a.Length > b.Length)
-                    return AllZeroesFrom(a, len) ? 0 : 1;
-                if (a.Length < b.Length)
-                    return AllZeroesFrom(b, len) ? 0 : -1;
+                Debug.Assert(a.Length == b.Length);
                 return 0;
             }
-
-            private bool AllZeroesFrom(byte[] bs, int pos)
-            {
-                while (pos < bs.Length)
-                {
-                    if (bs[pos++] != 0)
-                        return false;
-                }
-                return true;
-            }
         }
     }
 }
diff --git a/crypto/src/crypto/generators/ECKeyPairGenerator.cs b/crypto/src/crypto/generators/ECKeyPairGenerator.cs
index 26bc06e14..6a710c62e 100644
--- a/crypto/src/crypto/generators/ECKeyPairGenerator.cs
+++ b/crypto/src/crypto/generators/ECKeyPairGenerator.cs
@@ -105,7 +105,7 @@ namespace Org.BouncyCastle.Crypto.Generators
             {
                 d = new BigInteger(n.BitLength, random);
 
-                if (d.CompareTo(BigInteger.Two) < 0 || d.CompareTo(n) >= 0)
+                if (d.CompareTo(BigInteger.One) < 0 || d.CompareTo(n) >= 0)
                     continue;
 
                 if (WNafUtilities.GetNafWeight(d) < minWeight)
diff --git a/crypto/src/crypto/generators/SCrypt.cs b/crypto/src/crypto/generators/SCrypt.cs
index 4d15bb3d7..51dc50b81 100644
--- a/crypto/src/crypto/generators/SCrypt.cs
+++ b/crypto/src/crypto/generators/SCrypt.cs
@@ -98,31 +98,37 @@ namespace Org.BouncyCastle.Crypto.Generators
 			uint[] blockY = new uint[BCount];
 
 			uint[] X = new uint[BCount];
-			uint[][] V = new uint[N][];
+            uint[] V = new uint[N * BCount];
 
 			try
 			{
 				Array.Copy(B, BOff, X, 0, BCount);
 
-				for (int i = 0; i < N; ++i)
-				{
-					V[i] = (uint[])X.Clone();
-					BlockMix(X, blockX1, blockX2, blockY, r);
-				}
+                int off = 0;
+                for (int i = 0; i < N; i += 2)
+                {
+                    Array.Copy(X, 0, V, off, BCount);
+                    off += BCount;
+                    BlockMix(X, blockX1, blockX2, blockY, r);
+                    Array.Copy(blockY, 0, V, off, BCount);
+                    off += BCount;
+                    BlockMix(blockY, blockX1, blockX2, X, r);
+                }
 
 				uint mask = (uint)N - 1;
 				for (int i = 0; i < N; ++i)
 				{
 					uint j = X[BCount - 16] & mask;
-					Xor(X, V[j], 0, X);
-					BlockMix(X, blockX1, blockX2, blockY, r);
-				}
+                    Array.Copy(V, j * BCount, blockY, 0, BCount);
+                    Xor(blockY, X, 0, blockY);
+                    BlockMix(blockY, blockX1, blockX2, X, r);
+                }
 
 				Array.Copy(X, 0, B, BOff, BCount);
 			}
 			finally
 			{
-				ClearAll(V);
+				Clear(V);
 				ClearAll(X, blockX1, blockX2, blockY);
 			}
 		}
@@ -143,8 +149,6 @@ namespace Org.BouncyCastle.Crypto.Generators
 				YOff = halfLen + BOff - YOff;
 				BOff += 16;
 			}
-
-			Array.Copy(Y, 0, B, 0, Y.Length);
 		}
 
 		private static void Xor(uint[] a, uint[] b, int bOff, uint[] output)
diff --git a/crypto/src/crypto/parameters/ECDomainParameters.cs b/crypto/src/crypto/parameters/ECDomainParameters.cs
index e377f7760..3ff7d809f 100644
--- a/crypto/src/crypto/parameters/ECDomainParameters.cs
+++ b/crypto/src/crypto/parameters/ECDomainParameters.cs
@@ -8,12 +8,13 @@ namespace Org.BouncyCastle.Crypto.Parameters
 {
     public class ECDomainParameters
     {
-        internal ECCurve     curve;
-        internal byte[]      seed;
-        internal ECPoint     g;
-        internal BigInteger  n;
-        internal BigInteger  h;
-        internal BigInteger  hInv;
+        private readonly ECCurve     curve;
+        private readonly byte[] seed;
+        private readonly ECPoint g;
+        private readonly BigInteger n;
+        private readonly BigInteger h;
+
+        private BigInteger hInv;
 
         public ECDomainParameters(
             ECCurve     curve,
@@ -48,7 +49,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
             // we can't check for h == null here as h is optional in X9.62 as it is not required for ECDSA
 
             this.curve = curve;
-            this.g = Validate(curve, g);
+            this.g = ValidatePublicPoint(curve, g);
             this.n = n;
             this.h = h;
             this.seed = Arrays.Clone(seed);
@@ -113,26 +114,42 @@ namespace Org.BouncyCastle.Crypto.Parameters
         {
             return curve.Equals(other.curve)
                 &&	g.Equals(other.g)
-                &&	n.Equals(other.n)
-                &&  h.Equals(other.h);
+                &&	n.Equals(other.n);
         }
 
         public override int GetHashCode()
         {
-            int hc = curve.GetHashCode();
-            hc *= 37;
+            //return Arrays.GetHashCode(new object[]{ curve, g, n });
+            int hc = 4;
+            hc *= 257;
+            hc ^= curve.GetHashCode();
+            hc *= 257;
             hc ^= g.GetHashCode();
-            hc *= 37;
+            hc *= 257;
             hc ^= n.GetHashCode();
-            hc *= 37;
-            hc ^= h.GetHashCode();
             return hc;
         }
 
-        internal static ECPoint Validate(ECCurve c, ECPoint q)
+        public BigInteger ValidatePrivateScalar(BigInteger d)
+        {
+            if (null == d)
+                throw new ArgumentNullException("d", "Scalar cannot be null");
+
+            if (d.CompareTo(BigInteger.One) < 0 || (d.CompareTo(N) >= 0))
+                throw new ArgumentException("Scalar is not in the interval [1, n - 1]", "d");
+
+            return d;
+        }
+
+        public ECPoint ValidatePublicPoint(ECPoint q)
+        {
+            return ValidatePublicPoint(Curve, q);
+        }
+
+        internal static ECPoint ValidatePublicPoint(ECCurve c, ECPoint q)
         {
-            if (q == null)
-                throw new ArgumentException("Point has null value", "q");
+            if (null == q)
+                throw new ArgumentNullException("q", "Point cannot be null");
 
             q = ECAlgorithms.ImportPoint(c, q).Normalize();
 
diff --git a/crypto/src/crypto/parameters/ECNamedDomainParameters.cs b/crypto/src/crypto/parameters/ECNamedDomainParameters.cs
index 4b8e2558f..2279c7dcc 100644
--- a/crypto/src/crypto/parameters/ECNamedDomainParameters.cs
+++ b/crypto/src/crypto/parameters/ECNamedDomainParameters.cs
@@ -17,7 +17,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
         }
 
         public ECNamedDomainParameters(DerObjectIdentifier name, ECDomainParameters dp)
-            : this(name, dp.curve, dp.g, dp.n, dp.h, dp.seed)
+            : this(name, dp.Curve, dp.G, dp.N, dp.H, dp.GetSeed())
         {
         }
 
diff --git a/crypto/src/crypto/parameters/ECPrivateKeyParameters.cs b/crypto/src/crypto/parameters/ECPrivateKeyParameters.cs
index 4d0fa1fc6..47e53ef2d 100644
--- a/crypto/src/crypto/parameters/ECPrivateKeyParameters.cs
+++ b/crypto/src/crypto/parameters/ECPrivateKeyParameters.cs
@@ -24,10 +24,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
             DerObjectIdentifier publicKeyParamSet)
             : base("ECGOST3410", true, publicKeyParamSet)
         {
-            if (d == null)
-                throw new ArgumentNullException("d");
-
-            this.d = d;
+            this.d = Parameters.ValidatePrivateScalar(d);
         }
 
         public ECPrivateKeyParameters(
@@ -36,10 +33,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
             ECDomainParameters	parameters)
             : base(algorithm, true, parameters)
         {
-            if (d == null)
-                throw new ArgumentNullException("d");
-
-            this.d = d;
+            this.d = Parameters.ValidatePrivateScalar(d);
         }
 
         public ECPrivateKeyParameters(
@@ -48,10 +42,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
             DerObjectIdentifier publicKeyParamSet)
             : base(algorithm, true, publicKeyParamSet)
         {
-            if (d == null)
-                throw new ArgumentNullException("d");
-
-            this.d = d;
+            this.d = Parameters.ValidatePrivateScalar(d);
         }
 
         public BigInteger D
diff --git a/crypto/src/crypto/parameters/ECPublicKeyParameters.cs b/crypto/src/crypto/parameters/ECPublicKeyParameters.cs
index 69916e525..d43ac7e0e 100644
--- a/crypto/src/crypto/parameters/ECPublicKeyParameters.cs
+++ b/crypto/src/crypto/parameters/ECPublicKeyParameters.cs
@@ -24,10 +24,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
             DerObjectIdentifier publicKeyParamSet)
             : base("ECGOST3410", false, publicKeyParamSet)
         {
-            if (q == null)
-                throw new ArgumentNullException("q");
-
-            this.q = ECDomainParameters.Validate(Parameters.Curve, q);
+            this.q = ECDomainParameters.ValidatePublicPoint(Parameters.Curve, q);
         }
 
         public ECPublicKeyParameters(
@@ -36,10 +33,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
             ECDomainParameters	parameters)
             : base(algorithm, false, parameters)
         {
-            if (q == null)
-                throw new ArgumentNullException("q");
-
-            this.q = ECDomainParameters.Validate(Parameters.Curve, q);
+            this.q = ECDomainParameters.ValidatePublicPoint(Parameters.Curve, q);
         }
 
         public ECPublicKeyParameters(
@@ -48,10 +42,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
             DerObjectIdentifier publicKeyParamSet)
             : base(algorithm, false, publicKeyParamSet)
         {
-            if (q == null)
-                throw new ArgumentNullException("q");
-
-            this.q = ECDomainParameters.Validate(Parameters.Curve, q);
+            this.q = ECDomainParameters.ValidatePublicPoint(Parameters.Curve, q);
         }
 
         public ECPoint Q
diff --git a/crypto/src/math/ec/custom/sec/SecP128R1Field.cs b/crypto/src/math/ec/custom/sec/SecP128R1Field.cs
index d1ac009b3..cf91c7e5d 100644
--- a/crypto/src/math/ec/custom/sec/SecP128R1Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecP128R1Field.cs
@@ -134,6 +134,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
                 x = (uint)c;
             }
+
+            if (z[3] >= P3 && Nat128.Gte(z, P))
+            {
+                AddPInvTo(z);
+            }
         }
 
         public static void Square(uint[] x, uint[] z)
diff --git a/crypto/src/math/raw/Nat.cs b/crypto/src/math/raw/Nat.cs
index 040ade74f..f9e4e6714 100644
--- a/crypto/src/math/raw/Nat.cs
+++ b/crypto/src/math/raw/Nat.cs
@@ -270,6 +270,23 @@ namespace Org.BouncyCastle.Math.Raw
             Array.Copy(x, xOff, z, zOff, len);
         }
 
+        public static ulong[] Copy64(int len, ulong[] x)
+        {
+            ulong[] z = new ulong[len];
+            Array.Copy(x, 0, z, 0, len);
+            return z;
+        }
+
+        public static void Copy64(int len, ulong[] x, ulong[] z)
+        {
+            Array.Copy(x, 0, z, 0, len);
+        }
+
+        public static void Copy64(int len, ulong[] x, int xOff, ulong[] z, int zOff)
+        {
+            Array.Copy(x, xOff, z, zOff, len);
+        }
+
         public static uint[] Create(int len)
         {
             return new uint[len];
diff --git a/crypto/test/src/math/ec/custom/sec/test/SecP128R1FieldTest.cs b/crypto/test/src/math/ec/custom/sec/test/SecP128R1FieldTest.cs
new file mode 100644
index 000000000..26b4060b0
--- /dev/null
+++ b/crypto/test/src/math/ec/custom/sec/test/SecP128R1FieldTest.cs
@@ -0,0 +1,61 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto.EC;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec.Tests
+{
+    [TestFixture]
+    public class SecP128R1FieldTest
+    {
+        private static readonly X9ECParameters DP = CustomNamedCurves
+            .GetByOid(SecObjectIdentifiers.SecP128r1);
+
+        [Test]
+        public void Test_GitHub566()
+        {
+            uint[] x = new uint[]{ 0x4B1E2F5E, 0x09E29D21, 0xA58407ED, 0x6FC3C7CF };
+            uint[] y = new uint[]{ 0x2FFE8892, 0x55CA61CA, 0x0AF780B5, 0x4BD7B797 };
+
+            ECFieldElement Z = FE(x).Multiply(FE(y));
+
+            uint[] expected = new uint[] { 0x01FFFF01, 0, 0, 0 };
+            Assert.AreEqual(FE(expected), Z);
+        }
+
+        private ECFieldElement FE(BigInteger x)
+        {
+            return DP.Curve.FromBigInteger(x);
+        }
+
+        private ECFieldElement FE(uint[] x)
+        {
+            return FE(Nat128_ToBigInteger(x));
+        }
+
+        private static BigInteger Nat128_ToBigInteger(uint[] x)
+        {
+            byte[] bs = new byte[16];
+            for (int i = 0; i < 4; ++i)
+            {
+                uint x_i = x[i];
+                if (x_i != 0)
+                {
+                    Pack_UInt32_To_BE(x_i, bs, (3 - i) << 2);
+                }
+            }
+            return new BigInteger(1, bs);
+        }
+
+        private static void Pack_UInt32_To_BE(uint n, byte[] bs, int off)
+        {
+            bs[off] = (byte)(n >> 24);
+            bs[off + 1] = (byte)(n >> 16);
+            bs[off + 2] = (byte)(n >> 8);
+            bs[off + 3] = (byte)(n);
+        }
+    }
+}