diff --git a/crypto/src/crypto/IRawAgreement.cs b/crypto/src/crypto/IRawAgreement.cs
new file mode 100644
index 000000000..63e664888
--- /dev/null
+++ b/crypto/src/crypto/IRawAgreement.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+ public interface IRawAgreement
+ {
+ void Init(ICipherParameters parameters);
+
+ int AgreementSize { get; }
+
+ void CalculateAgreement(ICipherParameters publicKey, byte[] buf, int off);
+ }
+}
diff --git a/crypto/src/crypto/agreement/X25519Agreement.cs b/crypto/src/crypto/agreement/X25519Agreement.cs
new file mode 100644
index 000000000..7e5890c16
--- /dev/null
+++ b/crypto/src/crypto/agreement/X25519Agreement.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+ public sealed class X25519Agreement
+ : IRawAgreement
+ {
+ private X25519PrivateKeyParameters privateKey;
+
+ public void Init(ICipherParameters parameters)
+ {
+ this.privateKey = (X25519PrivateKeyParameters)parameters;
+ }
+
+ public int AgreementSize
+ {
+ get { return X25519PrivateKeyParameters.SecretSize; }
+ }
+
+ public void CalculateAgreement(ICipherParameters publicKey, byte[] buf, int off)
+ {
+ privateKey.GenerateSecret((X25519PublicKeyParameters)publicKey, buf, off);
+ }
+ }
+}
diff --git a/crypto/src/crypto/agreement/X448Agreement.cs b/crypto/src/crypto/agreement/X448Agreement.cs
new file mode 100644
index 000000000..26f608c26
--- /dev/null
+++ b/crypto/src/crypto/agreement/X448Agreement.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+ public sealed class X448Agreement
+ : IRawAgreement
+ {
+ private X448PrivateKeyParameters privateKey;
+
+ public void Init(ICipherParameters parameters)
+ {
+ this.privateKey = (X448PrivateKeyParameters)parameters;
+ }
+
+ public int AgreementSize
+ {
+ get { return X448PrivateKeyParameters.SecretSize; }
+ }
+
+ public void CalculateAgreement(ICipherParameters publicKey, byte[] buf, int off)
+ {
+ privateKey.GenerateSecret((X448PublicKeyParameters)publicKey, buf, off);
+ }
+ }
+}
diff --git a/crypto/src/crypto/generators/Ed25519KeyPairGenerator.cs b/crypto/src/crypto/generators/Ed25519KeyPairGenerator.cs
new file mode 100644
index 000000000..266d111cf
--- /dev/null
+++ b/crypto/src/crypto/generators/Ed25519KeyPairGenerator.cs
@@ -0,0 +1,25 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class Ed25519KeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private SecureRandom random;
+
+ public virtual void Init(KeyGenerationParameters parameters)
+ {
+ this.random = parameters.Random;
+ }
+
+ public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ Ed25519PrivateKeyParameters privateKey = new Ed25519PrivateKeyParameters(random);
+ Ed25519PublicKeyParameters publicKey = privateKey.GeneratePublicKey();
+ return new AsymmetricCipherKeyPair(publicKey, privateKey);
+ }
+ }
+}
diff --git a/crypto/src/crypto/generators/Ed448KeyPairGenerator.cs b/crypto/src/crypto/generators/Ed448KeyPairGenerator.cs
new file mode 100644
index 000000000..50aee631e
--- /dev/null
+++ b/crypto/src/crypto/generators/Ed448KeyPairGenerator.cs
@@ -0,0 +1,25 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class Ed448KeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private SecureRandom random;
+
+ public virtual void Init(KeyGenerationParameters parameters)
+ {
+ this.random = parameters.Random;
+ }
+
+ public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ Ed448PrivateKeyParameters privateKey = new Ed448PrivateKeyParameters(random);
+ Ed448PublicKeyParameters publicKey = privateKey.GeneratePublicKey();
+ return new AsymmetricCipherKeyPair(publicKey, privateKey);
+ }
+ }
+}
diff --git a/crypto/src/crypto/generators/X25519KeyPairGenerator.cs b/crypto/src/crypto/generators/X25519KeyPairGenerator.cs
new file mode 100644
index 000000000..94378448b
--- /dev/null
+++ b/crypto/src/crypto/generators/X25519KeyPairGenerator.cs
@@ -0,0 +1,25 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class X25519KeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private SecureRandom random;
+
+ public virtual void Init(KeyGenerationParameters parameters)
+ {
+ this.random = parameters.Random;
+ }
+
+ public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ X25519PrivateKeyParameters privateKey = new X25519PrivateKeyParameters(random);
+ X25519PublicKeyParameters publicKey = privateKey.GeneratePublicKey();
+ return new AsymmetricCipherKeyPair(publicKey, privateKey);
+ }
+ }
+}
diff --git a/crypto/src/crypto/generators/X448KeyPairGenerator.cs b/crypto/src/crypto/generators/X448KeyPairGenerator.cs
new file mode 100644
index 000000000..4a203e4f1
--- /dev/null
+++ b/crypto/src/crypto/generators/X448KeyPairGenerator.cs
@@ -0,0 +1,25 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+ public class X448KeyPairGenerator
+ : IAsymmetricCipherKeyPairGenerator
+ {
+ private SecureRandom random;
+
+ public virtual void Init(KeyGenerationParameters parameters)
+ {
+ this.random = parameters.Random;
+ }
+
+ public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+ {
+ X448PrivateKeyParameters privateKey = new X448PrivateKeyParameters(random);
+ X448PublicKeyParameters publicKey = privateKey.GeneratePublicKey();
+ return new AsymmetricCipherKeyPair(publicKey, privateKey);
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/Ed25519KeyGenerationParameters.cs b/crypto/src/crypto/parameters/Ed25519KeyGenerationParameters.cs
new file mode 100644
index 000000000..daf3856c3
--- /dev/null
+++ b/crypto/src/crypto/parameters/Ed25519KeyGenerationParameters.cs
@@ -0,0 +1,15 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class Ed25519KeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ public Ed25519KeyGenerationParameters(SecureRandom random)
+ : base(random, 256)
+ {
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/Ed25519PrivateKeyParameters.cs b/crypto/src/crypto/parameters/Ed25519PrivateKeyParameters.cs
new file mode 100644
index 000000000..97902e093
--- /dev/null
+++ b/crypto/src/crypto/parameters/Ed25519PrivateKeyParameters.cs
@@ -0,0 +1,98 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public sealed class Ed25519PrivateKeyParameters
+ : AsymmetricKeyParameter
+ {
+ public static readonly int KeySize = Ed25519.SecretKeySize;
+ public static readonly int SignatureSize = Ed25519.SignatureSize;
+
+ private readonly byte[] data = new byte[KeySize];
+
+ public Ed25519PrivateKeyParameters(SecureRandom random)
+ : base(true)
+ {
+ random.NextBytes(data);
+ }
+
+ public Ed25519PrivateKeyParameters(byte[] buf, int off)
+ : base(true)
+ {
+ Array.Copy(buf, off, data, 0, KeySize);
+ }
+
+ public Ed25519PrivateKeyParameters(Stream input)
+ : base(true)
+ {
+ if (KeySize != Streams.ReadFully(input, data))
+ throw new EndOfStreamException("EOF encountered in middle of Ed25519 private key");
+ }
+
+ public void Encode(byte[] buf, int off)
+ {
+ Array.Copy(data, 0, buf, off, KeySize);
+ }
+
+ public byte[] GetEncoded()
+ {
+ return Arrays.Clone(data);
+ }
+
+ public Ed25519PublicKeyParameters GeneratePublicKey()
+ {
+ byte[] publicKey = new byte[Ed25519.PublicKeySize];
+ Ed25519.GeneratePublicKey(data, 0, publicKey, 0);
+ return new Ed25519PublicKeyParameters(publicKey, 0);
+ }
+
+ public void Sign(Ed25519.Algorithm algorithm, Ed25519PublicKeyParameters publicKey, byte[] ctx, byte[] msg, int msgOff, int msgLen,
+ byte[] sig, int sigOff)
+ {
+ byte[] pk = new byte[Ed25519.PublicKeySize];
+ if (null == publicKey)
+ {
+ Ed25519.GeneratePublicKey(data, 0, pk, 0);
+ }
+ else
+ {
+ publicKey.Encode(pk, 0);
+ }
+
+ switch (algorithm)
+ {
+ case Ed25519.Algorithm.Ed25519:
+ {
+ if (null != ctx)
+ throw new ArgumentException("ctx");
+
+ Ed25519.Sign(data, 0, pk, 0, msg, msgOff, msgLen, sig, sigOff);
+ break;
+ }
+ case Ed25519.Algorithm.Ed25519ctx:
+ {
+ Ed25519.Sign(data, 0, pk, 0, ctx, msg, msgOff, msgLen, sig, sigOff);
+ break;
+ }
+ case Ed25519.Algorithm.Ed25519ph:
+ {
+ if (Ed25519.PrehashSize != msgLen)
+ throw new ArgumentException("msgLen");
+
+ Ed25519.SignPrehash(data, 0, pk, 0, ctx, msg, msgOff, sig, sigOff);
+ break;
+ }
+ default:
+ {
+ throw new ArgumentException("algorithm");
+ }
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/Ed25519PublicKeyParameters.cs b/crypto/src/crypto/parameters/Ed25519PublicKeyParameters.cs
new file mode 100644
index 000000000..96e9ec21f
--- /dev/null
+++ b/crypto/src/crypto/parameters/Ed25519PublicKeyParameters.cs
@@ -0,0 +1,40 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public sealed class Ed25519PublicKeyParameters
+ : AsymmetricKeyParameter
+ {
+ public static readonly int KeySize = Ed25519.PublicKeySize;
+
+ private readonly byte[] data = new byte[KeySize];
+
+ public Ed25519PublicKeyParameters(byte[] buf, int off)
+ : base(false)
+ {
+ Array.Copy(buf, off, data, 0, KeySize);
+ }
+
+ public Ed25519PublicKeyParameters(Stream input)
+ : base(false)
+ {
+ if (KeySize != Streams.ReadFully(input, data))
+ throw new EndOfStreamException("EOF encountered in middle of Ed25519 public key");
+ }
+
+ public void Encode(byte[] buf, int off)
+ {
+ Array.Copy(data, 0, buf, off, KeySize);
+ }
+
+ public byte[] GetEncoded()
+ {
+ return Arrays.Clone(data);
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/Ed448KeyGenerationParameters.cs b/crypto/src/crypto/parameters/Ed448KeyGenerationParameters.cs
new file mode 100644
index 000000000..830d15a04
--- /dev/null
+++ b/crypto/src/crypto/parameters/Ed448KeyGenerationParameters.cs
@@ -0,0 +1,15 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class Ed448KeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ public Ed448KeyGenerationParameters(SecureRandom random)
+ : base(random, 448)
+ {
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/Ed448PrivateKeyParameters.cs b/crypto/src/crypto/parameters/Ed448PrivateKeyParameters.cs
new file mode 100644
index 000000000..74b5d63f3
--- /dev/null
+++ b/crypto/src/crypto/parameters/Ed448PrivateKeyParameters.cs
@@ -0,0 +1,90 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public sealed class Ed448PrivateKeyParameters
+ : AsymmetricKeyParameter
+ {
+ public static readonly int KeySize = Ed448.SecretKeySize;
+ public static readonly int SignatureSize = Ed448.SignatureSize;
+
+ private readonly byte[] data = new byte[KeySize];
+
+ public Ed448PrivateKeyParameters(SecureRandom random)
+ : base(true)
+ {
+ random.NextBytes(data);
+ }
+
+ public Ed448PrivateKeyParameters(byte[] buf, int off)
+ : base(true)
+ {
+ Array.Copy(buf, off, data, 0, KeySize);
+ }
+
+ public Ed448PrivateKeyParameters(Stream input)
+ : base(true)
+ {
+ if (KeySize != Streams.ReadFully(input, data))
+ throw new EndOfStreamException("EOF encountered in middle of Ed448 private key");
+ }
+
+ public void Encode(byte[] buf, int off)
+ {
+ Array.Copy(data, 0, buf, off, KeySize);
+ }
+
+ public byte[] GetEncoded()
+ {
+ return Arrays.Clone(data);
+ }
+
+ public Ed448PublicKeyParameters GeneratePublicKey()
+ {
+ byte[] publicKey = new byte[Ed448.PublicKeySize];
+ Ed448.GeneratePublicKey(data, 0, publicKey, 0);
+ return new Ed448PublicKeyParameters(publicKey, 0);
+ }
+
+ public void Sign(Ed448.Algorithm algorithm, Ed448PublicKeyParameters publicKey, byte[] ctx, byte[] msg, int msgOff, int msgLen,
+ byte[] sig, int sigOff)
+ {
+ byte[] pk = new byte[Ed448.PublicKeySize];
+ if (null == publicKey)
+ {
+ Ed448.GeneratePublicKey(data, 0, pk, 0);
+ }
+ else
+ {
+ publicKey.Encode(pk, 0);
+ }
+
+ switch (algorithm)
+ {
+ case Ed448.Algorithm.Ed448:
+ {
+ Ed448.Sign(data, 0, pk, 0, ctx, msg, msgOff, msgLen, sig, sigOff);
+ break;
+ }
+ case Ed448.Algorithm.Ed448ph:
+ {
+ if (Ed448.PrehashSize != msgLen)
+ throw new ArgumentException("msgLen");
+
+ Ed448.SignPrehash(data, 0, pk, 0, ctx, msg, msgOff, sig, sigOff);
+ break;
+ }
+ default:
+ {
+ throw new ArgumentException("algorithm");
+ }
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/Ed448PublicKeyParameters.cs b/crypto/src/crypto/parameters/Ed448PublicKeyParameters.cs
new file mode 100644
index 000000000..d7faac246
--- /dev/null
+++ b/crypto/src/crypto/parameters/Ed448PublicKeyParameters.cs
@@ -0,0 +1,40 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public sealed class Ed448PublicKeyParameters
+ : AsymmetricKeyParameter
+ {
+ public static readonly int KeySize = Ed448.PublicKeySize;
+
+ private readonly byte[] data = new byte[KeySize];
+
+ public Ed448PublicKeyParameters(byte[] buf, int off)
+ : base(false)
+ {
+ Array.Copy(buf, off, data, 0, KeySize);
+ }
+
+ public Ed448PublicKeyParameters(Stream input)
+ : base(false)
+ {
+ if (KeySize != Streams.ReadFully(input, data))
+ throw new EndOfStreamException("EOF encountered in middle of Ed448 public key");
+ }
+
+ public void Encode(byte[] buf, int off)
+ {
+ Array.Copy(data, 0, buf, off, KeySize);
+ }
+
+ public byte[] GetEncoded()
+ {
+ return Arrays.Clone(data);
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/X25519KeyGenerationParameters.cs b/crypto/src/crypto/parameters/X25519KeyGenerationParameters.cs
new file mode 100644
index 000000000..09972c7a2
--- /dev/null
+++ b/crypto/src/crypto/parameters/X25519KeyGenerationParameters.cs
@@ -0,0 +1,15 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class X25519KeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ public X25519KeyGenerationParameters(SecureRandom random)
+ : base(random, 256)
+ {
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/X25519PrivateKeyParameters.cs b/crypto/src/crypto/parameters/X25519PrivateKeyParameters.cs
new file mode 100644
index 000000000..c25ab9364
--- /dev/null
+++ b/crypto/src/crypto/parameters/X25519PrivateKeyParameters.cs
@@ -0,0 +1,62 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc7748;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public sealed class X25519PrivateKeyParameters
+ : AsymmetricKeyParameter
+ {
+ public static readonly int KeySize = X25519.ScalarSize;
+ public static readonly int SecretSize = X25519.PointSize;
+
+ private readonly byte[] data = new byte[KeySize];
+
+ public X25519PrivateKeyParameters(SecureRandom random)
+ : base(true)
+ {
+ random.NextBytes(data);
+ }
+
+ public X25519PrivateKeyParameters(byte[] buf, int off)
+ : base(true)
+ {
+ Array.Copy(buf, off, data, 0, KeySize);
+ }
+
+ public X25519PrivateKeyParameters(Stream input)
+ : base(true)
+ {
+ if (KeySize != Streams.ReadFully(input, data))
+ throw new EndOfStreamException("EOF encountered in middle of X25519 private key");
+ }
+
+ public void Encode(byte[] buf, int off)
+ {
+ Array.Copy(data, 0, buf, off, KeySize);
+ }
+
+ public byte[] GetEncoded()
+ {
+ return Arrays.Clone(data);
+ }
+
+ public X25519PublicKeyParameters GeneratePublicKey()
+ {
+ byte[] publicKey = new byte[X25519.PointSize];
+ X25519.ScalarMultBase(data, 0, publicKey, 0);
+ return new X25519PublicKeyParameters(publicKey, 0);
+ }
+
+ public void GenerateSecret(X25519PublicKeyParameters publicKey, byte[] buf, int off)
+ {
+ byte[] encoded = new byte[X25519.PointSize];
+ publicKey.Encode(encoded, 0);
+ X25519.ScalarMult(data, 0, encoded, 0, buf, off);
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/X25519PublicKeyParameters.cs b/crypto/src/crypto/parameters/X25519PublicKeyParameters.cs
new file mode 100644
index 000000000..7df5f624d
--- /dev/null
+++ b/crypto/src/crypto/parameters/X25519PublicKeyParameters.cs
@@ -0,0 +1,40 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc7748;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public sealed class X25519PublicKeyParameters
+ : AsymmetricKeyParameter
+ {
+ public static readonly int KeySize = X25519.PointSize;
+
+ private readonly byte[] data = new byte[KeySize];
+
+ public X25519PublicKeyParameters(byte[] buf, int off)
+ : base(false)
+ {
+ Array.Copy(buf, off, data, 0, KeySize);
+ }
+
+ public X25519PublicKeyParameters(Stream input)
+ : base(false)
+ {
+ if (KeySize != Streams.ReadFully(input, data))
+ throw new EndOfStreamException("EOF encountered in middle of X25519 public key");
+ }
+
+ public void Encode(byte[] buf, int off)
+ {
+ Array.Copy(data, 0, buf, off, KeySize);
+ }
+
+ public byte[] GetEncoded()
+ {
+ return Arrays.Clone(data);
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/X448KeyGenerationParameters.cs b/crypto/src/crypto/parameters/X448KeyGenerationParameters.cs
new file mode 100644
index 000000000..a7cb55844
--- /dev/null
+++ b/crypto/src/crypto/parameters/X448KeyGenerationParameters.cs
@@ -0,0 +1,15 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public class X448KeyGenerationParameters
+ : KeyGenerationParameters
+ {
+ public X448KeyGenerationParameters(SecureRandom random)
+ : base(random, 448)
+ {
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/X448PrivateKeyParameters.cs b/crypto/src/crypto/parameters/X448PrivateKeyParameters.cs
new file mode 100644
index 000000000..291eac10f
--- /dev/null
+++ b/crypto/src/crypto/parameters/X448PrivateKeyParameters.cs
@@ -0,0 +1,62 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc7748;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public sealed class X448PrivateKeyParameters
+ : AsymmetricKeyParameter
+ {
+ public static readonly int KeySize = X448.ScalarSize;
+ public static readonly int SecretSize = X448.PointSize;
+
+ private readonly byte[] data = new byte[KeySize];
+
+ public X448PrivateKeyParameters(SecureRandom random)
+ : base(true)
+ {
+ random.NextBytes(data);
+ }
+
+ public X448PrivateKeyParameters(byte[] buf, int off)
+ : base(true)
+ {
+ Array.Copy(buf, off, data, 0, KeySize);
+ }
+
+ public X448PrivateKeyParameters(Stream input)
+ : base(true)
+ {
+ if (KeySize != Streams.ReadFully(input, data))
+ throw new EndOfStreamException("EOF encountered in middle of X448 private key");
+ }
+
+ public void Encode(byte[] buf, int off)
+ {
+ Array.Copy(data, 0, buf, off, KeySize);
+ }
+
+ public byte[] GetEncoded()
+ {
+ return Arrays.Clone(data);
+ }
+
+ public X448PublicKeyParameters GeneratePublicKey()
+ {
+ byte[] publicKey = new byte[X448.PointSize];
+ X448.ScalarMultBase(data, 0, publicKey, 0);
+ return new X448PublicKeyParameters(publicKey, 0);
+ }
+
+ public void GenerateSecret(X448PublicKeyParameters publicKey, byte[] buf, int off)
+ {
+ byte[] encoded = new byte[X448.PointSize];
+ publicKey.Encode(encoded, 0);
+ X448.ScalarMult(data, 0, encoded, 0, buf, off);
+ }
+ }
+}
diff --git a/crypto/src/crypto/parameters/X448PublicKeyParameters.cs b/crypto/src/crypto/parameters/X448PublicKeyParameters.cs
new file mode 100644
index 000000000..6c566ddf2
--- /dev/null
+++ b/crypto/src/crypto/parameters/X448PublicKeyParameters.cs
@@ -0,0 +1,40 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math.EC.Rfc7748;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+ public sealed class X448PublicKeyParameters
+ : AsymmetricKeyParameter
+ {
+ public static readonly int KeySize = X448.PointSize;
+
+ private readonly byte[] data = new byte[KeySize];
+
+ public X448PublicKeyParameters(byte[] buf, int off)
+ : base(false)
+ {
+ Array.Copy(buf, off, data, 0, KeySize);
+ }
+
+ public X448PublicKeyParameters(Stream input)
+ : base(false)
+ {
+ if (KeySize != Streams.ReadFully(input, data))
+ throw new EndOfStreamException("EOF encountered in middle of X448 public key");
+ }
+
+ public void Encode(byte[] buf, int off)
+ {
+ Array.Copy(data, 0, buf, off, KeySize);
+ }
+
+ public byte[] GetEncoded()
+ {
+ return Arrays.Clone(data);
+ }
+ }
+}
diff --git a/crypto/src/crypto/signers/Ed25519Signer.cs b/crypto/src/crypto/signers/Ed25519Signer.cs
new file mode 100644
index 000000000..904450ed1
--- /dev/null
+++ b/crypto/src/crypto/signers/Ed25519Signer.cs
@@ -0,0 +1,128 @@
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class Ed25519Signer
+ : ISigner
+ {
+ private readonly Buffer buffer = new Buffer();
+
+ private bool forSigning;
+ private Ed25519PrivateKeyParameters privateKey;
+ private Ed25519PublicKeyParameters publicKey;
+
+ public Ed25519Signer()
+ {
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Ed25519"; }
+ }
+
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ if (forSigning)
+ {
+ // TODO Allow IAsymmetricCipherKeyPair to be an ICipherParameters?
+
+ this.privateKey = (Ed25519PrivateKeyParameters)parameters;
+ this.publicKey = privateKey.GeneratePublicKey();
+ }
+ else
+ {
+ this.privateKey = null;
+ this.publicKey = (Ed25519PublicKeyParameters)parameters;
+ }
+
+ Reset();
+ }
+
+ public virtual void Update(byte b)
+ {
+ buffer.WriteByte(b);
+ }
+
+ public virtual void BlockUpdate(byte[] buf, int off, int len)
+ {
+ buffer.Write(buf, off, len);
+ }
+
+ public virtual byte[] GenerateSignature()
+ {
+ if (!forSigning)
+ throw new InvalidOperationException("Ed25519Signer not initialised for signature generation.");
+
+ return buffer.GenerateSignature(privateKey, publicKey);
+ }
+
+ public virtual bool VerifySignature(byte[] signature)
+ {
+ if (forSigning)
+ throw new InvalidOperationException("Ed25519Signer not initialised for verification");
+
+ return buffer.VerifySignature(publicKey, signature);
+ }
+
+ public virtual void Reset()
+ {
+ buffer.Reset();
+ }
+
+ private class Buffer : MemoryStream
+ {
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ internal byte[] GenerateSignature(Ed25519PrivateKeyParameters privateKey, Ed25519PublicKeyParameters publicKey)
+ {
+#if PORTABLE
+ byte[] buf = ToArray();
+ int count = buf.Length;
+#else
+ byte[] buf = GetBuffer();
+ int count = (int)Position;
+#endif
+ byte[] signature = new byte[Ed25519PrivateKeyParameters.SignatureSize];
+ privateKey.Sign(Ed25519.Algorithm.Ed25519, publicKey, null, buf, 0, count, signature, 0);
+ Reset();
+ return signature;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ internal bool VerifySignature(Ed25519PublicKeyParameters publicKey, byte[] signature)
+ {
+#if PORTABLE
+ byte[] buf = ToArray();
+ int count = buf.Length;
+#else
+ byte[] buf = GetBuffer();
+ int count = (int)Position;
+#endif
+ byte[] pk = publicKey.GetEncoded();
+ bool result = Ed25519.Verify(signature, 0, pk, 0, buf, 0, count);
+ Reset();
+ return result;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ internal void Reset()
+ {
+#if PORTABLE
+ this.Position = 0L;
+
+ // TODO Clear using Write method
+#else
+ Array.Clear(GetBuffer(), 0, (int)Position);
+#endif
+ this.Position = 0L;
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/signers/Ed25519ctxSigner.cs b/crypto/src/crypto/signers/Ed25519ctxSigner.cs
new file mode 100644
index 000000000..e9c2eca44
--- /dev/null
+++ b/crypto/src/crypto/signers/Ed25519ctxSigner.cs
@@ -0,0 +1,130 @@
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class Ed25519ctxSigner
+ : ISigner
+ {
+ private readonly Buffer buffer = new Buffer();
+ private readonly byte[] context;
+
+ private bool forSigning;
+ private Ed25519PrivateKeyParameters privateKey;
+ private Ed25519PublicKeyParameters publicKey;
+
+ public Ed25519ctxSigner(byte[] context)
+ {
+ this.context = Arrays.Clone(context);
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Ed25519ctx"; }
+ }
+
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ if (forSigning)
+ {
+ // TODO Allow IAsymmetricCipherKeyPair to be an ICipherParameters?
+
+ this.privateKey = (Ed25519PrivateKeyParameters)parameters;
+ this.publicKey = privateKey.GeneratePublicKey();
+ }
+ else
+ {
+ this.privateKey = null;
+ this.publicKey = (Ed25519PublicKeyParameters)parameters;
+ }
+
+ Reset();
+ }
+
+ public virtual void Update(byte b)
+ {
+ buffer.WriteByte(b);
+ }
+
+ public virtual void BlockUpdate(byte[] buf, int off, int len)
+ {
+ buffer.Write(buf, off, len);
+ }
+
+ public virtual byte[] GenerateSignature()
+ {
+ if (!forSigning)
+ throw new InvalidOperationException("Ed25519ctxSigner not initialised for signature generation.");
+
+ return buffer.GenerateSignature(privateKey, publicKey, context);
+ }
+
+ public virtual bool VerifySignature(byte[] signature)
+ {
+ if (forSigning)
+ throw new InvalidOperationException("Ed25519ctxSigner not initialised for verification");
+
+ return buffer.VerifySignature(publicKey, context, signature);
+ }
+
+ public virtual void Reset()
+ {
+ buffer.Reset();
+ }
+
+ private class Buffer : MemoryStream
+ {
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ internal byte[] GenerateSignature(Ed25519PrivateKeyParameters privateKey, Ed25519PublicKeyParameters publicKey, byte[] ctx)
+ {
+#if PORTABLE
+ byte[] buf = ToArray();
+ int count = buf.Length;
+#else
+ byte[] buf = GetBuffer();
+ int count = (int)Position;
+#endif
+ byte[] signature = new byte[Ed25519PrivateKeyParameters.SignatureSize];
+ privateKey.Sign(Ed25519.Algorithm.Ed25519ctx, publicKey, ctx, buf, 0, count, signature, 0);
+ Reset();
+ return signature;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ internal bool VerifySignature(Ed25519PublicKeyParameters publicKey, byte[] ctx, byte[] signature)
+ {
+#if PORTABLE
+ byte[] buf = ToArray();
+ int count = buf.Length;
+#else
+ byte[] buf = GetBuffer();
+ int count = (int)Position;
+#endif
+ byte[] pk = publicKey.GetEncoded();
+ bool result = Ed25519.Verify(signature, 0, pk, 0, ctx, buf, 0, count);
+ Reset();
+ return result;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ internal void Reset()
+ {
+#if PORTABLE
+ this.Position = 0L;
+
+ // TODO Clear using Write method
+#else
+ Array.Clear(GetBuffer(), 0, (int)Position);
+#endif
+ this.Position = 0L;
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/signers/Ed25519phSigner.cs b/crypto/src/crypto/signers/Ed25519phSigner.cs
new file mode 100644
index 000000000..0d3de96f3
--- /dev/null
+++ b/crypto/src/crypto/signers/Ed25519phSigner.cs
@@ -0,0 +1,89 @@
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class Ed25519phSigner
+ : ISigner
+ {
+ private readonly IDigest prehash = Ed25519.CreatePrehash();
+ private readonly byte[] context;
+
+ private bool forSigning;
+ private Ed25519PrivateKeyParameters privateKey;
+ private Ed25519PublicKeyParameters publicKey;
+
+ public Ed25519phSigner(byte[] context)
+ {
+ this.context = Arrays.Clone(context);
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Ed25519ph"; }
+ }
+
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ if (forSigning)
+ {
+ // TODO Allow AsymmetricCipherKeyPair to be a CipherParameters?
+
+ this.privateKey = (Ed25519PrivateKeyParameters)parameters;
+ this.publicKey = privateKey.GeneratePublicKey();
+ }
+ else
+ {
+ this.privateKey = null;
+ this.publicKey = (Ed25519PublicKeyParameters)parameters;
+ }
+
+ Reset();
+ }
+
+ public virtual void Update(byte b)
+ {
+ prehash.Update(b);
+ }
+
+ public virtual void BlockUpdate(byte[] buf, int off, int len)
+ {
+ prehash.BlockUpdate(buf, off, len);
+ }
+
+ public virtual byte[] GenerateSignature()
+ {
+ if (!forSigning)
+ throw new InvalidOperationException("Ed25519phSigner not initialised for signature generation.");
+
+ byte[] msg = new byte[Ed25519.PrehashSize];
+ if (Ed25519.PrehashSize != prehash.DoFinal(msg, 0))
+ throw new InvalidOperationException("Prehash digest failed");
+
+ byte[] signature = new byte[Ed25519PrivateKeyParameters.SignatureSize];
+ privateKey.Sign(Ed25519.Algorithm.Ed25519ph, publicKey, context, msg, 0, Ed25519.PrehashSize, signature, 0);
+ return signature;
+ }
+
+ public virtual bool VerifySignature(byte[] signature)
+ {
+ if (forSigning)
+ throw new InvalidOperationException("Ed25519phSigner not initialised for verification");
+
+ byte[] pk = publicKey.GetEncoded();
+ return Ed25519.VerifyPrehash(signature, 0, pk, 0, context, prehash);
+ }
+
+ public void Reset()
+ {
+ prehash.Reset();
+ }
+ }
+}
diff --git a/crypto/src/crypto/signers/Ed448Signer.cs b/crypto/src/crypto/signers/Ed448Signer.cs
new file mode 100644
index 000000000..c01d84b4d
--- /dev/null
+++ b/crypto/src/crypto/signers/Ed448Signer.cs
@@ -0,0 +1,130 @@
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class Ed448Signer
+ : ISigner
+ {
+ private readonly Buffer buffer = new Buffer();
+ private readonly byte[] context;
+
+ private bool forSigning;
+ private Ed448PrivateKeyParameters privateKey;
+ private Ed448PublicKeyParameters publicKey;
+
+ public Ed448Signer(byte[] context)
+ {
+ this.context = Arrays.Clone(context);
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Ed448"; }
+ }
+
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ if (forSigning)
+ {
+ // TODO Allow IAsymmetricCipherKeyPair to be an ICipherParameters?
+
+ this.privateKey = (Ed448PrivateKeyParameters)parameters;
+ this.publicKey = privateKey.GeneratePublicKey();
+ }
+ else
+ {
+ this.privateKey = null;
+ this.publicKey = (Ed448PublicKeyParameters)parameters;
+ }
+
+ Reset();
+ }
+
+ public virtual void Update(byte b)
+ {
+ buffer.WriteByte(b);
+ }
+
+ public virtual void BlockUpdate(byte[] buf, int off, int len)
+ {
+ buffer.Write(buf, off, len);
+ }
+
+ public virtual byte[] GenerateSignature()
+ {
+ if (!forSigning)
+ throw new InvalidOperationException("Ed448Signer not initialised for signature generation.");
+
+ return buffer.GenerateSignature(privateKey, publicKey, context);
+ }
+
+ public virtual bool VerifySignature(byte[] signature)
+ {
+ if (forSigning)
+ throw new InvalidOperationException("Ed448Signer not initialised for verification");
+
+ return buffer.VerifySignature(publicKey, context, signature);
+ }
+
+ public virtual void Reset()
+ {
+ buffer.Reset();
+ }
+
+ private class Buffer : MemoryStream
+ {
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ internal byte[] GenerateSignature(Ed448PrivateKeyParameters privateKey, Ed448PublicKeyParameters publicKey, byte[] ctx)
+ {
+#if PORTABLE
+ byte[] buf = ToArray();
+ int count = buf.Length;
+#else
+ byte[] buf = GetBuffer();
+ int count = (int)Position;
+#endif
+ byte[] signature = new byte[Ed448PrivateKeyParameters.SignatureSize];
+ privateKey.Sign(Ed448.Algorithm.Ed448, publicKey, ctx, buf, 0, count, signature, 0);
+ Reset();
+ return signature;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ internal bool VerifySignature(Ed448PublicKeyParameters publicKey, byte[] ctx, byte[] signature)
+ {
+#if PORTABLE
+ byte[] buf = ToArray();
+ int count = buf.Length;
+#else
+ byte[] buf = GetBuffer();
+ int count = (int)Position;
+#endif
+ byte[] pk = publicKey.GetEncoded();
+ bool result = Ed448.Verify(signature, 0, pk, 0, ctx, buf, 0, count);
+ Reset();
+ return result;
+ }
+
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ internal void Reset()
+ {
+#if PORTABLE
+ this.Position = 0L;
+
+ // TODO Clear using Write method
+#else
+ Array.Clear(GetBuffer(), 0, (int)Position);
+#endif
+ this.Position = 0L;
+ }
+ }
+ }
+}
diff --git a/crypto/src/crypto/signers/Ed448phSigner.cs b/crypto/src/crypto/signers/Ed448phSigner.cs
new file mode 100644
index 000000000..50d0a0154
--- /dev/null
+++ b/crypto/src/crypto/signers/Ed448phSigner.cs
@@ -0,0 +1,89 @@
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.EC.Rfc8032;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+ public class Ed448phSigner
+ : ISigner
+ {
+ private readonly IXof prehash = Ed448.CreatePrehash();
+ private readonly byte[] context;
+
+ private bool forSigning;
+ private Ed448PrivateKeyParameters privateKey;
+ private Ed448PublicKeyParameters publicKey;
+
+ public Ed448phSigner(byte[] context)
+ {
+ this.context = Arrays.Clone(context);
+ }
+
+ public virtual string AlgorithmName
+ {
+ get { return "Ed448ph"; }
+ }
+
+ public virtual void Init(bool forSigning, ICipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+
+ if (forSigning)
+ {
+ // TODO Allow AsymmetricCipherKeyPair to be a CipherParameters?
+
+ this.privateKey = (Ed448PrivateKeyParameters)parameters;
+ this.publicKey = privateKey.GeneratePublicKey();
+ }
+ else
+ {
+ this.privateKey = null;
+ this.publicKey = (Ed448PublicKeyParameters)parameters;
+ }
+
+ Reset();
+ }
+
+ public virtual void Update(byte b)
+ {
+ prehash.Update(b);
+ }
+
+ public virtual void BlockUpdate(byte[] buf, int off, int len)
+ {
+ prehash.BlockUpdate(buf, off, len);
+ }
+
+ public virtual byte[] GenerateSignature()
+ {
+ if (!forSigning)
+ throw new InvalidOperationException("Ed448phSigner not initialised for signature generation.");
+
+ byte[] msg = new byte[Ed448.PrehashSize];
+ if (Ed448.PrehashSize != prehash.DoFinal(msg, 0, Ed448.PrehashSize))
+ throw new InvalidOperationException("Prehash digest failed");
+
+ byte[] signature = new byte[Ed448PrivateKeyParameters.SignatureSize];
+ privateKey.Sign(Ed448.Algorithm.Ed448ph, publicKey, context, msg, 0, Ed448.PrehashSize, signature, 0);
+ return signature;
+ }
+
+ public virtual bool VerifySignature(byte[] signature)
+ {
+ if (forSigning)
+ throw new InvalidOperationException("Ed448phSigner not initialised for verification");
+
+ byte[] pk = publicKey.GetEncoded();
+ return Ed448.VerifyPrehash(signature, 0, pk, 0, context, prehash);
+ }
+
+ public void Reset()
+ {
+ prehash.Reset();
+ }
+ }
+}
|