diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2019-08-29 20:00:22 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2019-08-29 20:00:22 +0700 |
commit | 13af6106b7d495c775ee69ef495b64318318d87f (patch) | |
tree | c5afdc1f7780b2b6ae9b08ac15f238df3011a688 /crypto | |
parent | Add new X448 test cases from bc-java (diff) | |
download | BouncyCastle.NET-ed25519-13af6106b7d495c775ee69ef495b64318318d87f.tar.xz |
Add sanity checks on scalar mult. outputs
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/src/math/ec/rfc7748/X448Field.cs | 8 | ||||
-rw-r--r-- | crypto/src/math/ec/rfc8032/Ed25519.cs | 59 | ||||
-rw-r--r-- | crypto/src/math/ec/rfc8032/Ed448.cs | 59 |
3 files changed, 116 insertions, 10 deletions
diff --git a/crypto/src/math/ec/rfc7748/X448Field.cs b/crypto/src/math/ec/rfc7748/X448Field.cs index f1e89e520..14c9b4879 100644 --- a/crypto/src/math/ec/rfc7748/X448Field.cs +++ b/crypto/src/math/ec/rfc7748/X448Field.cs @@ -1009,6 +1009,14 @@ namespace Org.BouncyCastle.Math.EC.Rfc7748 z[15] = z15; } + public static void SubOne(uint[] z) + { + uint[] one = Create(); + one[0] = 1U; + + Sub(z, one, z); + } + public static void Zero(uint[] z) { for (int i = 0; i < Size; ++i) diff --git a/crypto/src/math/ec/rfc8032/Ed25519.cs b/crypto/src/math/ec/rfc8032/Ed25519.cs index b798bdf2d..238256cf7 100644 --- a/crypto/src/math/ec/rfc8032/Ed25519.cs +++ b/crypto/src/math/ec/rfc8032/Ed25519.cs @@ -12,6 +12,8 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 { public abstract class Ed25519 { + // -x^2 + y^2 == 1 + 0x52036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978A3 * x^2 * y^2 + public enum Algorithm { Ed25519 = 0, @@ -112,6 +114,46 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 || ctx != null && ctx.Length < 256; } + private static int CheckPoint(int[] x, int[] y) + { + int[] t = X25519Field.Create(); + int[] u = X25519Field.Create(); + int[] v = X25519Field.Create(); + + X25519Field.Sqr(x, u); + X25519Field.Sqr(y, v); + X25519Field.Mul(u, v, t); + X25519Field.Sub(v, u, v); + X25519Field.Mul(t, C_d, t); + X25519Field.AddOne(t); + X25519Field.Sub(t, v, t); + X25519Field.Normalize(t); + + return X25519Field.IsZero(t); + } + + private static int CheckPoint(int[] x, int[] y, int[] z) + { + int[] t = X25519Field.Create(); + int[] u = X25519Field.Create(); + int[] v = X25519Field.Create(); + int[] w = X25519Field.Create(); + + X25519Field.Sqr(x, u); + X25519Field.Sqr(y, v); + X25519Field.Sqr(z, w); + X25519Field.Mul(u, v, t); + X25519Field.Sub(v, u, v); + X25519Field.Mul(v, w, v); + X25519Field.Sqr(w, w); + X25519Field.Mul(t, C_d, t); + X25519Field.Add(t, w, t); + X25519Field.Sub(t, v, t); + X25519Field.Normalize(t); + + return X25519Field.IsZero(t); + } + private static bool CheckPointVar(byte[] p) { uint[] t = new uint[8]; @@ -234,7 +276,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 Encode24((uint)(n >> 32), bs, off + 4); } - private static void EncodePoint(PointAccum p, byte[] r, int rOff) + private static int EncodePoint(PointAccum p, byte[] r, int rOff) { int[] x = X25519Field.Create(); int[] y = X25519Field.Create(); @@ -245,8 +287,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 X25519Field.Normalize(x); X25519Field.Normalize(y); + int result = CheckPoint(x, y); + X25519Field.Encode(y, r, rOff); r[rOff + PointBytes - 1] |= (byte)((x[0] & 1) << 7); + + return result; } public static void GeneratePrivateKey(SecureRandom random, byte[] k) @@ -426,9 +472,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 ScalarMultStrausVar(nS, nA, pA, pR); byte[] check = new byte[PointBytes]; - EncodePoint(pR, check, 0); - - return Arrays.AreEqual(check, R); + return 0 != EncodePoint(pR, check, 0) && Arrays.AreEqual(check, R); } private static void PointAddVar(bool negate, PointExt p, PointAccum r) @@ -931,7 +975,8 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 { PointAccum p = new PointAccum(); ScalarMultBase(k, p); - EncodePoint(p, r, rOff); + if (0 == EncodePoint(p, r, rOff)) + throw new InvalidOperationException(); } internal static void ScalarMultBaseYZ(byte[] k, int kOff, int[] y, int[] z) @@ -941,6 +986,10 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 PointAccum p = new PointAccum(); ScalarMultBase(n, p); + + if (0 == CheckPoint(p.x, p.y, p.z)) + throw new InvalidOperationException(); + X25519Field.Copy(p.y, 0, y, 0); X25519Field.Copy(p.z, 0, z, 0); } diff --git a/crypto/src/math/ec/rfc8032/Ed448.cs b/crypto/src/math/ec/rfc8032/Ed448.cs index 842839396..925f48eb1 100644 --- a/crypto/src/math/ec/rfc8032/Ed448.cs +++ b/crypto/src/math/ec/rfc8032/Ed448.cs @@ -12,6 +12,8 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 { public abstract class Ed448 { + // x^2 + y^2 == 1 - 39081 * x^2 * y^2 + public enum Algorithm { Ed448 = 0, @@ -109,6 +111,46 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 return ctx != null && ctx.Length < 256; } + private static int CheckPoint(uint[] x, uint[] y) + { + uint[] t = X448Field.Create(); + uint[] u = X448Field.Create(); + uint[] v = X448Field.Create(); + + X448Field.Sqr(x, u); + X448Field.Sqr(y, v); + X448Field.Mul(u, v, t); + X448Field.Add(u, v, u); + X448Field.Mul(t, -C_d, t); + X448Field.SubOne(t); + X448Field.Add(t, u, t); + X448Field.Normalize(t); + + return X448Field.IsZero(t); + } + + private static int CheckPoint(uint[] x, uint[] y, uint[] z) + { + uint[] t = X448Field.Create(); + uint[] u = X448Field.Create(); + uint[] v = X448Field.Create(); + uint[] w = X448Field.Create(); + + X448Field.Sqr(x, u); + X448Field.Sqr(y, v); + X448Field.Sqr(z, w); + X448Field.Mul(u, v, t); + X448Field.Add(u, v, u); + X448Field.Mul(u, w, u); + X448Field.Sqr(w, w); + X448Field.Mul(t, -C_d, t); + X448Field.Sub(t, w, t); + X448Field.Add(t, u, t); + X448Field.Normalize(t); + + return X448Field.IsZero(t); + } + private static bool CheckPointVar(byte[] p) { if ((p[PointBytes - 1] & 0x7F) != 0x00) @@ -243,7 +285,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 Encode24((uint)(n >> 32), bs, off + 4); } - private static void EncodePoint(PointExt p, byte[] r, int rOff) + private static int EncodePoint(PointExt p, byte[] r, int rOff) { uint[] x = X448Field.Create(); uint[] y = X448Field.Create(); @@ -254,8 +296,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 X448Field.Normalize(x); X448Field.Normalize(y); + int result = CheckPoint(x, y); + X448Field.Encode(y, r, rOff); r[rOff + PointBytes - 1] = (byte)((x[0] & 1) << 7); + + return result; } public static void GeneratePrivateKey(SecureRandom random, byte[] k) @@ -435,9 +481,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 ScalarMultStrausVar(nS, nA, pA, pR); byte[] check = new byte[PointBytes]; - EncodePoint(pR, check, 0); - - return Arrays.AreEqual(check, R); + return 0 != EncodePoint(pR, check, 0) && Arrays.AreEqual(check, R); } private static void PointAddVar(bool negate, PointExt p, PointExt r) @@ -1018,7 +1062,8 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 { PointExt p = new PointExt(); ScalarMultBase(k, p); - EncodePoint(p, r, rOff); + if (0 == EncodePoint(p, r, rOff)) + throw new InvalidOperationException(); } internal static void ScalarMultBaseXY(byte[] k, int kOff, uint[] x, uint[] y) @@ -1028,6 +1073,10 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 PointExt p = new PointExt(); ScalarMultBase(n, p); + + if (0 == CheckPoint(p.x, p.y, p.z)) + throw new InvalidOperationException(); + X448Field.Copy(p.x, 0, x, 0); X448Field.Copy(p.y, 0, y, 0); } |