diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2024-03-13 20:11:36 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2024-03-13 20:11:36 +0700 |
commit | 64439fc0cfd678f86faf741963c72fdef217ad5c (patch) | |
tree | d6d2c0075db1e16afc7ca4ebcf57531703f30803 /crypto | |
parent | Refactoring in Cms (diff) | |
download | BouncyCastle.NET-ed25519-64439fc0cfd678f86faf741963c72fdef217ad5c.tar.xz |
Fix for EdDSA verification infinite loop
- see https://github.com/bcgit/bc-java/issues/1599
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/src/math/ec/rfc8032/Scalar25519.cs | 10 | ||||
-rw-r--r-- | crypto/src/math/ec/rfc8032/Scalar448.cs | 10 | ||||
-rw-r--r-- | crypto/src/math/ec/rfc8032/ScalarUtilities.cs | 216 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/Ed25519Test.cs | 15 |
4 files changed, 193 insertions, 58 deletions
diff --git a/crypto/src/math/ec/rfc8032/Scalar25519.cs b/crypto/src/math/ec/rfc8032/Scalar25519.cs index 67eee6155..4fb2fd2da 100644 --- a/crypto/src/math/ec/rfc8032/Scalar25519.cs +++ b/crypto/src/math/ec/rfc8032/Scalar25519.cs @@ -606,6 +606,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 Span<uint> Nu = stackalloc uint[16]; LSq.CopyTo(Nu); Span<uint> Nv = stackalloc uint[16]; Nat256.Square(k, Nv); ++Nv[0]; Span<uint> p = stackalloc uint[16]; Nat256.Mul(L, k, p); + Span<uint> t = stackalloc uint[16]; Span<uint> u0 = stackalloc uint[4]; u0.CopyFrom(L); Span<uint> u1 = stackalloc uint[4]; Span<uint> v0 = stackalloc uint[4]; v0.CopyFrom(k); @@ -622,12 +623,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 if ((int)p[last] < 0) { - ScalarUtilities.AddShifted_NP(last, s, Nu, Nv, p); + ScalarUtilities.AddShifted_NP(last, s, Nu, Nv, p, t); ScalarUtilities.AddShifted_UV(last: 3, s, u0, u1, v0, v1); } else { - ScalarUtilities.SubShifted_NP(last, s, Nu, Nv, p); + ScalarUtilities.SubShifted_NP(last, s, Nu, Nv, p, t); ScalarUtilities.SubShifted_UV(last: 3, s, u0, u1, v0, v1); } @@ -658,6 +659,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 uint[] Nu = new uint[16]; Array.Copy(LSq, Nu, 16); uint[] Nv = new uint[16]; Nat256.Square(k, Nv); ++Nv[0]; uint[] p = new uint[16]; Nat256.Mul(L, k, p); + uint[] t = new uint[16]; uint[] u0 = new uint[4]; Array.Copy(L, u0, 4); uint[] u1 = new uint[4]; uint[] v0 = new uint[4]; Array.Copy(k, v0, 4); @@ -674,12 +676,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 if ((int)p[last] < 0) { - ScalarUtilities.AddShifted_NP(last, s, Nu, Nv, p); + ScalarUtilities.AddShifted_NP(last, s, Nu, Nv, p, t); ScalarUtilities.AddShifted_UV(last: 3, s, u0, u1, v0, v1); } else { - ScalarUtilities.SubShifted_NP(last, s, Nu, Nv, p); + ScalarUtilities.SubShifted_NP(last, s, Nu, Nv, p, t); ScalarUtilities.SubShifted_UV(last: 3, s, u0, u1, v0, v1); } diff --git a/crypto/src/math/ec/rfc8032/Scalar448.cs b/crypto/src/math/ec/rfc8032/Scalar448.cs index 124b91250..d53f0b669 100644 --- a/crypto/src/math/ec/rfc8032/Scalar448.cs +++ b/crypto/src/math/ec/rfc8032/Scalar448.cs @@ -1125,6 +1125,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 Span<uint> Nu = stackalloc uint[28]; LSq.CopyTo(Nu); Span<uint> Nv = stackalloc uint[28]; Nat448.Square(k, Nv); ++Nv[0]; Span<uint> p = stackalloc uint[28]; Nat448.Mul(L, k, p); + Span<uint> t = stackalloc uint[28]; Span<uint> u0 = stackalloc uint[8]; u0.CopyFrom(L); Span<uint> u1 = stackalloc uint[8]; Span<uint> v0 = stackalloc uint[8]; v0.CopyFrom(k); @@ -1141,12 +1142,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 if ((int)p[last] < 0) { - ScalarUtilities.AddShifted_NP(last, s, Nu, Nv, p); + ScalarUtilities.AddShifted_NP(last, s, Nu, Nv, p, t); ScalarUtilities.AddShifted_UV(last: 7, s, u0, u1, v0, v1); } else { - ScalarUtilities.SubShifted_NP(last, s, Nu, Nv, p); + ScalarUtilities.SubShifted_NP(last, s, Nu, Nv, p, t); ScalarUtilities.SubShifted_UV(last: 7, s, u0, u1, v0, v1); } @@ -1180,6 +1181,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 uint[] Nu = new uint[28]; Array.Copy(LSq, Nu, 28); uint[] Nv = new uint[28]; Nat448.Square(k, Nv); ++Nv[0]; uint[] p = new uint[28]; Nat448.Mul(L, k, p); + uint[] t = new uint[28]; uint[] u0 = new uint[8]; Array.Copy(L, u0, 8); uint[] u1 = new uint[8]; uint[] v0 = new uint[8]; Array.Copy(k, v0, 8); @@ -1196,12 +1198,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 if ((int)p[last] < 0) { - ScalarUtilities.AddShifted_NP(last, s, Nu, Nv, p); + ScalarUtilities.AddShifted_NP(last, s, Nu, Nv, p, t); ScalarUtilities.AddShifted_UV(last: 7, s, u0, u1, v0, v1); } else { - ScalarUtilities.SubShifted_NP(last, s, Nu, Nv, p); + ScalarUtilities.SubShifted_NP(last, s, Nu, Nv, p, t); ScalarUtilities.SubShifted_UV(last: 7, s, u0, u1, v0, v1); } diff --git a/crypto/src/math/ec/rfc8032/ScalarUtilities.cs b/crypto/src/math/ec/rfc8032/ScalarUtilities.cs index c70a4f2e8..fca4a0232 100644 --- a/crypto/src/math/ec/rfc8032/ScalarUtilities.cs +++ b/crypto/src/math/ec/rfc8032/ScalarUtilities.cs @@ -12,62 +12,120 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 { #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void AddShifted_NP(int last, int s, Span<uint> Nu, ReadOnlySpan<uint> Nv, Span<uint> _p) + internal static void AddShifted_NP(int last, int s, Span<uint> Nu, ReadOnlySpan<uint> Nv, Span<uint> p, Span<uint> t) #else - internal static void AddShifted_NP(int last, int s, uint[] Nu, uint[] Nv, uint[] _p) + internal static void AddShifted_NP(int last, int s, uint[] Nu, uint[] Nv, uint[] p, uint[] t) #endif { - int sWords = s >> 5, sBits = s & 31; - - ulong cc__p = 0UL; + ulong cc_p = 0UL; ulong cc_Nu = 0UL; - if (sBits == 0) + if (s == 0) { - for (int i = sWords; i <= last; ++i) + for (int i = 0; i <= last; ++i) { + uint p_i = p[i]; + cc_Nu += Nu[i]; - cc_Nu += _p[i - sWords]; + cc_Nu += p_i; - cc__p += _p[i]; - cc__p += Nv[i - sWords]; - _p[i] = (uint)cc__p; cc__p >>= 32; + cc_p += p_i; + cc_p += Nv[i]; + p_i = (uint)cc_p; cc_p >>= 32; + p[i] = p_i; - cc_Nu += _p[i - sWords]; + cc_Nu += p_i; Nu[i] = (uint)cc_Nu; cc_Nu >>= 32; } } - else + else if (s < 32) { uint prev_p = 0U; uint prev_q = 0U; uint prev_v = 0U; - for (int i = sWords; i <= last; ++i) + for (int i = 0; i <= last; ++i) { - uint next_p = _p[i - sWords]; - uint p_s = (next_p << sBits) | (prev_p >> -sBits); - prev_p = next_p; + uint p_i = p[i]; + uint p_s = (p_i << s) | (prev_p >> -s); + prev_p = p_i; cc_Nu += Nu[i]; cc_Nu += p_s; - uint next_v = Nv[i - sWords]; - uint v_s = (next_v << sBits) | (prev_v >> -sBits); + uint next_v = Nv[i]; + uint v_s = (next_v << s) | (prev_v >> -s); prev_v = next_v; - cc__p += _p[i]; - cc__p += v_s; - _p[i] = (uint)cc__p; cc__p >>= 32; + cc_p += p_i; + cc_p += v_s; + p_i = (uint)cc_p; cc_p >>= 32; + p[i] = p_i; - uint next_q = _p[i - sWords]; - uint q_s = (next_q << sBits) | (prev_q >> -sBits); - prev_q = next_q; + uint q_s = (p_i << s) | (prev_q >> -s); + prev_q = p_i; cc_Nu += q_s; Nu[i] = (uint)cc_Nu; cc_Nu >>= 32; } } + else + { + // Keep the original value of p in t +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + t[..(last + 1)].CopyFrom(p); +#else + Array.Copy(p, 0, t, 0, last + 1); +#endif + + int sWords = s >> 5, sBits = s & 31; + if (sBits == 0) + { + for (int i = sWords; i <= last; ++i) + { + cc_Nu += Nu[i]; + cc_Nu += t[i - sWords]; + + cc_p += p[i]; + cc_p += Nv[i - sWords]; + p[i] = (uint)cc_p; cc_p >>= 32; + + cc_Nu += p[i - sWords]; + Nu[i] = (uint)cc_Nu; cc_Nu >>= 32; + } + } + else + { + uint prev_t = 0U; + uint prev_q = 0U; + uint prev_v = 0U; + + for (int i = sWords; i <= last; ++i) + { + uint next_t = t[i - sWords]; + uint t_s = (next_t << sBits) | (prev_t >> -sBits); + prev_t = next_t; + + cc_Nu += Nu[i]; + cc_Nu += t_s; + + uint next_v = Nv[i - sWords]; + uint v_s = (next_v << sBits) | (prev_v >> -sBits); + prev_v = next_v; + + cc_p += p[i]; + cc_p += v_s; + p[i] = (uint)cc_p; cc_p >>= 32; + + uint next_q = p[i - sWords]; + uint q_s = (next_q << sBits) | (prev_q >> -sBits); + prev_q = next_q; + + cc_Nu += q_s; + Nu[i] = (uint)cc_Nu; cc_Nu >>= 32; + } + } + } } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER @@ -171,62 +229,120 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void SubShifted_NP(int last, int s, Span<uint> Nu, ReadOnlySpan<uint> Nv, Span<uint> _p) + internal static void SubShifted_NP(int last, int s, Span<uint> Nu, ReadOnlySpan<uint> Nv, Span<uint> p, Span<uint> t) #else - internal static void SubShifted_NP(int last, int s, uint[] Nu, uint[] Nv, uint[] _p) + internal static void SubShifted_NP(int last, int s, uint[] Nu, uint[] Nv, uint[] p, uint[] t) #endif { - int sWords = s >> 5, sBits = s & 31; - - long cc__p = 0L; + long cc_p = 0L; long cc_Nu = 0L; - if (sBits == 0) + if (s == 0) { - for (int i = sWords; i <= last; ++i) + for (int i = 0; i <= last; ++i) { + uint p_i = p[i]; + cc_Nu += Nu[i]; - cc_Nu -= _p[i - sWords]; + cc_Nu -= p_i; - cc__p += _p[i]; - cc__p -= Nv[i - sWords]; - _p[i] = (uint)cc__p; cc__p >>= 32; + cc_p += p_i; + cc_p -= Nv[i]; + p_i = (uint)cc_p; cc_p >>= 32; + p[i] = p_i; - cc_Nu -= _p[i - sWords]; + cc_Nu -= p_i; Nu[i] = (uint)cc_Nu; cc_Nu >>= 32; } } - else + else if (s < 32) { uint prev_p = 0U; uint prev_q = 0U; uint prev_v = 0U; - for (int i = sWords; i <= last; ++i) + for (int i = 0; i <= last; ++i) { - uint next_p = _p[i - sWords]; - uint p_s = (next_p << sBits) | (prev_p >> -sBits); - prev_p = next_p; + uint p_i = p[i]; + uint p_s = (p_i << s) | (prev_p >> -s); + prev_p = p_i; cc_Nu += Nu[i]; cc_Nu -= p_s; - uint next_v = Nv[i - sWords]; - uint v_s = (next_v << sBits) | (prev_v >> -sBits); + uint next_v = Nv[i]; + uint v_s = (next_v << s) | (prev_v >> -s); prev_v = next_v; - cc__p += _p[i]; - cc__p -= v_s; - _p[i] = (uint)cc__p; cc__p >>= 32; + cc_p += p_i; + cc_p -= v_s; + p_i = (uint)cc_p; cc_p >>= 32; + p[i] = p_i; - uint next_q = _p[i - sWords]; - uint q_s = (next_q << sBits) | (prev_q >> -sBits); - prev_q = next_q; + uint q_s = (p_i << s) | (prev_q >> -s); + prev_q = p_i; cc_Nu -= q_s; Nu[i] = (uint)cc_Nu; cc_Nu >>= 32; } } + else + { + // Keep the original value of p in t +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + t[..(last + 1)].CopyFrom(p); +#else + Array.Copy(p, 0, t, 0, last + 1); +#endif + + int sWords = s >> 5, sBits = s & 31; + if (sBits == 0) + { + for (int i = sWords; i <= last; ++i) + { + cc_Nu += Nu[i]; + cc_Nu -= t[i - sWords]; + + cc_p += p[i]; + cc_p -= Nv[i - sWords]; + p[i] = (uint)cc_p; cc_p >>= 32; + + cc_Nu -= p[i - sWords]; + Nu[i] = (uint)cc_Nu; cc_Nu >>= 32; + } + } + else + { + uint prev_t = 0U; + uint prev_q = 0U; + uint prev_v = 0U; + + for (int i = sWords; i <= last; ++i) + { + uint next_t = t[i - sWords]; + uint t_s = (next_t << sBits) | (prev_t >> -sBits); + prev_t = next_t; + + cc_Nu += Nu[i]; + cc_Nu -= t_s; + + uint next_v = Nv[i - sWords]; + uint v_s = (next_v << sBits) | (prev_v >> -sBits); + prev_v = next_v; + + cc_p += p[i]; + cc_p -= v_s; + p[i] = (uint)cc_p; cc_p >>= 32; + + uint next_q = p[i - sWords]; + uint q_s = (next_q << sBits) | (prev_q >> -sBits); + prev_q = next_q; + + cc_Nu -= q_s; + Nu[i] = (uint)cc_Nu; cc_Nu >>= 32; + } + } + } } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER diff --git a/crypto/test/src/crypto/test/Ed25519Test.cs b/crypto/test/src/crypto/test/Ed25519Test.cs index b604916de..88b06c32e 100644 --- a/crypto/test/src/crypto/test/Ed25519Test.cs +++ b/crypto/test/src/crypto/test/Ed25519Test.cs @@ -25,6 +25,21 @@ namespace Org.BouncyCastle.Crypto.Tests } [Test] + public void TestRegression_GitHub_bc_java_1599() + { + Ed25519PublicKeyParameters publicKey = new Ed25519PublicKeyParameters( + Hex.DecodeStrict("386e7cf7b9e8353933b07f1db8d84d3720bb667cbd811b312b4e338672338a6d")); + byte[] content = Hex.DecodeStrict("414141624c6743596c6f414141514943486e6a4a71326a75705455472d5a36694d716871313467414854486f64757677694844664f594a3230775f77426c6e35444a3953614e616353496835336b626e716e723965ef34c5"); + byte[] sig = Hex.DecodeStrict("74dc43223fc21b9157e686a1446621a4640464b8ee4877ea7e3963cb5da8b21b9089241defdd7f36448ec4c76174af131994321da7e28483b3c2a7906947fa0f"); + + ISigner signer = new Ed25519Signer(); + signer.Init(false, publicKey); + signer.BlockUpdate(content, 0, content.Length); + bool verified = signer.VerifySignature(sig); + Assert.True(verified); + } + + [Test] public void TestFunction() { string resultText = Perform().ToString(); |