summary refs log tree commit diff
path: root/crypto/src/math/ec/ECCurve.cs
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2014-07-23 15:17:12 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2014-07-23 15:17:12 +0700
commit6e306046568f9a4d13639b913f0ff6d5879fa165 (patch)
tree994b8711674bb146ff578c1f0dff649282962acb /crypto/src/math/ec/ECCurve.cs
parentUpdate encrypt_then_mac entry (diff)
downloadBouncyCastle.NET-ed25519-6e306046568f9a4d13639b913f0ff6d5879fa165.tar.xz
Add automatic EC point validation for decoded points and for multiplier outputs
Diffstat (limited to 'crypto/src/math/ec/ECCurve.cs')
-rw-r--r--crypto/src/math/ec/ECCurve.cs164
1 files changed, 105 insertions, 59 deletions
diff --git a/crypto/src/math/ec/ECCurve.cs b/crypto/src/math/ec/ECCurve.cs
index 9c16375e6..889da292f 100644
--- a/crypto/src/math/ec/ECCurve.cs
+++ b/crypto/src/math/ec/ECCurve.cs
@@ -102,6 +102,27 @@ namespace Org.BouncyCastle.Math.EC
             return new Config(this, this.m_coord, this.m_endomorphism, this.m_multiplier);
         }
 
+        public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y)
+        {
+            ECPoint p = CreatePoint(x, y);
+            if (!p.IsValid())
+            {
+                throw new ArgumentException("Invalid point coordinates");
+            }
+            return p;
+        }
+
+        [Obsolete("Per-point compression property will be removed")]
+        public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y, bool withCompression)
+        {
+            ECPoint p = CreatePoint(x, y, withCompression);
+            if (!p.IsValid())
+            {
+                throw new ArgumentException("Invalid point coordinates");
+            }
+            return p;
+        }
+
         public virtual ECPoint CreatePoint(BigInteger x, BigInteger y)
         {
             return CreatePoint(x, y, false);
@@ -185,7 +206,7 @@ namespace Org.BouncyCastle.Math.EC
             // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates.
             p = p.Normalize();
 
-            return CreatePoint(p.XCoord.ToBigInteger(), p.YCoord.ToBigInteger(), p.IsCompressed);
+            return ValidatePoint(p.XCoord.ToBigInteger(), p.YCoord.ToBigInteger(), p.IsCompressed);
         }
 
         /**
@@ -344,7 +365,8 @@ namespace Org.BouncyCastle.Math.EC
             ECPoint p = null;
             int expectedLength = (FieldSize + 7) / 8;
 
-            switch (encoded[0])
+            byte type = encoded[0];
+            switch (type)
             {
                 case 0x00: // infinity
                 {
@@ -361,7 +383,7 @@ namespace Org.BouncyCastle.Math.EC
                     if (encoded.Length != (expectedLength + 1))
                         throw new ArgumentException("Incorrect length for compressed encoding", "encoded");
 
-                    int yTilde = encoded[0] & 1;
+                    int yTilde = type & 1;
                     BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
 
                     p = DecompressPoint(yTilde, X);
@@ -376,7 +398,7 @@ namespace Org.BouncyCastle.Math.EC
                     BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
                     BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
 
-                    p = CreatePoint(X, Y);
+                    p = ValidatePoint(X, Y);
                     break;
                 }
 
@@ -389,26 +411,59 @@ namespace Org.BouncyCastle.Math.EC
                     BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
                     BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
 
-                    if (Y.TestBit(0) != (encoded[0] == 0x07))
+                    if (Y.TestBit(0) != (type == 0x07))
                         throw new ArgumentException("Inconsistent Y coordinate in hybrid encoding", "encoded");
 
-                    p = CreatePoint(X, Y);
+                    p = ValidatePoint(X, Y);
                     break;
                 }
 
                 default:
-                    throw new FormatException("Invalid point encoding " + encoded[0]);
+                    throw new FormatException("Invalid point encoding " + type);
             }
 
+            if (type != 0x00 && p.IsInfinity)
+                throw new ArgumentException("Invalid infinity encoding", "encoded");
+
             return p;
         }
     }
 
+    public abstract class AbstractFpCurve
+        : ECCurve
+    {
+        protected AbstractFpCurve(BigInteger q)
+            : base(FiniteFields.GetPrimeField(q))
+        {
+        }
+
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement x = FromBigInteger(X1);
+            ECFieldElement rhs = x.Square().Add(A).Multiply(x).Add(B);
+            ECFieldElement y = rhs.Sqrt();
+
+            /*
+             * If y is not a square, then we haven't got a point on the curve
+             */
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            if (y.TestBitZero() != (yTilde == 1))
+            {
+                // Use the other root
+                y = y.Negate();
+            }
+
+            return CreateRawPoint(x, y, true);
+        }
+    }
+
     /**
      * Elliptic curve over Fp
      */
     public class FpCurve
