Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@

namespace Org.BouncyCastle.Crypto.Parameters
{
/// <summary>
/// Key generation parameters for Ed25519 (RFC 8032). Carries the <see cref="SecureRandom"/> used for
/// seed generation; the strength is fixed at 256 bits.
/// </summary>
public class Ed25519KeyGenerationParameters
: KeyGenerationParameters
{
/// <summary>
/// Construct using <paramref name="random"/> as the entropy source for the 32-byte seed.
/// </summary>
public Ed25519KeyGenerationParameters(SecureRandom random)
: base(random, 256)
{
Expand Down
40 changes: 40 additions & 0 deletions crypto/src/crypto/parameters/Ed25519PrivateKeyParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,50 @@

namespace Org.BouncyCastle.Crypto.Parameters
{
/// <summary>
/// Ed25519 private key (RFC 8032). Holds the 32-byte secret seed; the corresponding public key is
/// derived lazily on first use and cached.
/// </summary>
public sealed class Ed25519PrivateKeyParameters
: AsymmetricKeyParameter
{
/// <summary>Length in bytes of an Ed25519 private-key seed (32).</summary>
public static readonly int KeySize = Ed25519.SecretKeySize;

/// <summary>Length in bytes of an Ed25519 signature (64).</summary>
public static readonly int SignatureSize = Ed25519.SignatureSize;

private readonly byte[] data = new byte[KeySize];

private Ed25519PublicKeyParameters cachedPublicKey;

/// <summary>Generate a fresh random Ed25519 private key using <paramref name="random"/>.</summary>
public Ed25519PrivateKeyParameters(SecureRandom random)
: base(true)
{
Ed25519.GeneratePrivateKey(random, data);
}

/// <summary>Construct from a 32-byte seed buffer.</summary>
/// <exception cref="ArgumentException">If <paramref name="buf"/> length differs from
/// <see cref="KeySize"/>.</exception>
public Ed25519PrivateKeyParameters(byte[] buf)
: this(Validate(buf), 0)
{
}

/// <summary>Construct from <paramref name="buf"/> at <paramref name="off"/>; reads
/// <see cref="KeySize"/> bytes.</summary>
public Ed25519PrivateKeyParameters(byte[] buf, int off)
: base(true)
{
Array.Copy(buf, off, data, 0, KeySize);
}

#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
/// <summary>Construct from a span carrying the 32-byte seed.</summary>
/// <exception cref="ArgumentException">If <paramref name="buf"/> length differs from
/// <see cref="KeySize"/>.</exception>
public Ed25519PrivateKeyParameters(ReadOnlySpan<byte> buf)
: base(true)
{
Expand All @@ -46,25 +62,31 @@ public Ed25519PrivateKeyParameters(ReadOnlySpan<byte> buf)
}
#endif

/// <summary>Read the 32-byte seed from <paramref name="input"/>.</summary>
/// <exception cref="EndOfStreamException">If the stream ends before <see cref="KeySize"/>
/// bytes have been read.</exception>
public Ed25519PrivateKeyParameters(Stream input)
: base(true)
{
if (KeySize != Streams.ReadFully(input, data))
throw new EndOfStreamException("EOF encountered in middle of Ed25519 private key");
}

/// <summary>Write the 32-byte seed into <paramref name="buf"/> at <paramref name="off"/>.</summary>
public void Encode(byte[] buf, int off)
{
Array.Copy(data, 0, buf, off, KeySize);
}

#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
/// <summary>Write the 32-byte seed into the supplied span.</summary>
public void Encode(Span<byte> buf)
{
data.CopyTo(buf);
}
#endif

/// <summary>Return a fresh copy of the 32-byte seed.</summary>
public byte[] GetEncoded()
{
return Arrays.Clone(data);
Expand All @@ -76,9 +98,23 @@ public byte[] GetEncoded()
internal ReadOnlyMemory<byte> DataMemory => data;
#endif

/// <summary>
/// Derive (and cache) the public key corresponding to this private key.
/// </summary>
public Ed25519PublicKeyParameters GeneratePublicKey() =>
Objects.EnsureSingletonInitialized(ref cachedPublicKey, data, CreatePublicKey);

/// <summary>
/// Compute an Ed25519 signature. Selects between pure Ed25519, Ed25519ctx and Ed25519ph based on
/// <paramref name="algorithm"/>. The pure variant rejects a non-<c>null</c> context; the context
/// and prehash variants require a context up to 255 bytes long, and Ed25519ph additionally
/// requires <paramref name="msgLen"/> to equal <see cref="Ed25519.PrehashSize"/>.
/// </summary>
/// <exception cref="ArgumentNullException">If <paramref name="ctx"/> is required but
/// <c>null</c>.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="ctx"/> exceeds 255 bytes,
/// is supplied for pure Ed25519, <paramref name="msgLen"/> is wrong for Ed25519ph, or
/// <paramref name="algorithm"/> is unrecognised.</exception>
public void Sign(Ed25519.Algorithm algorithm, byte[] ctx, byte[] msg, int msgOff, int msgLen,
byte[] sig, int sigOff)
{
Expand Down Expand Up @@ -127,6 +163,10 @@ public void Sign(Ed25519.Algorithm algorithm, byte[] ctx, byte[] msg, int msgOff
}

#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Span-based overload of
/// <see cref="Sign(Ed25519.Algorithm, byte[], byte[], int, int, byte[], int)"/>.
/// </summary>
public void Sign(Ed25519.Algorithm algorithm, byte[] ctx, ReadOnlySpan<byte> msg, Span<byte> sig)
{
Ed25519PublicKeyParameters publicKey = GeneratePublicKey();
Expand Down
54 changes: 54 additions & 0 deletions crypto/src/crypto/parameters/Ed25519PublicKeyParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,47 @@

namespace Org.BouncyCastle.Crypto.Parameters
{
/// <summary>
/// Ed25519 public key (RFC 8032). Wraps a decoded curve point obtained from a 32-byte encoded
/// representation; the point is validated at construction so that subsequent verifications work
/// against a known-good key.
/// </summary>
public sealed class Ed25519PublicKeyParameters
: AsymmetricKeyParameter
{
/// <summary>Length in bytes of an Ed25519 public key encoding (32).</summary>
public static readonly int KeySize = Ed25519.PublicKeySize;

private readonly Ed25519.PublicPoint m_publicPoint;

/// <summary>
/// Construct from a 32-byte buffer holding the encoded public point.
/// </summary>
/// <exception cref="ArgumentException">If <paramref name="buf"/> length differs from
/// <see cref="KeySize"/>, or the encoding does not decode to a valid curve point.</exception>
public Ed25519PublicKeyParameters(byte[] buf)
: this(Validate(buf), 0)
{
}

/// <summary>
/// Construct from <paramref name="buf"/> starting at <paramref name="off"/>; reads
/// <see cref="KeySize"/> bytes.
/// </summary>
/// <exception cref="ArgumentException">If the encoded bytes do not decode to a valid curve
/// point.</exception>
public Ed25519PublicKeyParameters(byte[] buf, int off)
: base(false)
{
m_publicPoint = Parse(buf, off);
}

#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Construct from a span holding the encoded public point.
/// </summary>
/// <exception cref="ArgumentException">If <paramref name="buf"/> length differs from
/// <see cref="KeySize"/>, or the encoding does not decode to a valid curve point.</exception>
public Ed25519PublicKeyParameters(ReadOnlySpan<byte> buf)
: base(false)
{
Expand All @@ -35,6 +57,13 @@ public Ed25519PublicKeyParameters(ReadOnlySpan<byte> buf)
}
#endif

/// <summary>
/// Read <see cref="KeySize"/> encoded bytes from <paramref name="input"/> and decode them.
/// </summary>
/// <exception cref="EndOfStreamException">If the stream ends before <see cref="KeySize"/>
/// bytes have been read.</exception>
/// <exception cref="ArgumentException">If the encoded bytes do not decode to a valid curve
/// point.</exception>
public Ed25519PublicKeyParameters(Stream input)
: base(false)
{
Expand All @@ -54,31 +83,52 @@ public Ed25519PublicKeyParameters(Stream input)
#endif
}

/// <summary>
/// Construct from an already-decoded curve point. No further validation is performed.
/// </summary>
/// <exception cref="ArgumentNullException">If <paramref name="publicPoint"/> is <c>null</c>.</exception>
public Ed25519PublicKeyParameters(Ed25519.PublicPoint publicPoint)
: base(false)
{
m_publicPoint = publicPoint ?? throw new ArgumentNullException(nameof(publicPoint));
}

/// <summary>
/// Write the 32-byte encoded public point into <paramref name="buf"/> at <paramref name="off"/>.
/// </summary>
public void Encode(byte[] buf, int off)
{
Ed25519.EncodePublicPoint(m_publicPoint, buf, off);
}

#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
/// <summary>Write the 32-byte encoded public point into the supplied span.</summary>
public void Encode(Span<byte> buf)
{
Ed25519.EncodePublicPoint(m_publicPoint, buf);
}
#endif

/// <summary>Return a fresh copy of the 32-byte encoded public point.</summary>
public byte[] GetEncoded()
{
byte[] data = new byte[KeySize];
Encode(data, 0);
return data;
}

/// <summary>
/// Verify an Ed25519 signature. Selects between pure Ed25519, Ed25519ctx and Ed25519ph based on
/// <paramref name="algorithm"/>. The pure variant rejects a non-<c>null</c> context; the context
/// and prehash variants require a context up to 255 bytes long, and Ed25519ph additionally
/// requires <paramref name="msgLen"/> to equal <see cref="Ed25519.PrehashSize"/>.
/// </summary>
/// <returns><c>true</c> if the signature is valid for this key; otherwise <c>false</c>.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="ctx"/> is required but
/// <c>null</c>.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="ctx"/> exceeds 255 bytes,
/// is supplied for pure Ed25519, <paramref name="msgLen"/> is wrong for Ed25519ph, or
/// <paramref name="algorithm"/> is unrecognised.</exception>
public bool Verify(Ed25519.Algorithm algorithm, byte[] ctx, byte[] msg, int msgOff, int msgLen,
byte[] sig, int sigOff)
{
Expand Down Expand Up @@ -119,6 +169,10 @@ public bool Verify(Ed25519.Algorithm algorithm, byte[] ctx, byte[] msg, int msgO
}

#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Span-based overload of
/// <see cref="Verify(Ed25519.Algorithm, byte[], byte[], int, int, byte[], int)"/>.
/// </summary>
public bool Verify(Ed25519.Algorithm algorithm, byte[] ctx, ReadOnlySpan<byte> msg, ReadOnlySpan<byte> sig)
{
switch (algorithm)
Expand Down
7 changes: 7 additions & 0 deletions crypto/src/crypto/parameters/Ed448KeyGenerationParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@

namespace Org.BouncyCastle.Crypto.Parameters
{
/// <summary>
/// Key generation parameters for Ed448 (RFC 8032). Carries the <see cref="SecureRandom"/> used for
/// seed generation; the strength is fixed at 448 bits.
/// </summary>
public class Ed448KeyGenerationParameters
: KeyGenerationParameters
{
/// <summary>
/// Construct using <paramref name="random"/> as the entropy source for the 57-byte seed.
/// </summary>
public Ed448KeyGenerationParameters(SecureRandom random)
: base(random, 448)
{
Expand Down
36 changes: 36 additions & 0 deletions crypto/src/crypto/parameters/Ed448PrivateKeyParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,50 @@

namespace Org.BouncyCastle.Crypto.Parameters
{
/// <summary>
/// Ed448 private key (RFC 8032). Holds the 57-byte secret seed; the corresponding public key is
/// derived lazily on first use and cached.
/// </summary>
public sealed class Ed448PrivateKeyParameters
: AsymmetricKeyParameter
{
/// <summary>Length in bytes of an Ed448 private-key seed (57).</summary>
public static readonly int KeySize = Ed448.SecretKeySize;

/// <summary>Length in bytes of an Ed448 signature (114).</summary>
public static readonly int SignatureSize = Ed448.SignatureSize;

private readonly byte[] data = new byte[KeySize];

private Ed448PublicKeyParameters cachedPublicKey;

/// <summary>Generate a fresh random Ed448 private key using <paramref name="random"/>.</summary>
public Ed448PrivateKeyParameters(SecureRandom random)
: base(true)
{
Ed448.GeneratePrivateKey(random, data);
}

/// <summary>Construct from a 57-byte seed buffer.</summary>
/// <exception cref="ArgumentException">If <paramref name="buf"/> length differs from
/// <see cref="KeySize"/>.</exception>
public Ed448PrivateKeyParameters(byte[] buf)
: this(Validate(buf), 0)
{
}

/// <summary>Construct from <paramref name="buf"/> at <paramref name="off"/>; reads
/// <see cref="KeySize"/> bytes.</summary>
public Ed448PrivateKeyParameters(byte[] buf, int off)
: base(true)
{
Array.Copy(buf, off, data, 0, KeySize);
}

#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
/// <summary>Construct from a span carrying the 57-byte seed.</summary>
/// <exception cref="ArgumentException">If <paramref name="buf"/> length differs from
/// <see cref="KeySize"/>.</exception>
public Ed448PrivateKeyParameters(ReadOnlySpan<byte> buf)
: base(true)
{
Expand All @@ -46,25 +62,31 @@ public Ed448PrivateKeyParameters(ReadOnlySpan<byte> buf)
}
#endif

/// <summary>Read the 57-byte seed from <paramref name="input"/>.</summary>
/// <exception cref="EndOfStreamException">If the stream ends before <see cref="KeySize"/>
/// bytes have been read.</exception>
public Ed448PrivateKeyParameters(Stream input)
: base(true)
{
if (KeySize != Streams.ReadFully(input, data))
throw new EndOfStreamException("EOF encountered in middle of Ed448 private key");
}

/// <summary>Write the 57-byte seed into <paramref name="buf"/> at <paramref name="off"/>.</summary>
public void Encode(byte[] buf, int off)
{
Array.Copy(data, 0, buf, off, KeySize);
}

#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
/// <summary>Write the 57-byte seed into the supplied span.</summary>
public void Encode(Span<byte> buf)
{
data.CopyTo(buf);
}
#endif

/// <summary>Return a fresh copy of the 57-byte seed.</summary>
public byte[] GetEncoded()
{
return Arrays.Clone(data);
Expand All @@ -76,9 +98,19 @@ public byte[] GetEncoded()
internal ReadOnlyMemory<byte> DataMemory => data;
#endif

/// <summary>Derive (and cache) the public key corresponding to this private key.</summary>
public Ed448PublicKeyParameters GeneratePublicKey() =>
Objects.EnsureSingletonInitialized(ref cachedPublicKey, data, CreatePublicKey);

/// <summary>
/// Compute an Ed448 signature. Both Ed448 and Ed448ph require a non-<c>null</c> context up to
/// 255 bytes; Ed448ph additionally requires <paramref name="msgLen"/> to equal
/// <see cref="Ed448.PrehashSize"/>.
/// </summary>
/// <exception cref="ArgumentNullException">If <paramref name="ctx"/> is <c>null</c>.</exception>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="ctx"/> exceeds 255 bytes,
/// <paramref name="msgLen"/> is wrong for Ed448ph, or <paramref name="algorithm"/> is
/// unrecognised.</exception>
public void Sign(Ed448.Algorithm algorithm, byte[] ctx, byte[] msg, int msgOff, int msgLen,
byte[] sig, int sigOff)
{
Expand Down Expand Up @@ -119,6 +151,10 @@ public void Sign(Ed448.Algorithm algorithm, byte[] ctx, byte[] msg, int msgOff,
}

#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
/// <summary>
/// Span-based overload of
/// <see cref="Sign(Ed448.Algorithm, byte[], byte[], int, int, byte[], int)"/>.
/// </summary>
public void Sign(Ed448.Algorithm algorithm, byte[] ctx, ReadOnlySpan<byte> msg, Span<byte> sig)
{
Ed448PublicKeyParameters publicKey = GeneratePublicKey();
Expand Down
Loading