From fbae27fb1edcea6b0924dba977a6d94f0a3655db Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Fri, 21 Sep 2018 15:17:56 +0700 Subject: Higher-level API support for Ed25519/Ed448/X25519/X448 --- crypto/BouncyCastle.Android.csproj | 25 ++++ crypto/BouncyCastle.csproj | 25 ++++ crypto/BouncyCastle.iOS.csproj | 25 ++++ crypto/crypto.csproj | 150 +++++++++++++++++++++ crypto/src/asn1/edec/EdECObjectIdentifiers.cs | 17 +++ crypto/src/crypto/IRawAgreement.cs | 13 ++ crypto/src/crypto/agreement/X25519Agreement.cs | 27 ++++ crypto/src/crypto/agreement/X448Agreement.cs | 27 ++++ .../crypto/generators/Ed25519KeyPairGenerator.cs | 25 ++++ .../src/crypto/generators/Ed448KeyPairGenerator.cs | 25 ++++ .../crypto/generators/X25519KeyPairGenerator.cs | 25 ++++ .../src/crypto/generators/X448KeyPairGenerator.cs | 25 ++++ .../parameters/Ed25519KeyGenerationParameters.cs | 15 +++ .../parameters/Ed25519PrivateKeyParameters.cs | 98 ++++++++++++++ .../parameters/Ed25519PublicKeyParameters.cs | 40 ++++++ .../parameters/Ed448KeyGenerationParameters.cs | 15 +++ .../crypto/parameters/Ed448PrivateKeyParameters.cs | 90 +++++++++++++ .../crypto/parameters/Ed448PublicKeyParameters.cs | 40 ++++++ .../parameters/X25519KeyGenerationParameters.cs | 15 +++ .../parameters/X25519PrivateKeyParameters.cs | 62 +++++++++ .../crypto/parameters/X25519PublicKeyParameters.cs | 40 ++++++ .../parameters/X448KeyGenerationParameters.cs | 15 +++ .../crypto/parameters/X448PrivateKeyParameters.cs | 62 +++++++++ .../crypto/parameters/X448PublicKeyParameters.cs | 40 ++++++ crypto/src/crypto/signers/Ed25519Signer.cs | 128 ++++++++++++++++++ crypto/src/crypto/signers/Ed25519ctxSigner.cs | 130 ++++++++++++++++++ crypto/src/crypto/signers/Ed25519phSigner.cs | 89 ++++++++++++ crypto/src/crypto/signers/Ed448Signer.cs | 130 ++++++++++++++++++ crypto/src/crypto/signers/Ed448phSigner.cs | 89 ++++++++++++ crypto/src/math/ec/rfc8032/Ed25519.cs | 7 + crypto/src/math/ec/rfc8032/Ed448.cs | 6 + crypto/src/pkcs/PrivateKeyInfoFactory.cs | 116 +++++++++++----- crypto/src/security/AgreementUtilities.cs | 55 +++++--- crypto/src/security/GeneratorUtilities.cs | 34 ++++- crypto/src/security/PrivateKeyFactory.cs | 28 +++- crypto/src/security/PublicKeyFactory.cs | 32 ++++- crypto/src/security/SignerUtilities.cs | 36 ++++- crypto/src/x509/SubjectPublicKeyInfoFactory.cs | 67 ++++++--- crypto/test/UnitTests.csproj | 5 + crypto/test/src/asn1/test/PrivateKeyInfoTest.cs | 60 +++++++++ crypto/test/src/asn1/test/RegressionTest.cs | 1 + crypto/test/src/crypto/test/Ed25519Test.cs | 111 +++++++++++++++ crypto/test/src/crypto/test/Ed448Test.cs | 107 +++++++++++++++ crypto/test/src/crypto/test/RegressionTest.cs | 4 + crypto/test/src/crypto/test/X25519Test.cs | 69 ++++++++++ crypto/test/src/crypto/test/X448Test.cs | 69 ++++++++++ .../test/src/math/ec/rfc8032/test/Ed25519Test.cs | 10 +- crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs | 8 +- crypto/test/src/security/test/TestSignerUtil.cs | 18 +++ 49 files changed, 2259 insertions(+), 91 deletions(-) create mode 100644 crypto/src/asn1/edec/EdECObjectIdentifiers.cs create mode 100644 crypto/src/crypto/IRawAgreement.cs create mode 100644 crypto/src/crypto/agreement/X25519Agreement.cs create mode 100644 crypto/src/crypto/agreement/X448Agreement.cs create mode 100644 crypto/src/crypto/generators/Ed25519KeyPairGenerator.cs create mode 100644 crypto/src/crypto/generators/Ed448KeyPairGenerator.cs create mode 100644 crypto/src/crypto/generators/X25519KeyPairGenerator.cs create mode 100644 crypto/src/crypto/generators/X448KeyPairGenerator.cs create mode 100644 crypto/src/crypto/parameters/Ed25519KeyGenerationParameters.cs create mode 100644 crypto/src/crypto/parameters/Ed25519PrivateKeyParameters.cs create mode 100644 crypto/src/crypto/parameters/Ed25519PublicKeyParameters.cs create mode 100644 crypto/src/crypto/parameters/Ed448KeyGenerationParameters.cs create mode 100644 crypto/src/crypto/parameters/Ed448PrivateKeyParameters.cs create mode 100644 crypto/src/crypto/parameters/Ed448PublicKeyParameters.cs create mode 100644 crypto/src/crypto/parameters/X25519KeyGenerationParameters.cs create mode 100644 crypto/src/crypto/parameters/X25519PrivateKeyParameters.cs create mode 100644 crypto/src/crypto/parameters/X25519PublicKeyParameters.cs create mode 100644 crypto/src/crypto/parameters/X448KeyGenerationParameters.cs create mode 100644 crypto/src/crypto/parameters/X448PrivateKeyParameters.cs create mode 100644 crypto/src/crypto/parameters/X448PublicKeyParameters.cs create mode 100644 crypto/src/crypto/signers/Ed25519Signer.cs create mode 100644 crypto/src/crypto/signers/Ed25519ctxSigner.cs create mode 100644 crypto/src/crypto/signers/Ed25519phSigner.cs create mode 100644 crypto/src/crypto/signers/Ed448Signer.cs create mode 100644 crypto/src/crypto/signers/Ed448phSigner.cs create mode 100644 crypto/test/src/asn1/test/PrivateKeyInfoTest.cs create mode 100644 crypto/test/src/crypto/test/Ed25519Test.cs create mode 100644 crypto/test/src/crypto/test/Ed448Test.cs create mode 100644 crypto/test/src/crypto/test/X25519Test.cs create mode 100644 crypto/test/src/crypto/test/X448Test.cs diff --git a/crypto/BouncyCastle.Android.csproj b/crypto/BouncyCastle.Android.csproj index 3c34c5e1b..c5eb8e6f5 100644 --- a/crypto/BouncyCastle.Android.csproj +++ b/crypto/BouncyCastle.Android.csproj @@ -258,6 +258,7 @@ + @@ -659,6 +660,7 @@ + @@ -699,6 +701,8 @@ + + @@ -815,6 +819,8 @@ + + @@ -831,6 +837,8 @@ + + @@ -901,6 +909,12 @@ + + + + + + @@ -939,6 +953,12 @@ + + + + + + @@ -950,6 +970,11 @@ + + + + + diff --git a/crypto/BouncyCastle.csproj b/crypto/BouncyCastle.csproj index 95d42bc8b..76da30095 100644 --- a/crypto/BouncyCastle.csproj +++ b/crypto/BouncyCastle.csproj @@ -252,6 +252,7 @@ + @@ -653,6 +654,7 @@ + @@ -693,6 +695,8 @@ + + @@ -809,6 +813,8 @@ + + @@ -825,6 +831,8 @@ + + @@ -895,6 +903,12 @@ + + + + + + @@ -933,6 +947,12 @@ + + + + + + @@ -944,6 +964,11 @@ + + + + + diff --git a/crypto/BouncyCastle.iOS.csproj b/crypto/BouncyCastle.iOS.csproj index f9cebdc86..52dae0f4f 100644 --- a/crypto/BouncyCastle.iOS.csproj +++ b/crypto/BouncyCastle.iOS.csproj @@ -253,6 +253,7 @@ + @@ -654,6 +655,7 @@ + @@ -694,6 +696,8 @@ + + @@ -810,6 +814,8 @@ + + @@ -826,6 +832,8 @@ + + @@ -896,6 +904,12 @@ + + + + + + @@ -934,6 +948,12 @@ + + + + + + @@ -945,6 +965,11 @@ + + + + + diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj index b6dfb3963..2ffb66d8c 100644 --- a/crypto/crypto.csproj +++ b/crypto/crypto.csproj @@ -1148,6 +1148,11 @@ SubType = "Code" BuildAction = "Compile" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -361,6 +371,30 @@ namespace Org.BouncyCastle.Security if (mechanism == null) mechanism = algorithm; + if (Platform.StartsWith(mechanism, "Ed")) + { + if (mechanism.Equals("Ed25519")) + { + return new Ed25519Signer(); + } + if (mechanism.Equals("Ed25519ctx")) + { + return new Ed25519ctxSigner(Arrays.EmptyBytes); + } + if (mechanism.Equals("Ed25519ph")) + { + return new Ed25519phSigner(Arrays.EmptyBytes); + } + if (mechanism.Equals("Ed448")) + { + return new Ed448Signer(Arrays.EmptyBytes); + } + if (mechanism.Equals("Ed448ph")) + { + return new Ed448phSigner(Arrays.EmptyBytes); + } + } + if (mechanism.Equals("RSA")) { return (new RsaDigestSigner(new NullDigest(), (AlgorithmIdentifier)null)); diff --git a/crypto/src/x509/SubjectPublicKeyInfoFactory.cs b/crypto/src/x509/SubjectPublicKeyInfoFactory.cs index 7614321d4..fca5da3f5 100644 --- a/crypto/src/x509/SubjectPublicKeyInfoFactory.cs +++ b/crypto/src/x509/SubjectPublicKeyInfoFactory.cs @@ -3,6 +3,7 @@ using System; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.EdEC; using Org.BouncyCastle.Asn1.Oiw; using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Asn1.X509; @@ -26,20 +27,20 @@ namespace Org.BouncyCastle.X509 /// /// Create a Subject Public Key Info object for a given public key. /// - /// One of ElGammalPublicKeyParameters, DSAPublicKeyParameter, DHPublicKeyParameters, RsaKeyParameters or ECPublicKeyParameters + /// One of ElGammalPublicKeyParameters, DSAPublicKeyParameter, DHPublicKeyParameters, RsaKeyParameters or ECPublicKeyParameters /// A subject public key info object. /// Throw exception if object provided is not one of the above. public static SubjectPublicKeyInfo CreateSubjectPublicKeyInfo( - AsymmetricKeyParameter key) + AsymmetricKeyParameter publicKey) { - if (key == null) - throw new ArgumentNullException("key"); - if (key.IsPrivate) - throw new ArgumentException("Private key passed - public key expected.", "key"); + if (publicKey == null) + throw new ArgumentNullException("publicKey"); + if (publicKey.IsPrivate) + throw new ArgumentException("Private key passed - public key expected.", "publicKey"); - if (key is ElGamalPublicKeyParameters) + if (publicKey is ElGamalPublicKeyParameters) { - ElGamalPublicKeyParameters _key = (ElGamalPublicKeyParameters)key; + ElGamalPublicKeyParameters _key = (ElGamalPublicKeyParameters)publicKey; ElGamalParameters kp = _key.Parameters; SubjectPublicKeyInfo info = new SubjectPublicKeyInfo( @@ -51,9 +52,9 @@ namespace Org.BouncyCastle.X509 return info; } - if (key is DsaPublicKeyParameters) + if (publicKey is DsaPublicKeyParameters) { - DsaPublicKeyParameters _key = (DsaPublicKeyParameters) key; + DsaPublicKeyParameters _key = (DsaPublicKeyParameters) publicKey; DsaParameters kp = _key.Parameters; Asn1Encodable ae = kp == null ? null @@ -64,9 +65,9 @@ namespace Org.BouncyCastle.X509 new DerInteger(_key.Y)); } - if (key is DHPublicKeyParameters) + if (publicKey is DHPublicKeyParameters) { - DHPublicKeyParameters _key = (DHPublicKeyParameters) key; + DHPublicKeyParameters _key = (DHPublicKeyParameters) publicKey; DHParameters kp = _key.Parameters; SubjectPublicKeyInfo info = new SubjectPublicKeyInfo( @@ -78,9 +79,9 @@ namespace Org.BouncyCastle.X509 return info; } // End of DH - if (key is RsaKeyParameters) + if (publicKey is RsaKeyParameters) { - RsaKeyParameters _key = (RsaKeyParameters) key; + RsaKeyParameters _key = (RsaKeyParameters) publicKey; SubjectPublicKeyInfo info = new SubjectPublicKeyInfo( new AlgorithmIdentifier(PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance), @@ -89,9 +90,9 @@ namespace Org.BouncyCastle.X509 return info; } // End of RSA. - if (key is ECPublicKeyParameters) + if (publicKey is ECPublicKeyParameters) { - ECPublicKeyParameters _key = (ECPublicKeyParameters) key; + ECPublicKeyParameters _key = (ECPublicKeyParameters) publicKey; if (_key.AlgorithmName == "ECGOST3410") { @@ -139,9 +140,9 @@ namespace Org.BouncyCastle.X509 } } // End of EC - if (key is Gost3410PublicKeyParameters) + if (publicKey is Gost3410PublicKeyParameters) { - Gost3410PublicKeyParameters _key = (Gost3410PublicKeyParameters) key; + Gost3410PublicKeyParameters _key = (Gost3410PublicKeyParameters) publicKey; if (_key.PublicKeyParamSet == null) throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set"); @@ -164,7 +165,35 @@ namespace Org.BouncyCastle.X509 return new SubjectPublicKeyInfo(algID, new DerOctetString(keyBytes)); } - throw new ArgumentException("Class provided no convertible: " + Platform.GetTypeName(key)); + if (publicKey is X448PublicKeyParameters) + { + X448PublicKeyParameters key = (X448PublicKeyParameters)publicKey; + + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X448), key.GetEncoded()); + } + + if (publicKey is X25519PublicKeyParameters) + { + X25519PublicKeyParameters key = (X25519PublicKeyParameters)publicKey; + + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519), key.GetEncoded()); + } + + if (publicKey is Ed448PublicKeyParameters) + { + Ed448PublicKeyParameters key = (Ed448PublicKeyParameters)publicKey; + + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed448), key.GetEncoded()); + } + + if (publicKey is Ed25519PublicKeyParameters) + { + Ed25519PublicKeyParameters key = (Ed25519PublicKeyParameters)publicKey; + + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519), key.GetEncoded()); + } + + throw new ArgumentException("Class provided no convertible: " + Platform.GetTypeName(publicKey)); } private static void ExtractBytes( diff --git a/crypto/test/UnitTests.csproj b/crypto/test/UnitTests.csproj index 5f0e7af57..bb046c2b6 100644 --- a/crypto/test/UnitTests.csproj +++ b/crypto/test/UnitTests.csproj @@ -101,6 +101,7 @@ + @@ -186,6 +187,8 @@ + + @@ -284,6 +287,8 @@ + + diff --git a/crypto/test/src/asn1/test/PrivateKeyInfoTest.cs b/crypto/test/src/asn1/test/PrivateKeyInfoTest.cs new file mode 100644 index 000000000..eb17a54c3 --- /dev/null +++ b/crypto/test/src/asn1/test/PrivateKeyInfoTest.cs @@ -0,0 +1,60 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Asn1.Tests +{ + [TestFixture] + public class PrivateKeyInfoTest + : SimpleTest + { + private static readonly byte[] priv = Base64.Decode( + "MC4CAQAwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC"); + + private static readonly byte[] privWithPub = Base64.Decode( + "MHICAQEwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC" + + "oB8wHQYKKoZIhvcNAQkJFDEPDA1DdXJkbGUgQ2hhaXJzgSEAGb9ECWmEzf6FQbrB" + + "Z9w7lshQhqowtrbLDFw4rXAxZuE="); + + public override string Name + { + get { return "PrivateKeyInfoTest"; } + } + + public override void PerformTest() + { + PrivateKeyInfo privInfo1 = PrivateKeyInfo.GetInstance(priv); + + IsTrue(!privInfo1.HasPublicKey); + + PrivateKeyInfo privInfo2 = new PrivateKeyInfo(privInfo1.PrivateKeyAlgorithm, privInfo1.ParsePrivateKey()); + + IsTrue("enc 1 failed", AreEqual(priv, privInfo2.GetEncoded())); + + privInfo1 = PrivateKeyInfo.GetInstance(privWithPub); + + IsTrue(privInfo1.HasPublicKey); + + privInfo2 = new PrivateKeyInfo(privInfo1.PrivateKeyAlgorithm, privInfo1.ParsePrivateKey(), privInfo1.Attributes, privInfo1.PublicKeyData.GetOctets()); + + IsTrue("enc 2 failed", AreEqual(privWithPub, privInfo2.GetEncoded())); + } + + public static void Main(string[] args) + { + RunTest(new PrivateKeyInfoTest()); + } + + [Test] + public void TestFunction() + { + string resultText = Perform().ToString(); + + Assert.AreEqual(Name + ": Okay", resultText); + } + } +} diff --git a/crypto/test/src/asn1/test/RegressionTest.cs b/crypto/test/src/asn1/test/RegressionTest.cs index 873ab4396..eeca9ccd0 100644 --- a/crypto/test/src/asn1/test/RegressionTest.cs +++ b/crypto/test/src/asn1/test/RegressionTest.cs @@ -51,6 +51,7 @@ namespace Org.BouncyCastle.Asn1.Tests new Pkcs10Test(), new Pkcs12Test(), new PkiFailureInfoTest(), + new PrivateKeyInfoTest(), new ProcurationSyntaxUnitTest(), new ProfessionInfoUnitTest(), new QCStatementUnitTest(), diff --git a/crypto/test/src/crypto/test/Ed25519Test.cs b/crypto/test/src/crypto/test/Ed25519Test.cs new file mode 100644 index 000000000..82e36d991 --- /dev/null +++ b/crypto/test/src/crypto/test/Ed25519Test.cs @@ -0,0 +1,111 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Signers; +using Org.BouncyCastle.Math.EC.Rfc8032; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Crypto.Tests +{ + [TestFixture] + public class Ed25519Test + : SimpleTest + { + private static readonly SecureRandom Random = new SecureRandom(); + + public override string Name + { + get { return "Ed25519"; } + } + + public static void Main(string[] args) + { + RunTest(new Ed25519Test()); + } + + [Test] + public void TestFunction() + { + string resultText = Perform().ToString(); + + Assert.AreEqual(Name + ": Okay", resultText); + } + + public override void PerformTest() + { + for (int i = 0; i < 10; ++i) + { + DoTestConsistency(Ed25519.Algorithm.Ed25519, null); + + byte[] context = RandomContext(Random.NextInt() & 255); + DoTestConsistency(Ed25519.Algorithm.Ed25519ctx, context); + DoTestConsistency(Ed25519.Algorithm.Ed25519ph, context); + } + } + + private ISigner CreateSigner(Ed25519.Algorithm algorithm, byte[] context) + { + switch (algorithm) + { + case Ed25519.Algorithm.Ed25519: + return new Ed25519Signer(); + case Ed25519.Algorithm.Ed25519ctx: + return new Ed25519ctxSigner(context); + case Ed25519.Algorithm.Ed25519ph: + return new Ed25519phSigner(context); + default: + throw new ArgumentException("algorithm"); + } + } + + private byte[] RandomContext(int length) + { + byte[] context = new byte[length]; + Random.NextBytes(context); + return context; + } + + private void DoTestConsistency(Ed25519.Algorithm algorithm, byte[] context) + { + Ed25519KeyPairGenerator kpg = new Ed25519KeyPairGenerator(); + kpg.Init(new Ed25519KeyGenerationParameters(Random)); + + AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair(); + Ed25519PrivateKeyParameters privateKey = (Ed25519PrivateKeyParameters)kp.Private; + Ed25519PublicKeyParameters publicKey = (Ed25519PublicKeyParameters)kp.Public; + + byte[] msg = new byte[Random.NextInt() & 255]; + Random.NextBytes(msg); + + ISigner signer = CreateSigner(algorithm, context); + signer.Init(true, privateKey); + signer.BlockUpdate(msg, 0, msg.Length); + byte[] signature = signer.GenerateSignature(); + + ISigner verifier = CreateSigner(algorithm, context); + verifier.Init(false, publicKey); + verifier.BlockUpdate(msg, 0, msg.Length); + bool shouldVerify = verifier.VerifySignature(signature); + + if (!shouldVerify) + { + Fail("Ed25519(" + algorithm + ") signature failed to verify"); + } + + signature[Random.Next() % signature.Length] ^= (byte)(1 << (Random.NextInt() & 7)); + + verifier.Init(false, publicKey); + verifier.BlockUpdate(msg, 0, msg.Length); + bool shouldNotVerify = verifier.VerifySignature(signature); + + if (shouldNotVerify) + { + Fail("Ed25519(" + algorithm + ") bad signature incorrectly verified"); + } + } + } +} diff --git a/crypto/test/src/crypto/test/Ed448Test.cs b/crypto/test/src/crypto/test/Ed448Test.cs new file mode 100644 index 000000000..b035f554e --- /dev/null +++ b/crypto/test/src/crypto/test/Ed448Test.cs @@ -0,0 +1,107 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Signers; +using Org.BouncyCastle.Math.EC.Rfc8032; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Crypto.Tests +{ + [TestFixture] + public class Ed448Test + : SimpleTest + { + private static readonly SecureRandom Random = new SecureRandom(); + + public override string Name + { + get { return "Ed448"; } + } + + public static void Main(string[] args) + { + RunTest(new Ed448Test()); + } + + [Test] + public void TestFunction() + { + string resultText = Perform().ToString(); + + Assert.AreEqual(Name + ": Okay", resultText); + } + + public override void PerformTest() + { + for (int i = 0; i < 10; ++i) + { + byte[] context = RandomContext(Random.NextInt() & 255); + DoTestConsistency(Ed448.Algorithm.Ed448, context); + DoTestConsistency(Ed448.Algorithm.Ed448ph, context); + } + } + + private ISigner CreateSigner(Ed448.Algorithm algorithm, byte[] context) + { + switch (algorithm) + { + case Ed448.Algorithm.Ed448: + return new Ed448Signer(context); + case Ed448.Algorithm.Ed448ph: + return new Ed448phSigner(context); + default: + throw new ArgumentException("algorithm"); + } + } + + private byte[] RandomContext(int length) + { + byte[] context = new byte[length]; + Random.NextBytes(context); + return context; + } + + private void DoTestConsistency(Ed448.Algorithm algorithm, byte[] context) + { + Ed448KeyPairGenerator kpg = new Ed448KeyPairGenerator(); + kpg.Init(new Ed448KeyGenerationParameters(Random)); + + AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair(); + Ed448PrivateKeyParameters privateKey = (Ed448PrivateKeyParameters)kp.Private; + Ed448PublicKeyParameters publicKey = (Ed448PublicKeyParameters)kp.Public; + + byte[] msg = new byte[Random.NextInt() & 255]; + Random.NextBytes(msg); + + ISigner signer = CreateSigner(algorithm, context); + signer.Init(true, privateKey); + signer.BlockUpdate(msg, 0, msg.Length); + byte[] signature = signer.GenerateSignature(); + + ISigner verifier = CreateSigner(algorithm, context); + verifier.Init(false, publicKey); + verifier.BlockUpdate(msg, 0, msg.Length); + bool shouldVerify = verifier.VerifySignature(signature); + + if (!shouldVerify) + { + Fail("Ed448(" + algorithm + ") signature failed to verify"); + } + + signature[Random.Next() % signature.Length] ^= (byte)(1 << (Random.NextInt() & 7)); + + verifier.Init(false, publicKey); + verifier.BlockUpdate(msg, 0, msg.Length); + bool shouldNotVerify = verifier.VerifySignature(signature); + + if (shouldNotVerify) + { + Fail("Ed448(" + algorithm + ") bad signature incorrectly verified"); + } + } + } +} diff --git a/crypto/test/src/crypto/test/RegressionTest.cs b/crypto/test/src/crypto/test/RegressionTest.cs index 13fe23ecc..18aa62d97 100644 --- a/crypto/test/src/crypto/test/RegressionTest.cs +++ b/crypto/test/src/crypto/test/RegressionTest.cs @@ -133,6 +133,10 @@ namespace Org.BouncyCastle.Crypto.Tests new SM2EngineTest(), new SM2KeyExchangeTest(), new SM2SignerTest(), + new X25519Test(), + new X448Test(), + new Ed25519Test(), + new Ed448Test(), }; public static void Main(string[] args) diff --git a/crypto/test/src/crypto/test/X25519Test.cs b/crypto/test/src/crypto/test/X25519Test.cs new file mode 100644 index 000000000..29466e0c6 --- /dev/null +++ b/crypto/test/src/crypto/test/X25519Test.cs @@ -0,0 +1,69 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Crypto.Agreement; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Crypto.Tests +{ + [TestFixture] + public class X25519Test + : SimpleTest + { + private static readonly SecureRandom Random = new SecureRandom(); + + public override string Name + { + get { return "X25519"; } + } + + public static void Main(string[] args) + { + RunTest(new X25519Test()); + } + + [Test] + public void TestFunction() + { + string resultText = Perform().ToString(); + + Assert.AreEqual(Name + ": Okay", resultText); + } + + public override void PerformTest() + { + for (int i = 0; i < 10; ++i) + { + DoTestAgreement(); + } + } + + private void DoTestAgreement() + { + IAsymmetricCipherKeyPairGenerator kpGen = new X25519KeyPairGenerator(); + kpGen.Init(new X25519KeyGenerationParameters(Random)); + + AsymmetricCipherKeyPair kpA = kpGen.GenerateKeyPair(); + AsymmetricCipherKeyPair kpB = kpGen.GenerateKeyPair(); + + X25519Agreement agreeA = new X25519Agreement(); + agreeA.Init(kpA.Private); + byte[] secretA = new byte[agreeA.AgreementSize]; + agreeA.CalculateAgreement(kpB.Public, secretA, 0); + + X25519Agreement agreeB = new X25519Agreement(); + agreeB.Init(kpB.Private); + byte[] secretB = new byte[agreeB.AgreementSize]; + agreeB.CalculateAgreement(kpA.Public, secretB, 0); + + if (!AreEqual(secretA, secretB)) + { + Fail("X25519 agreement failed"); + } + } + } +} diff --git a/crypto/test/src/crypto/test/X448Test.cs b/crypto/test/src/crypto/test/X448Test.cs new file mode 100644 index 000000000..5d4b14b63 --- /dev/null +++ b/crypto/test/src/crypto/test/X448Test.cs @@ -0,0 +1,69 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Crypto.Agreement; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Crypto.Tests +{ + [TestFixture] + public class X448Test + : SimpleTest + { + private static readonly SecureRandom Random = new SecureRandom(); + + public override string Name + { + get { return "X448"; } + } + + public static void Main(string[] args) + { + RunTest(new X448Test()); + } + + [Test] + public void TestFunction() + { + string resultText = Perform().ToString(); + + Assert.AreEqual(Name + ": Okay", resultText); + } + + public override void PerformTest() + { + for (int i = 0; i < 10; ++i) + { + DoTestAgreement(); + } + } + + private void DoTestAgreement() + { + IAsymmetricCipherKeyPairGenerator kpGen = new X448KeyPairGenerator(); + kpGen.Init(new X448KeyGenerationParameters(Random)); + + AsymmetricCipherKeyPair kpA = kpGen.GenerateKeyPair(); + AsymmetricCipherKeyPair kpB = kpGen.GenerateKeyPair(); + + X448Agreement agreeA = new X448Agreement(); + agreeA.Init(kpA.Private); + byte[] secretA = new byte[agreeA.AgreementSize]; + agreeA.CalculateAgreement(kpB.Public, secretA, 0); + + X448Agreement agreeB = new X448Agreement(); + agreeB.Init(kpB.Private); + byte[] secretB = new byte[agreeB.AgreementSize]; + agreeB.CalculateAgreement(kpA.Public, secretB, 0); + + if (!AreEqual(secretA, secretB)) + { + Fail("X448 agreement failed"); + } + } + } +} diff --git a/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs b/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs index 5a42daeae..8a61609af 100644 --- a/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs +++ b/crypto/test/src/math/ec/rfc8032/test/Ed25519Test.cs @@ -36,7 +36,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests Random.NextBytes(sk); Ed25519.GeneratePublicKey(sk, 0, pk, 0); - int mLen = Random.Next() & 255; + int mLen = Random.NextInt() & 255; Ed25519.Sign(sk, 0, m, 0, mLen, sig1, 0); Ed25519.Sign(sk, 0, pk, 0, m, 0, mLen, sig2, 0); @@ -59,7 +59,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests { byte[] sk = new byte[Ed25519.SecretKeySize]; byte[] pk = new byte[Ed25519.PublicKeySize]; - byte[] ctx = new byte[Random.Next() & 7]; + byte[] ctx = new byte[Random.NextInt() & 7]; byte[] m = new byte[255]; byte[] sig1 = new byte[Ed25519.SignatureSize]; byte[] sig2 = new byte[Ed25519.SignatureSize]; @@ -72,7 +72,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests Random.NextBytes(sk); Ed25519.GeneratePublicKey(sk, 0, pk, 0); - int mLen = Random.Next() & 255; + int mLen = Random.NextInt() & 255; Ed25519.Sign(sk, 0, ctx, m, 0, mLen, sig1, 0); Ed25519.Sign(sk, 0, pk, 0, ctx, m, 0, mLen, sig2, 0); @@ -95,7 +95,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests { byte[] sk = new byte[Ed25519.SecretKeySize]; byte[] pk = new byte[Ed25519.PublicKeySize]; - byte[] ctx = new byte[Random.Next() & 7]; + byte[] ctx = new byte[Random.NextInt() & 7]; byte[] m = new byte[255]; byte[] ph = new byte[Ed25519.PrehashSize]; byte[] sig1 = new byte[Ed25519.SignatureSize]; @@ -109,7 +109,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests Random.NextBytes(sk); Ed25519.GeneratePublicKey(sk, 0, pk, 0); - int mLen = Random.Next() & 255; + int mLen = Random.NextInt() & 255; IDigest prehash = Ed25519.CreatePrehash(); prehash.BlockUpdate(m, 0, mLen); diff --git a/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs b/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs index 826f76345..cc8e82de0 100644 --- a/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs +++ b/crypto/test/src/math/ec/rfc8032/test/Ed448Test.cs @@ -25,7 +25,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests { byte[] sk = new byte[Ed448.SecretKeySize]; byte[] pk = new byte[Ed448.PublicKeySize]; - byte[] ctx = new byte[Random.Next() & 7]; + byte[] ctx = new byte[Random.NextInt() & 7]; byte[] m = new byte[255]; byte[] sig1 = new byte[Ed448.SignatureSize]; byte[] sig2 = new byte[Ed448.SignatureSize]; @@ -38,7 +38,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests Random.NextBytes(sk); Ed448.GeneratePublicKey(sk, 0, pk, 0); - int mLen = Random.Next() & 255; + int mLen = Random.NextInt() & 255; Ed448.Sign(sk, 0, ctx, m, 0, mLen, sig1, 0); Ed448.Sign(sk, 0, pk, 0, ctx, m, 0, mLen, sig2, 0); @@ -61,7 +61,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests { byte[] sk = new byte[Ed448.SecretKeySize]; byte[] pk = new byte[Ed448.PublicKeySize]; - byte[] ctx = new byte[Random.Next() & 7]; + byte[] ctx = new byte[Random.NextInt() & 7]; byte[] m = new byte[255]; byte[] ph = new byte[Ed448.PrehashSize]; byte[] sig1 = new byte[Ed448.SignatureSize]; @@ -75,7 +75,7 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032.Tests Random.NextBytes(sk); Ed448.GeneratePublicKey(sk, 0, pk, 0); - int mLen = Random.Next() & 255; + int mLen = Random.NextInt() & 255; IXof prehash = Ed448.CreatePrehash(); prehash.BlockUpdate(m, 0, mLen); diff --git a/crypto/test/src/security/test/TestSignerUtil.cs b/crypto/test/src/security/test/TestSignerUtil.cs index f2ee4b048..dc3c1c81b 100644 --- a/crypto/test/src/security/test/TestSignerUtil.cs +++ b/crypto/test/src/security/test/TestSignerUtil.cs @@ -94,6 +94,14 @@ namespace Org.BouncyCastle.Security.Tests AsymmetricCipherKeyPair ecGostPair = ecGostKpg.GenerateKeyPair(); + IAsymmetricCipherKeyPairGenerator ed25519Kpg = GeneratorUtilities.GetKeyPairGenerator("Ed25519"); + ed25519Kpg.Init(new Ed25519KeyGenerationParameters(new SecureRandom())); + AsymmetricCipherKeyPair ed25519Pair = ed25519Kpg.GenerateKeyPair(); + + IAsymmetricCipherKeyPairGenerator ed448Kpg = GeneratorUtilities.GetKeyPairGenerator("Ed448"); + ed448Kpg.Init(new Ed448KeyGenerationParameters(new SecureRandom())); + AsymmetricCipherKeyPair ed448Pair = ed448Kpg.GenerateKeyPair(); + // // GOST3410 parameters // @@ -147,6 +155,16 @@ namespace Org.BouncyCastle.Security.Tests signParams = ecGostPair.Private; verifyParams = ecGostPair.Public; } + else if (cipherName == "ED25519") + { + signParams = ed25519Pair.Private; + verifyParams = ed25519Pair.Public; + } + else if (cipherName == "ED448") + { + signParams = ed448Pair.Private; + verifyParams = ed448Pair.Public; + } else if (cipherName == "GOST3410") { signParams = gostPair.Private; -- cgit 1.4.1