-        : ECCurve
+        : AbstractFpCurve
     {
         private const int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
 
@@ -421,7 +476,7 @@ namespace Org.BouncyCastle.Math.EC
         }
 
         public FpCurve(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor)
-            : base(FiniteFields.GetPrimeField(q))
+            : base(q)
         {
             this.m_q = q;
             this.m_r = FpFieldElement.CalculateResidue(q);
@@ -440,7 +495,7 @@ namespace Org.BouncyCastle.Math.EC
         }
 
         protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
-            : base(FiniteFields.GetPrimeField(q))
+            : base(q)
         {
             this.m_q = q;
             this.m_r = r;
@@ -523,38 +578,11 @@ namespace Org.BouncyCastle.Math.EC
 
             return base.ImportPoint(p);
         }
-
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1);
-            ECFieldElement alpha = x.Square().Add(m_a).Multiply(x).Add(m_b);
-            ECFieldElement beta = alpha.Sqrt();
-
-            //
-            // if we can't find a sqrt we haven't got a point on the
-            // curve - run!
-            //
-            if (beta == null)
-                throw new ArithmeticException("Invalid point compression");
-
-            if (beta.TestBitZero() != (yTilde == 1))
-            {
-                // Use the other root
-                beta = beta.Negate();
-            }
-
-            return new FpPoint(this, x, beta, true);
-        }
     }
 
-    /**
-     * Elliptic curves over F2m. The Weierstrass equation is given by
-     * <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>.
-     */
-    public class F2mCurve : ECCurve
+    public abstract class AbstractF2mCurve
+        : ECCurve
     {
-        private const int F2M_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
-
         private static IFiniteField BuildField(int m, int k1, int k2, int k3)
         {
             if (k1 == 0)
@@ -585,6 +613,21 @@ namespace Org.BouncyCastle.Math.EC
             return FiniteFields.GetBinaryExtensionField(new int[]{ 0, k1, k2, k3, m });
         }
 
+        protected AbstractF2mCurve(int m, int k1, int k2, int k3)
+            : base(BuildField(m, k1, k2, k3))
+        {
+        }
+    }
+
+    /**
+     * Elliptic curves over F2m. The Weierstrass equation is given by
+     * <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>.
+     */
+    public class F2mCurve
+        : AbstractF2mCurve
+    {
+        private const int F2M_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
         /**
          * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
          */
@@ -748,7 +791,7 @@ namespace Org.BouncyCastle.Math.EC
             BigInteger	b,
             BigInteger	order,
             BigInteger	cofactor)
-            : base(BuildField(m, k1, k2, k3))
+            : base(m, k1, k2, k3)
         {
             this.m = m;
             this.k1 = k1;
@@ -781,7 +824,7 @@ namespace Org.BouncyCastle.Math.EC
         }
 
         protected F2mCurve(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
-            : base(BuildField(m, k1, k2, k3))
+            : base(m, k1, k2, k3)
         {
             this.m = m;
             this.k1 = k1;
@@ -936,7 +979,7 @@ namespace Org.BouncyCastle.Math.EC
 
         protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
         {
-            ECFieldElement xp = FromBigInteger(X1), yp;
+            ECFieldElement xp = FromBigInteger(X1), yp = null;
             if (xp.IsZero)
             {
                 yp = m_b.Sqrt();
@@ -946,31 +989,34 @@ namespace Org.BouncyCastle.Math.EC
                 ECFieldElement beta = xp.Square().Invert().Multiply(B).Add(A).Add(xp);
                 ECFieldElement z = SolveQuadradicEquation(beta);
 
-                if (z == null)
-                    throw new ArithmeticException("Invalid point compression");
-
-                if (z.TestBitZero() != (yTilde == 1))
-                {
-                    z = z.AddOne();
-                }
-
-                switch (this.CoordinateSystem)
+                if (z != null)
                 {
-                    case COORD_LAMBDA_AFFINE:
-                    case COORD_LAMBDA_PROJECTIVE:
+                    if (z.TestBitZero() != (yTilde == 1))
                     {
-                        yp = z.Add(xp);
-                        break;
+                        z = z.AddOne();
                     }
-                    default:
+
+                    switch (this.CoordinateSystem)
                     {
-                        yp = z.Multiply(xp);
-                        break;
+                        case COORD_LAMBDA_AFFINE:
+                        case COORD_LAMBDA_PROJECTIVE:
+                        {
+                            yp = z.Add(xp);
+                            break;
+                        }
+                        default:
+                        {
+                            yp = z.Multiply(xp);
+                            break;
+                        }
                     }
                 }
             }
 
-            return new F2mPoint(this, xp, yp, true);
+            if (yp == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return CreateRawPoint(xp, yp, true);
         }
 
         /**