diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2018-09-21 15:17:56 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2018-09-21 15:17:56 +0700 |
commit | fbae27fb1edcea6b0924dba977a6d94f0a3655db (patch) | |
tree | ffea8216ac6125b574dcd05bed38fccd0fe10ba5 /crypto/src | |
parent | Refactoring (diff) | |
download | BouncyCastle.NET-ed25519-fbae27fb1edcea6b0924dba977a6d94f0a3655db.tar.xz |
Higher-level API support for Ed25519/Ed448/X25519/X448
Diffstat (limited to 'crypto/src')
34 files changed, 1581 insertions, 82 deletions
diff --git a/crypto/src/asn1/edec/EdECObjectIdentifiers.cs b/crypto/src/asn1/edec/EdECObjectIdentifiers.cs new file mode 100644 index 000000000..f8c5713d8 --- /dev/null +++ b/crypto/src/asn1/edec/EdECObjectIdentifiers.cs @@ -0,0 +1,17 @@ +using System; + +namespace Org.BouncyCastle.Asn1.EdEC +{ + /** + * Edwards Elliptic Curve Object Identifiers (RFC 8410) + */ + public abstract class EdECObjectIdentifiers + { + public static readonly DerObjectIdentifier id_edwards_curve_algs = new DerObjectIdentifier("1.3.101"); + + public static readonly DerObjectIdentifier id_X25519 = id_edwards_curve_algs.Branch("110"); + public static readonly DerObjectIdentifier id_X448 = id_edwards_curve_algs.Branch("111"); + public static readonly DerObjectIdentifier id_Ed25519 = id_edwards_curve_algs.Branch("112"); + public static readonly DerObjectIdentifier id_Ed448 = id_edwards_curve_algs.Branch("113"); + } +} 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(); + } + } +} diff --git a/crypto/src/math/ec/rfc8032/Ed25519.cs b/crypto/src/math/ec/rfc8032/Ed25519.cs index adb56ca9b..0b0e649d7 100644 --- a/crypto/src/math/ec/rfc8032/Ed25519.cs +++ b/crypto/src/math/ec/rfc8032/Ed25519.cs @@ -12,6 +12,13 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 { public abstract class Ed25519 { + public enum Algorithm + { + Ed25519 = 0, + Ed25519ctx = 1, + Ed25519ph = 2, + } + private const long M28L = 0x0FFFFFFFL; private const long M32L = 0xFFFFFFFFL; diff --git a/crypto/src/math/ec/rfc8032/Ed448.cs b/crypto/src/math/ec/rfc8032/Ed448.cs index c1c0788a7..f12aa0807 100644 --- a/crypto/src/math/ec/rfc8032/Ed448.cs +++ b/crypto/src/math/ec/rfc8032/Ed448.cs @@ -12,6 +12,12 @@ namespace Org.BouncyCastle.Math.EC.Rfc8032 { public abstract class Ed448 { + public enum Algorithm + { + Ed448 = 0, + Ed448ph = 1, + } + private const ulong M26UL = 0x03FFFFFFUL; private const ulong M28UL = 0x0FFFFFFFUL; diff --git a/crypto/src/pkcs/PrivateKeyInfoFactory.cs b/crypto/src/pkcs/PrivateKeyInfoFactory.cs index a349a11d2..69eb3fa67 100644 --- a/crypto/src/pkcs/PrivateKeyInfoFactory.cs +++ b/crypto/src/pkcs/PrivateKeyInfoFactory.cs @@ -2,6 +2,7 @@ using System; 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.Sec; @@ -22,59 +23,68 @@ namespace Org.BouncyCastle.Pkcs } public static PrivateKeyInfo CreatePrivateKeyInfo( - AsymmetricKeyParameter key) + AsymmetricKeyParameter privateKey) { - if (key == null) - throw new ArgumentNullException("key"); - if (!key.IsPrivate) - throw new ArgumentException("Public key passed - private key expected", "key"); + return CreatePrivateKeyInfo(privateKey, null); + } + + /** + * Create a PrivateKeyInfo representation of a private key with attributes. + * + * @param privateKey the key to be encoded into the info object. + * @param attributes the set of attributes to be included. + * @return the appropriate PrivateKeyInfo + * @throws java.io.IOException on an error encoding the key + */ + public static PrivateKeyInfo CreatePrivateKeyInfo(AsymmetricKeyParameter privateKey, Asn1Set attributes) + { + if (privateKey == null) + throw new ArgumentNullException("privateKey"); + if (!privateKey.IsPrivate) + throw new ArgumentException("Public key passed - private key expected", "privateKey"); - if (key is ElGamalPrivateKeyParameters) + if (privateKey is ElGamalPrivateKeyParameters) { - ElGamalPrivateKeyParameters _key = (ElGamalPrivateKeyParameters)key; + ElGamalPrivateKeyParameters _key = (ElGamalPrivateKeyParameters)privateKey; + ElGamalParameters egp = _key.Parameters; return new PrivateKeyInfo( - new AlgorithmIdentifier( - OiwObjectIdentifiers.ElGamalAlgorithm, - new ElGamalParameter( - _key.Parameters.P, - _key.Parameters.G).ToAsn1Object()), - new DerInteger(_key.X)); + new AlgorithmIdentifier(OiwObjectIdentifiers.ElGamalAlgorithm, new ElGamalParameter(egp.P, egp.G).ToAsn1Object()), + new DerInteger(_key.X), + attributes); } - if (key is DsaPrivateKeyParameters) + if (privateKey is DsaPrivateKeyParameters) { - DsaPrivateKeyParameters _key = (DsaPrivateKeyParameters)key; + DsaPrivateKeyParameters _key = (DsaPrivateKeyParameters)privateKey; + DsaParameters dp = _key.Parameters; return new PrivateKeyInfo( - new AlgorithmIdentifier( - X9ObjectIdentifiers.IdDsa, - new DsaParameter( - _key.Parameters.P, - _key.Parameters.Q, - _key.Parameters.G).ToAsn1Object()), - new DerInteger(_key.X)); + new AlgorithmIdentifier(X9ObjectIdentifiers.IdDsa, new DsaParameter(dp.P, dp.Q, dp.G).ToAsn1Object()), + new DerInteger(_key.X), + attributes); } - if (key is DHPrivateKeyParameters) + if (privateKey is DHPrivateKeyParameters) { - DHPrivateKeyParameters _key = (DHPrivateKeyParameters)key; + DHPrivateKeyParameters _key = (DHPrivateKeyParameters)privateKey; DHParameter p = new DHParameter( _key.Parameters.P, _key.Parameters.G, _key.Parameters.L); return new PrivateKeyInfo( new AlgorithmIdentifier(_key.AlgorithmOid, p.ToAsn1Object()), - new DerInteger(_key.X)); + new DerInteger(_key.X), + attributes); } - if (key is RsaKeyParameters) + if (privateKey is RsaKeyParameters) { AlgorithmIdentifier algID = new AlgorithmIdentifier( PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance); RsaPrivateKeyStructure keyStruct; - if (key is RsaPrivateCrtKeyParameters) + if (privateKey is RsaPrivateCrtKeyParameters) { - RsaPrivateCrtKeyParameters _key = (RsaPrivateCrtKeyParameters)key; + RsaPrivateCrtKeyParameters _key = (RsaPrivateCrtKeyParameters)privateKey; keyStruct = new RsaPrivateKeyStructure( _key.Modulus, @@ -88,7 +98,7 @@ namespace Org.BouncyCastle.Pkcs } else { - RsaKeyParameters _key = (RsaKeyParameters) key; + RsaKeyParameters _key = (RsaKeyParameters) privateKey; keyStruct = new RsaPrivateKeyStructure( _key.Modulus, @@ -101,12 +111,12 @@ namespace Org.BouncyCastle.Pkcs BigInteger.Zero); } - return new PrivateKeyInfo(algID, keyStruct.ToAsn1Object()); + return new PrivateKeyInfo(algID, keyStruct.ToAsn1Object(), attributes); } - if (key is ECPrivateKeyParameters) + if (privateKey is ECPrivateKeyParameters) { - ECPrivateKeyParameters priv = (ECPrivateKeyParameters)key; + ECPrivateKeyParameters priv = (ECPrivateKeyParameters)privateKey; ECDomainParameters dp = priv.Parameters; int orderBitLength = dp.N.BitLength; @@ -145,12 +155,12 @@ namespace Org.BouncyCastle.Pkcs algID = new AlgorithmIdentifier(X9ObjectIdentifiers.IdECPublicKey, x962); } - return new PrivateKeyInfo(algID, ec); + return new PrivateKeyInfo(algID, ec, attributes); } - if (key is Gost3410PrivateKeyParameters) + if (privateKey is Gost3410PrivateKeyParameters) { - Gost3410PrivateKeyParameters _key = (Gost3410PrivateKeyParameters)key; + Gost3410PrivateKeyParameters _key = (Gost3410PrivateKeyParameters)privateKey; if (_key.PublicKeyParamSet == null) throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set"); @@ -170,10 +180,42 @@ namespace Org.BouncyCastle.Pkcs CryptoProObjectIdentifiers.GostR3410x94, algParams.ToAsn1Object()); - return new PrivateKeyInfo(algID, new DerOctetString(keyBytes)); + return new PrivateKeyInfo(algID, new DerOctetString(keyBytes), attributes); + } + + if (privateKey is X448PrivateKeyParameters) + { + X448PrivateKeyParameters key = (X448PrivateKeyParameters)privateKey; + + return new PrivateKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X448), + new DerOctetString(key.GetEncoded()), attributes, key.GeneratePublicKey().GetEncoded()); + } + + if (privateKey is X25519PrivateKeyParameters) + { + X25519PrivateKeyParameters key = (X25519PrivateKeyParameters)privateKey; + + return new PrivateKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519), + new DerOctetString(key.GetEncoded()), attributes, key.GeneratePublicKey().GetEncoded()); + } + + if (privateKey is Ed448PrivateKeyParameters) + { + Ed448PrivateKeyParameters key = (Ed448PrivateKeyParameters)privateKey; + + return new PrivateKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed448), + new DerOctetString(key.GetEncoded()), attributes, key.GeneratePublicKey().GetEncoded()); + } + + if (privateKey is Ed25519PrivateKeyParameters) + { + Ed25519PrivateKeyParameters key = (Ed25519PrivateKeyParameters)privateKey; + + return new PrivateKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519), + new DerOctetString(key.GetEncoded()), attributes, key.GeneratePublicKey().GetEncoded()); } - throw new ArgumentException("Class provided is not convertible: " + Platform.GetTypeName(key)); + throw new ArgumentException("Class provided is not convertible: " + Platform.GetTypeName(privateKey)); } public static PrivateKeyInfo CreatePrivateKeyInfo( diff --git a/crypto/src/security/AgreementUtilities.cs b/crypto/src/security/AgreementUtilities.cs index 12d427c8c..26d1628cc 100644 --- a/crypto/src/security/AgreementUtilities.cs +++ b/crypto/src/security/AgreementUtilities.cs @@ -1,6 +1,7 @@ using System.Collections; using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.EdEC; using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Agreement; @@ -27,7 +28,10 @@ namespace Org.BouncyCastle.Security algorithms[X9ObjectIdentifiers.DHSinglePassCofactorDHSha1KdfScheme.Id] = "ECCDHWITHSHA1KDF"; algorithms[X9ObjectIdentifiers.DHSinglePassStdDHSha1KdfScheme.Id] = "ECDHWITHSHA1KDF"; algorithms[X9ObjectIdentifiers.MqvSinglePassSha1KdfScheme.Id] = "ECMQVWITHSHA1KDF"; - } + + algorithms[EdECObjectIdentifiers.id_X25519.Id] = "X25519"; + algorithms[EdECObjectIdentifiers.id_X448.Id] = "X448"; + } public static IBasicAgreement GetBasicAgreement( DerObjectIdentifier oid) @@ -38,15 +42,9 @@ namespace Org.BouncyCastle.Security public static IBasicAgreement GetBasicAgreement( string algorithm) { - string upper = Platform.ToUpperInvariant(algorithm); - string mechanism = (string) algorithms[upper]; - - if (mechanism == null) - { - mechanism = upper; - } + string mechanism = GetMechanism(algorithm); - if (mechanism == "DH" || mechanism == "DIFFIEHELLMAN") + if (mechanism == "DH" || mechanism == "DIFFIEHELLMAN") return new DHBasicAgreement(); if (mechanism == "ECDH") @@ -72,15 +70,9 @@ namespace Org.BouncyCastle.Security string agreeAlgorithm, string wrapAlgorithm) { - string upper = Platform.ToUpperInvariant(agreeAlgorithm); - string mechanism = (string) algorithms[upper]; + string mechanism = GetMechanism(agreeAlgorithm); - if (mechanism == null) - { - mechanism = upper; - } - - // 'DHWITHSHA1KDF' retained for backward compatibility + // 'DHWITHSHA1KDF' retained for backward compatibility if (mechanism == "DHWITHSHA1KDF" || mechanism == "ECDHWITHSHA1KDF") return new ECDHWithKdfBasicAgreement( wrapAlgorithm, @@ -96,10 +88,37 @@ namespace Org.BouncyCastle.Security throw new SecurityUtilityException("Basic Agreement (with KDF) " + agreeAlgorithm + " not recognised."); } + public static IRawAgreement GetRawAgreement( + DerObjectIdentifier oid) + { + return GetRawAgreement(oid.Id); + } + + public static IRawAgreement GetRawAgreement( + string algorithm) + { + string mechanism = GetMechanism(algorithm); + + if (mechanism == "X25519") + return new X25519Agreement(); + + if (mechanism == "X448") + return new X448Agreement(); + + throw new SecurityUtilityException("Raw Agreement " + algorithm + " not recognised."); + } + public static string GetAlgorithmName( DerObjectIdentifier oid) { - return (string) algorithms[oid.Id]; + return (string)algorithms[oid.Id]; } + + private static string GetMechanism(string algorithm) + { + string upper = Platform.ToUpperInvariant(algorithm); + string mechanism = (string)algorithms[upper]; + return mechanism == null ? upper : mechanism; + } } } diff --git a/crypto/src/security/GeneratorUtilities.cs b/crypto/src/security/GeneratorUtilities.cs index db1929c16..26ddb396b 100644 --- a/crypto/src/security/GeneratorUtilities.cs +++ b/crypto/src/security/GeneratorUtilities.cs @@ -2,6 +2,7 @@ using System.Collections; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.EdEC; using Org.BouncyCastle.Asn1.Iana; using Org.BouncyCastle.Asn1.Kisa; using Org.BouncyCastle.Asn1.Nist; @@ -180,12 +181,23 @@ namespace Org.BouncyCastle.Security AddKpgAlgorithm("ECGOST3410", "ECGOST-3410", "GOST-3410-2001"); + AddKpgAlgorithm("Ed25519", + "Ed25519ctx", + "Ed25519ph", + EdECObjectIdentifiers.id_Ed25519); + AddKpgAlgorithm("Ed448", + "Ed448ph", + EdECObjectIdentifiers.id_Ed448); AddKpgAlgorithm("ELGAMAL"); AddKpgAlgorithm("GOST3410", "GOST-3410", "GOST-3410-94"); AddKpgAlgorithm("RSA", "1.2.840.113549.1.1.1"); + AddKpgAlgorithm("X25519", + EdECObjectIdentifiers.id_X25519); + AddKpgAlgorithm("X448", + EdECObjectIdentifiers.id_X448); AddDefaultKeySizeEntries(64, "DES"); AddDefaultKeySizeEntries(80, "SKIPJACK"); @@ -216,11 +228,11 @@ namespace Org.BouncyCastle.Security string canonicalName, params object[] aliases) { - kgAlgorithms[canonicalName] = canonicalName; + kgAlgorithms[Platform.ToUpperInvariant(canonicalName)] = canonicalName; foreach (object alias in aliases) { - kgAlgorithms[alias.ToString()] = canonicalName; + kgAlgorithms[Platform.ToUpperInvariant(alias.ToString())] = canonicalName; } } @@ -228,11 +240,11 @@ namespace Org.BouncyCastle.Security string canonicalName, params object[] aliases) { - kpgAlgorithms[canonicalName] = canonicalName; + kpgAlgorithms[Platform.ToUpperInvariant(canonicalName)] = canonicalName; foreach (object alias in aliases) { - kpgAlgorithms[alias.ToString()] = canonicalName; + kpgAlgorithms[Platform.ToUpperInvariant(alias.ToString())] = canonicalName; } } @@ -248,7 +260,7 @@ namespace Org.BouncyCastle.Security foreach (object alias in aliases) { - kgAlgorithms[alias.ToString()] = mainName; + kgAlgorithms[Platform.ToUpperInvariant(alias.ToString())] = mainName; } } @@ -318,6 +330,12 @@ namespace Org.BouncyCastle.Security if (Platform.StartsWith(canonicalName, "EC")) return new ECKeyPairGenerator(canonicalName); + if (canonicalName == "Ed25519") + return new Ed25519KeyPairGenerator(); + + if (canonicalName == "Ed448") + return new Ed448KeyPairGenerator(); + if (canonicalName == "ELGAMAL") return new ElGamalKeyPairGenerator(); @@ -327,6 +345,12 @@ namespace Org.BouncyCastle.Security if (canonicalName == "RSA") return new RsaKeyPairGenerator(); + if (canonicalName == "X25519") + return new X25519KeyPairGenerator(); + + if (canonicalName == "X448") + return new X448KeyPairGenerator(); + throw new SecurityUtilityException("KeyPairGenerator " + algorithm + " (" + canonicalName + ") not supported."); } diff --git a/crypto/src/security/PrivateKeyFactory.cs b/crypto/src/security/PrivateKeyFactory.cs index c9e19cc7d..0b07d0659 100644 --- a/crypto/src/security/PrivateKeyFactory.cs +++ b/crypto/src/security/PrivateKeyFactory.cs @@ -5,6 +5,7 @@ using System.Text; 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.Sec; @@ -170,12 +171,37 @@ namespace Org.BouncyCastle.Security return new Gost3410PrivateKeyParameters(x, gostParams.PublicKeyParamSet); } + else if (algOid.Equals(EdECObjectIdentifiers.id_X25519)) + { + return new X25519PrivateKeyParameters(GetRawKey(keyInfo, X25519PrivateKeyParameters.KeySize), 0); + } + else if (algOid.Equals(EdECObjectIdentifiers.id_X448)) + { + return new X448PrivateKeyParameters(GetRawKey(keyInfo, X448PrivateKeyParameters.KeySize), 0); + } + else if (algOid.Equals(EdECObjectIdentifiers.id_Ed25519)) + { + return new Ed25519PrivateKeyParameters(GetRawKey(keyInfo, Ed25519PrivateKeyParameters.KeySize), 0); + } + else if (algOid.Equals(EdECObjectIdentifiers.id_Ed448)) + { + return new Ed448PrivateKeyParameters(GetRawKey(keyInfo, Ed448PrivateKeyParameters.KeySize), 0); + } else { - throw new SecurityUtilityException("algorithm identifier in key not recognised"); + throw new SecurityUtilityException("algorithm identifier in private key not recognised"); } } + private static byte[] GetRawKey(PrivateKeyInfo keyInfo, int expectedSize) + { + byte[] result = Asn1OctetString.GetInstance(keyInfo.ParsePrivateKey()).GetOctets(); + if (expectedSize != result.Length) + throw new SecurityUtilityException("private key encoding has incorrect length"); + + return result; + } + public static AsymmetricKeyParameter DecryptKey( char[] passPhrase, EncryptedPrivateKeyInfo encInfo) diff --git a/crypto/src/security/PublicKeyFactory.cs b/crypto/src/security/PublicKeyFactory.cs index f1b28b774..e39748e45 100644 --- a/crypto/src/security/PublicKeyFactory.cs +++ b/crypto/src/security/PublicKeyFactory.cs @@ -5,6 +5,7 @@ using System.Text; 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.Sec; @@ -218,12 +219,41 @@ namespace Org.BouncyCastle.Security return new Gost3410PublicKeyParameters(y, algParams.PublicKeyParamSet); } + else if (algOid.Equals(EdECObjectIdentifiers.id_X25519)) + { + return new X25519PublicKeyParameters(GetRawKey(keyInfo, X25519PublicKeyParameters.KeySize), 0); + } + else if (algOid.Equals(EdECObjectIdentifiers.id_X448)) + { + return new X448PublicKeyParameters(GetRawKey(keyInfo, X448PublicKeyParameters.KeySize), 0); + } + else if (algOid.Equals(EdECObjectIdentifiers.id_Ed25519)) + { + return new Ed25519PublicKeyParameters(GetRawKey(keyInfo, Ed25519PublicKeyParameters.KeySize), 0); + } + else if (algOid.Equals(EdECObjectIdentifiers.id_Ed448)) + { + return new Ed448PublicKeyParameters(GetRawKey(keyInfo, Ed448PublicKeyParameters.KeySize), 0); + } else { - throw new SecurityUtilityException("algorithm identifier in key not recognised: " + algOid); + throw new SecurityUtilityException("algorithm identifier in public key not recognised: " + algOid); } } + private static byte[] GetRawKey(SubjectPublicKeyInfo keyInfo, int expectedSize) + { + /* + * TODO[RFC 8422] + * - Require keyInfo.Algorithm.Parameters == null? + */ + byte[] result = keyInfo.PublicKeyData.GetOctets(); + if (expectedSize != result.Length) + throw new SecurityUtilityException("public key encoding has incorrect length"); + + return result; + } + private static bool IsPkcsDHParam(Asn1Sequence seq) { if (seq.Count == 2) diff --git a/crypto/src/security/SignerUtilities.cs b/crypto/src/security/SignerUtilities.cs index 44281503a..a9045ae6e 100644 --- a/crypto/src/security/SignerUtilities.cs +++ b/crypto/src/security/SignerUtilities.cs @@ -4,6 +4,7 @@ using System.IO; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.CryptoPro; +using Org.BouncyCastle.Asn1.EdEC; using Org.BouncyCastle.Asn1.Nist; using Org.BouncyCastle.Asn1.Oiw; using Org.BouncyCastle.Asn1.Pkcs; @@ -231,7 +232,13 @@ namespace Org.BouncyCastle.Security algorithms["GOST3411WITHECGOST3410"] = "ECGOST3410"; algorithms[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001.Id] = "ECGOST3410"; - + algorithms["ED25519"] = "Ed25519"; + algorithms[EdECObjectIdentifiers.id_Ed25519.Id] = "Ed25519"; + algorithms["ED25519CTX"] = "Ed25519ctx"; + algorithms["ED25519PH"] = "Ed25519ph"; + algorithms["ED448"] = "Ed448"; + algorithms[EdECObjectIdentifiers.id_Ed448.Id] = "Ed448"; + algorithms["ED448PH"] = "Ed448ph"; oids["MD2withRSA"] = PkcsObjectIdentifiers.MD2WithRsaEncryption; oids["MD4withRSA"] = PkcsObjectIdentifiers.MD4WithRsaEncryption; @@ -264,6 +271,9 @@ namespace Org.BouncyCastle.Security oids["GOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94; oids["ECGOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001; + + oids["Ed25519"] = EdECObjectIdentifiers.id_Ed25519; + oids["Ed448"] = EdECObjectIdentifiers.id_Ed448; } /// <summary> @@ -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 /// <summary> /// Create a Subject Public Key Info object for a given public key. /// </summary> - /// <param name="key">One of ElGammalPublicKeyParameters, DSAPublicKeyParameter, DHPublicKeyParameters, RsaKeyParameters or ECPublicKeyParameters</param> + /// <param name="publicKey">One of ElGammalPublicKeyParameters, DSAPublicKeyParameter, DHPublicKeyParameters, RsaKeyParameters or ECPublicKeyParameters</param> /// <returns>A subject public key info object.</returns> /// <exception cref="Exception">Throw exception if object provided is not one of the above.</exception> 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( |