diff --git a/crypto/src/crypto/util/OpenSshPrivateKeyUtilities.cs b/crypto/src/crypto/util/OpenSshPrivateKeyUtilities.cs
index 187ecc39e..aa934b1d6 100644
--- a/crypto/src/crypto/util/OpenSshPrivateKeyUtilities.cs
+++ b/crypto/src/crypto/util/OpenSshPrivateKeyUtilities.cs
@@ -1,7 +1,7 @@
using System;
+using System.Text;
using Org.BouncyCastle.Asn1;
-using Org.BouncyCastle.Asn1.Nist;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.Sec;
using Org.BouncyCastle.Asn1.X9;
@@ -16,7 +16,7 @@ namespace Org.BouncyCastle.Crypto.Utilities
{
/// <summary>Magic value for proprietary OpenSSH private key.</summary>
/// <remarks>C string so null terminated.</remarks>
- private static readonly byte[] AUTH_MAGIC = Strings.ToByteArray("openssh-key-v1\0");
+ private static readonly byte[] AUTH_MAGIC = Encoding.ASCII.GetBytes("openssh-key-v1\0");
/**
* Encode a cipher parameters into an OpenSSH private key.
@@ -66,9 +66,9 @@ namespace Org.BouncyCastle.Crypto.Utilities
SshBuilder builder = new SshBuilder();
builder.WriteBytes(AUTH_MAGIC);
- builder.WriteString("none"); // cipher name
- builder.WriteString("none"); // KDF name
- builder.WriteString(""); // KDF options
+ builder.WriteStringAscii("none"); // cipher name
+ builder.WriteStringAscii("none"); // KDF name
+ builder.WriteStringAscii(""); // KDF options
builder.U32(1); // Number of keys
@@ -84,7 +84,7 @@ namespace Org.BouncyCastle.Crypto.Utilities
pkBuild.U32((uint)checkint);
pkBuild.U32((uint)checkint);
- pkBuild.WriteString("ssh-ed25519");
+ pkBuild.WriteStringAscii("ssh-ed25519");
// Public key (as part of private key pair)
byte[] pubKeyEncoded = publicKeyParameters.GetEncoded();
@@ -94,7 +94,7 @@ namespace Org.BouncyCastle.Crypto.Utilities
pkBuild.WriteBlock(Arrays.Concatenate(ed25519PrivateKey.GetEncoded(), pubKeyEncoded));
// Comment for this private key (empty)
- pkBuild.WriteString("");
+ pkBuild.WriteStringUtf8("");
builder.WriteBlock(pkBuild.GetPaddedBytes());
}
@@ -102,8 +102,7 @@ namespace Org.BouncyCastle.Crypto.Utilities
return builder.GetBytes();
}
- throw new ArgumentException("unable to convert " + parameters.GetType().Name + " to openssh private key");
-
+ throw new ArgumentException("unable to convert " + Platform.GetTypeName(parameters) + " to openssh private key");
}
/**
@@ -177,11 +176,9 @@ namespace Org.BouncyCastle.Crypto.Utilities
{
SshBuffer kIn = new SshBuffer(AUTH_MAGIC, blob);
- string cipherName = kIn.ReadString();
+ string cipherName = kIn.ReadStringAscii();
if (!"none".Equals(cipherName))
- {
throw new InvalidOperationException("encrypted keys not supported");
- }
// KDF name
kIn.SkipBlock();
@@ -191,9 +188,7 @@ namespace Org.BouncyCastle.Crypto.Utilities
int publicKeyCount = kIn.ReadU32();
if (publicKeyCount != 1)
- {
throw new InvalidOperationException("multiple keys not supported");
- }
// Burn off public key.
OpenSshPublicKeyUtilities.ParsePublicKey(kIn.ReadBlock());
@@ -201,87 +196,80 @@ namespace Org.BouncyCastle.Crypto.Utilities
byte[] privateKeyBlock = kIn.ReadPaddedBlock();
if (kIn.HasRemaining())
- {
throw new InvalidOperationException("decoded key has trailing data");
- }
SshBuffer pkIn = new SshBuffer(privateKeyBlock);
int check1 = pkIn.ReadU32();
int check2 = pkIn.ReadU32();
if (check1 != check2)
- {
throw new InvalidOperationException("private key check values are not the same");
- }
- string keyType = pkIn.ReadString();
+ string keyType = pkIn.ReadStringAscii();
if ("ssh-ed25519".Equals(keyType))
{
// Public key
- pkIn.ReadBlock();
+ pkIn.SkipBlock();
+
// Private key value..
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ ReadOnlySpan<byte> edPrivateKey = pkIn.ReadBlockSpan();
+#else
byte[] edPrivateKey = pkIn.ReadBlock();
+#endif
+
if (edPrivateKey.Length != Ed25519PrivateKeyParameters.KeySize + Ed25519PublicKeyParameters.KeySize)
- {
throw new InvalidOperationException("private key value of wrong length");
- }
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ result = new Ed25519PrivateKeyParameters(edPrivateKey[..Ed25519PrivateKeyParameters.KeySize]);
+#else
result = new Ed25519PrivateKeyParameters(edPrivateKey, 0);
+#endif
}
else if (keyType.StartsWith("ecdsa"))
{
- DerObjectIdentifier oid = SshNamedCurves.GetByName(Strings.FromByteArray(pkIn.ReadBlock())) ??
+ var curveName = pkIn.ReadStringAscii();
+
+ var oid = SshNamedCurves.GetOid(curveName) ??
throw new InvalidOperationException("OID not found for: " + keyType);
- X9ECParameters curveParams = NistNamedCurves.GetByOid(oid) ?? throw new InvalidOperationException("Curve not found for: " + oid);
+
+ var x9ECParameters = SshNamedCurves.GetByOid(oid) ??
+ throw new InvalidOperationException("Curve not found for: " + oid);
// Skip public key.
- pkIn.ReadBlock();
- byte[] privKey = pkIn.ReadBlock();
+ pkIn.SkipBlock();
- result = new ECPrivateKeyParameters(new BigInteger(1, privKey),
- new ECNamedDomainParameters(oid, curveParams));
+ var d = pkIn.ReadMpintPositive();
+
+ result = new ECPrivateKeyParameters(d, new ECNamedDomainParameters(oid, x9ECParameters));
}
else if (keyType.StartsWith("ssh-rsa"))
{
- BigInteger modulus = new BigInteger(1, pkIn.ReadBlock());
- BigInteger pubExp = new BigInteger(1, pkIn.ReadBlock());
- BigInteger privExp = new BigInteger(1, pkIn.ReadBlock());
- BigInteger coef = new BigInteger(1, pkIn.ReadBlock());
- BigInteger p = new BigInteger(1, pkIn.ReadBlock());
- BigInteger q = new BigInteger(1, pkIn.ReadBlock());
+ BigInteger modulus = pkIn.ReadMpintPositive();
+ BigInteger pubExp = pkIn.ReadMpintPositive();
+ BigInteger privExp = pkIn.ReadMpintPositive();
+ BigInteger coef = pkIn.ReadMpintPositive();
+ BigInteger p = pkIn.ReadMpintPositive();
+ BigInteger q = pkIn.ReadMpintPositive();
BigInteger pSub1 = p.Subtract(BigIntegers.One);
BigInteger qSub1 = q.Subtract(BigIntegers.One);
BigInteger dP = privExp.Remainder(pSub1);
BigInteger dQ = privExp.Remainder(qSub1);
- result = new RsaPrivateCrtKeyParameters(
- modulus,
- pubExp,
- privExp,
- p,
- q,
- dP,
- dQ,
- coef);
+ result = new RsaPrivateCrtKeyParameters(modulus, pubExp, privExp, p, q, dP, dQ, coef);
}
// Comment for private key
pkIn.SkipBlock();
if (pkIn.HasRemaining())
- {
throw new ArgumentException("private key block has trailing data");
- }
}
- if (result == null)
- {
- throw new ArgumentException("unable to parse key");
- }
-
- return result;
+ return result ?? throw new ArgumentException("unable to parse key"); ;
}
/**
@@ -292,9 +280,7 @@ namespace Org.BouncyCastle.Crypto.Utilities
for (int t = 0; t < sequence.Count; t++)
{
if (!(sequence[t] is DerInteger))
- {
return false;
- }
}
return true;
}
diff --git a/crypto/src/crypto/util/OpenSshPublicKeyUtilities.cs b/crypto/src/crypto/util/OpenSshPublicKeyUtilities.cs
index cdb16b06a..f04ab85f7 100644
--- a/crypto/src/crypto/util/OpenSshPublicKeyUtilities.cs
+++ b/crypto/src/crypto/util/OpenSshPublicKeyUtilities.cs
@@ -1,9 +1,9 @@
using System;
-using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Utilities
{
@@ -38,43 +38,34 @@ namespace Org.BouncyCastle.Crypto.Utilities
public static byte[] EncodePublicKey(AsymmetricKeyParameter cipherParameters)
{
if (cipherParameters == null)
- {
- throw new ArgumentException("cipherParameters was null.");
- }
+ throw new ArgumentNullException(nameof(cipherParameters));
+ if (cipherParameters.IsPrivate)
+ throw new ArgumentException("Not a public key", nameof(cipherParameters));
- if (cipherParameters is RsaKeyParameters)
+ if (cipherParameters is RsaKeyParameters rsaPubKey)
{
- if (cipherParameters.IsPrivate)
- {
- throw new ArgumentException("RSAKeyParamaters was for encryption");
- }
-
- RsaKeyParameters rsaPubKey = (RsaKeyParameters)cipherParameters;
-
SshBuilder builder = new SshBuilder();
- builder.WriteString(RSA);
- builder.WriteBigNum(rsaPubKey.Exponent);
- builder.WriteBigNum(rsaPubKey.Modulus);
-
+ builder.WriteStringAscii(RSA);
+ builder.WriteMpint(rsaPubKey.Exponent);
+ builder.WriteMpint(rsaPubKey.Modulus);
return builder.GetBytes();
-
}
else if (cipherParameters is ECPublicKeyParameters ecPublicKey)
{
- SshBuilder builder = new SshBuilder();
+ string curveName = null;
- //
- // checked for named curve parameters..
- //
- string name = SshNamedCurves.GetNameForParameters(ecPublicKey.Parameters);
-
- if (name == null)
+ var oid = ecPublicKey.PublicKeyParamSet;
+ if (oid != null)
{
- throw new ArgumentException("unable to derive ssh curve name for " + ecPublicKey.Parameters.Curve.GetType().Name);
+ curveName = SshNamedCurves.GetName(oid);
}
- builder.WriteString(ECDSA + "-sha2-" + name); // Magic
- builder.WriteString(name);
+ if (curveName == null)
+ throw new ArgumentException("unable to derive ssh curve name for EC public key");
+
+ SshBuilder builder = new SshBuilder();
+ builder.WriteStringAscii(ECDSA + "-sha2-" + curveName); // Magic
+ builder.WriteStringAscii(curveName);
builder.WriteBlock(ecPublicKey.Q.GetEncoded(false)); //Uncompressed
return builder.GetBytes();
}
@@ -83,22 +74,22 @@ namespace Org.BouncyCastle.Crypto.Utilities
DsaParameters dsaParams = dsaPubKey.Parameters;
SshBuilder builder = new SshBuilder();
- builder.WriteString(DSS);
- builder.WriteBigNum(dsaParams.P);
- builder.WriteBigNum(dsaParams.Q);
- builder.WriteBigNum(dsaParams.G);
- builder.WriteBigNum(dsaPubKey.Y);
+ builder.WriteStringAscii(DSS);
+ builder.WriteMpint(dsaParams.P);
+ builder.WriteMpint(dsaParams.Q);
+ builder.WriteMpint(dsaParams.G);
+ builder.WriteMpint(dsaPubKey.Y);
return builder.GetBytes();
}
else if (cipherParameters is Ed25519PublicKeyParameters ed25519PublicKey)
{
SshBuilder builder = new SshBuilder();
- builder.WriteString(ED_25519);
+ builder.WriteStringAscii(ED_25519);
builder.WriteBlock(ed25519PublicKey.GetEncoded());
return builder.GetBytes();
}
- throw new ArgumentException("unable to convert " + cipherParameters.GetType().Name + " to private key");
+ throw new ArgumentException("unable to convert " + Platform.GetTypeName(cipherParameters) + " to private key");
}
/**
@@ -111,55 +102,60 @@ namespace Org.BouncyCastle.Crypto.Utilities
{
AsymmetricKeyParameter result = null;
- string magic = buffer.ReadString();
+ string magic = buffer.ReadStringAscii();
if (RSA.Equals(magic))
{
- BigInteger e = buffer.ReadBigNumPositive();
- BigInteger n = buffer.ReadBigNumPositive();
+ BigInteger e = buffer.ReadMpintPositive();
+ BigInteger n = buffer.ReadMpintPositive();
result = new RsaKeyParameters(false, n, e);
}
else if (DSS.Equals(magic))
{
- BigInteger p = buffer.ReadBigNumPositive();
- BigInteger q = buffer.ReadBigNumPositive();
- BigInteger g = buffer.ReadBigNumPositive();
- BigInteger pubKey = buffer.ReadBigNumPositive();
+ BigInteger p = buffer.ReadMpintPositive();
+ BigInteger q = buffer.ReadMpintPositive();
+ BigInteger g = buffer.ReadMpintPositive();
+ BigInteger pubKey = buffer.ReadMpintPositive();
result = new DsaPublicKeyParameters(pubKey, new DsaParameters(p, q, g));
}
else if (magic.StartsWith(ECDSA))
{
- string curveName = buffer.ReadString();
- DerObjectIdentifier oid = SshNamedCurves.GetByName(curveName);
- X9ECParameters x9ECParameters = SshNamedCurves.GetParameters(oid) ??
- throw new InvalidOperationException("unable to find curve for " + magic + " using curve name " + curveName);
- var curve = x9ECParameters.Curve;
- byte[] pointRaw = buffer.ReadBlock();
-
- result = new ECPublicKeyParameters(
- curve.DecodePoint(pointRaw),
- new ECNamedDomainParameters(oid, x9ECParameters));
+ var curveName = buffer.ReadStringAscii();
+
+ var oid = SshNamedCurves.GetOid(curveName);
+
+ X9ECParameters x9ECParameters = oid == null ? null : SshNamedCurves.GetByOid(oid);
+ if (x9ECParameters == null)
+ {
+ throw new InvalidOperationException(
+ "unable to find curve for " + magic + " using curve name " + curveName);
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ ReadOnlySpan<byte> pointEncoding = buffer.ReadBlockSpan();
+#else
+ byte[] pointEncoding = buffer.ReadBlock();
+#endif
+ var point = x9ECParameters.Curve.DecodePoint(pointEncoding);
+
+ result = new ECPublicKeyParameters(point, new ECNamedDomainParameters(oid, x9ECParameters));
}
else if (ED_25519.Equals(magic))
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ ReadOnlySpan<byte> pubKeyBytes = buffer.ReadBlockSpan();
+#else
byte[] pubKeyBytes = buffer.ReadBlock();
- if (pubKeyBytes.Length != Ed25519PublicKeyParameters.KeySize)
- {
- throw new InvalidOperationException("public key value of wrong length");
- }
+#endif
- result = new Ed25519PublicKeyParameters(pubKeyBytes, 0);
+ result = new Ed25519PublicKeyParameters(pubKeyBytes);
}
if (result == null)
- {
throw new ArgumentException("unable to parse key");
- }
if (buffer.HasRemaining())
- {
throw new ArgumentException("decoded key has trailing data");
- }
return result;
}
diff --git a/crypto/src/crypto/util/SshBuffer.cs b/crypto/src/crypto/util/SshBuffer.cs
index 094b85364..0df123388 100644
--- a/crypto/src/crypto/util/SshBuffer.cs
+++ b/crypto/src/crypto/util/SshBuffer.cs
@@ -1,4 +1,5 @@
using System;
+using System.Text;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Utilities;
@@ -16,9 +17,7 @@ namespace Org.BouncyCastle.Crypto.Utilities
for (int i = 0; i != magic.Length; i++)
{
if (magic[i] != buffer[i])
- {
throw new ArgumentException("magic-number incorrect");
- }
}
pos += magic.Length;
@@ -32,47 +31,62 @@ namespace Org.BouncyCastle.Crypto.Utilities
public int ReadU32()
{
if (pos > buffer.Length - 4)
- {
throw new ArgumentOutOfRangeException("4 bytes for U32 exceeds buffer.");
- }
-
- int i = (buffer[pos++] & 0xFF) << 24;
- i |= (buffer[pos++] & 0xFF) << 16;
- i |= (buffer[pos++] & 0xFF) << 8;
- i |= buffer[pos++] & 0xFF;
+ int i = (int)Pack.BE_To_UInt32(buffer, pos);
+ pos += 4;
return i;
}
- public string ReadString()
+ public string ReadStringAscii()
{
- return Strings.FromByteArray(ReadBlock());
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return Encoding.ASCII.GetString(ReadBlockSpan());
+#else
+ return Encoding.ASCII.GetString(ReadBlock());
+#endif
+ }
+
+ public string ReadStringUtf8()
+ {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return Encoding.UTF8.GetString(ReadBlockSpan());
+#else
+ return Encoding.UTF8.GetString(ReadBlock());
+#endif
}
public byte[] ReadBlock()
{
int len = ReadU32();
if (len == 0)
- {
- return new byte[0];
- }
-
+ return Arrays.EmptyBytes;
if (pos > buffer.Length - len)
- {
- throw new ArgumentException("not enough data for block");
- }
+ throw new InvalidOperationException("not enough data for block");
int start = pos; pos += len;
return Arrays.CopyOfRange(buffer, start, pos);
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public ReadOnlySpan<byte> ReadBlockSpan()
+ {
+ int len = ReadU32();
+ if (len == 0)
+ return ReadOnlySpan<byte>.Empty;
+ if (pos > buffer.Length - len)
+ throw new InvalidOperationException("not enough data for block");
+
+ int start = pos; pos += len;
+ return buffer.AsSpan(start, len);
+ }
+#endif
+
public void SkipBlock()
{
int len = ReadU32();
if (pos > buffer.Length - len)
- {
- throw new ArgumentException("not enough data for block");
- }
+ throw new InvalidOperationException("not enough data for block");
pos += len;
}
@@ -86,20 +100,13 @@ namespace Org.BouncyCastle.Crypto.Utilities
{
int len = ReadU32();
if (len == 0)
- {
- return new byte[0];
- }
-
+ return Arrays.EmptyBytes;
if (pos > buffer.Length - len)
- {
- throw new ArgumentException("not enough data for block");
- }
+ throw new InvalidOperationException("not enough data for block");
int align = len % blockSize;
if (0 != align)
- {
- throw new ArgumentException("missing padding");
- }
+ throw new InvalidOperationException("missing padding");
int start = pos; pos += len;
int end = pos;
@@ -116,9 +123,7 @@ namespace Org.BouncyCastle.Crypto.Utilities
for (int i = 1, padPos = end; i <= padCount; ++i, ++padPos)
{
if (i != (buffer[padPos] & 0xFF))
- {
- throw new ArgumentException("incorrect padding");
- }
+ throw new InvalidOperationException("incorrect padding");
}
}
}
@@ -126,27 +131,32 @@ namespace Org.BouncyCastle.Crypto.Utilities
return Arrays.CopyOfRange(buffer, start, end);
}
- public BigInteger ReadBigNumPositive()
+ public BigInteger ReadMpint()
{
int len = ReadU32();
- if (pos + len > buffer.Length)
- {
- throw new ArgumentException("not enough data for big num");
- }
+ if (pos > buffer.Length - len)
+ throw new InvalidOperationException("not enough data for big num");
+
+ if (len == 0)
+ return BigInteger.Zero;
+ if (len == 1 && buffer[pos] == 0)
+ throw new InvalidOperationException("Zero MUST be stored with length 0");
+ if (len > 1 && buffer[pos] == (byte)-(buffer[pos + 1] >> 7))
+ throw new InvalidOperationException("Unnecessary leading bytes MUST NOT be included");
int start = pos; pos += len;
- byte[] d = Arrays.CopyOfRange(buffer, start, pos);
- return new BigInteger(1, d);
+ return new BigInteger(buffer, start, len);
}
- public byte[] GetBuffer()
+ public BigInteger ReadMpintPositive()
{
- return Arrays.Clone(buffer);
- }
+ BigInteger n = ReadMpint();
+ if (n.SignValue < 0)
+ throw new InvalidOperationException("Expected a positive mpint");
- public bool HasRemaining()
- {
- return pos < buffer.Length;
+ return n;
}
+
+ public bool HasRemaining() => pos < buffer.Length;
}
}
diff --git a/crypto/src/crypto/util/SshBuilder.cs b/crypto/src/crypto/util/SshBuilder.cs
index 9f2f35360..d631448d5 100644
--- a/crypto/src/crypto/util/SshBuilder.cs
+++ b/crypto/src/crypto/util/SshBuilder.cs
@@ -1,8 +1,8 @@
using System;
using System.IO;
+using System.Text;
using Org.BouncyCastle.Math;
-using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Utilities
{
@@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Crypto.Utilities
bos.WriteByte(Convert.ToByte(value & 0xFF));
}
- public void WriteBigNum(BigInteger n)
+ public void WriteMpint(BigInteger n)
{
WriteBlock(n.ToByteArray());
}
@@ -26,14 +26,7 @@ namespace Org.BouncyCastle.Crypto.Utilities
public void WriteBlock(byte[] value)
{
U32((uint)value.Length);
- try
- {
- bos.Write(value, 0, value.Length);
- }
- catch (IOException e)
- {
- throw new InvalidOperationException(e.Message, e);
- }
+ WriteBytes(value);
}
public void WriteBytes(byte[] value)
@@ -48,9 +41,14 @@ namespace Org.BouncyCastle.Crypto.Utilities
}
}
- public void WriteString(string str)
+ public void WriteStringAscii(string str)
+ {
+ WriteBlock(Encoding.ASCII.GetBytes(str));
+ }
+
+ public void WriteStringUtf8(string str)
{
- WriteBlock(Strings.ToByteArray(str));
+ WriteBlock(Encoding.UTF8.GetBytes(str));
}
public byte[] GetBytes()
diff --git a/crypto/src/crypto/util/SshNamedCurves.cs b/crypto/src/crypto/util/SshNamedCurves.cs
index d97c2476e..019a4d5f5 100644
--- a/crypto/src/crypto/util/SshNamedCurves.cs
+++ b/crypto/src/crypto/util/SshNamedCurves.cs
@@ -1,93 +1,107 @@
-using System.Collections.Generic;
-using System.Linq;
+using System;
+using System.Collections.Generic;
using Org.BouncyCastle.Asn1;
-using Org.BouncyCastle.Asn1.Nist;
using Org.BouncyCastle.Asn1.Sec;
using Org.BouncyCastle.Asn1.X9;
-using Org.BouncyCastle.Crypto.EC;
-using Org.BouncyCastle.Crypto.Parameters;
-using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Utilities.Collections;
namespace Org.BouncyCastle.Crypto.Utilities
{
- public class SshNamedCurves
+ public static class SshNamedCurves
{
- private static readonly Dictionary<string, DerObjectIdentifier> OidMap =
- new Dictionary<string, DerObjectIdentifier>
- {
- { "nistp256", SecObjectIdentifiers.SecP256r1 },
- { "nistp384", SecObjectIdentifiers.SecP384r1 },
- { "nistp521", SecObjectIdentifiers.SecP521r1 },
- { "nistk163", SecObjectIdentifiers.SecT163k1 },
- { "nistp192", SecObjectIdentifiers.SecP192r1 },
- { "nistp224", SecObjectIdentifiers.SecP224r1 },
- { "nistk233", SecObjectIdentifiers.SecT233k1 },
- { "nistb233", SecObjectIdentifiers.SecT233r1 },
- { "nistk283", SecObjectIdentifiers.SecT283k1 },
- { "nistk409", SecObjectIdentifiers.SecT409k1 },
- { "nistb409", SecObjectIdentifiers.SecT409r1 },
- { "nistt571", SecObjectIdentifiers.SecT571k1 }
- };
+ private static readonly Dictionary<string, DerObjectIdentifier> objIds =
+ new Dictionary<string, DerObjectIdentifier>(StringComparer.OrdinalIgnoreCase);
+ private static readonly Dictionary<DerObjectIdentifier, string> names =
+ new Dictionary<DerObjectIdentifier, string>();
+ private static void DefineCurveAlias(string name, DerObjectIdentifier oid)
+ {
+ if (FindByOidLazy(oid) == null)
+ throw new InvalidOperationException();
- private static readonly Dictionary<string, string> CurveNameToSSHName =
- new Dictionary<string, string>
- {
- {"secp256r1", "nistp256"},
- {"secp384r1", "nistp384"},
- {"secp521r1", "nistp521"},
- {"sect163k1", "nistk163"},
- {"secp192r1", "nistp192"},
- {"secp224r1", "nistp224"},
- {"sect233k1", "nistk233"},
- {"sect233r1", "nistb233"},
- {"sect283k1", "nistk283"},
- {"sect409k1", "nistk409"},
- {"sect409r1", "nistb409"},
- {"sect571k1", "nistt571"}
- };
+ objIds.Add(name, oid);
+ names.Add(oid, name);
+ }
- private static readonly Dictionary<ECCurve, string> CurveMap =
- CustomNamedCurves.Names.ToDictionary(k => CustomNamedCurves.GetByNameLazy(k).Curve, v => v);
+ private static X9ECParametersHolder FindByOidLazy(DerObjectIdentifier oid) =>
+ ECKeyPairGenerator.FindECCurveByOidLazy(oid);
- private static readonly Dictionary<DerObjectIdentifier, string> OidToName =
- OidMap.ToDictionary(k => k.Value, v => v.Key);
+ static SshNamedCurves()
+ {
+ DefineCurveAlias("nistp192", SecObjectIdentifiers.SecP192r1);
+ DefineCurveAlias("nistp224", SecObjectIdentifiers.SecP224r1);
+ DefineCurveAlias("nistp256", SecObjectIdentifiers.SecP256r1);
+ DefineCurveAlias("nistp384", SecObjectIdentifiers.SecP384r1);
+ DefineCurveAlias("nistp521", SecObjectIdentifiers.SecP521r1);
+ DefineCurveAlias("nistb233", SecObjectIdentifiers.SecT233r1);
+ DefineCurveAlias("nistb409", SecObjectIdentifiers.SecT409r1);
+ DefineCurveAlias("nistk163", SecObjectIdentifiers.SecT163k1);
+ DefineCurveAlias("nistk233", SecObjectIdentifiers.SecT233k1);
+ DefineCurveAlias("nistk283", SecObjectIdentifiers.SecT283k1);
+ DefineCurveAlias("nistk409", SecObjectIdentifiers.SecT409k1);
+ DefineCurveAlias("nistt571", SecObjectIdentifiers.SecT571k1);
+ }
+ /// <summary>Look up the <see cref="X9ECParameters"/> for the curve with the given name.</summary>
+ /// <param name="name">The name of the curve.</param>
+ public static X9ECParameters GetByName(string name)
+ {
+ DerObjectIdentifier oid = GetOid(name);
+ return oid == null ? null : GetByOid(oid);
+ }
- public static DerObjectIdentifier GetByName(string sshName)
+ /// <summary>Look up an <see cref="X9ECParametersHolder"/> for the curve with the given name.</summary>
+ /// <remarks>
+ /// Allows accessing the <see cref="Math.EC.ECCurve">curve</see> without necessarily triggering the creation of
+ /// the full <see cref="X9ECParameters"/>.
+ /// </remarks>
+ /// <param name="name">The name of the curve.</param>
+ public static X9ECParametersHolder GetByNameLazy(string name)
{
- return OidMap[sshName];
+ DerObjectIdentifier oid = GetOid(name);
+ return oid == null ? null : GetByOidLazy(oid);
}
- public static X9ECParameters GetParameters(string sshName)
+ /// <summary>Look up the <see cref="X9ECParameters"/> for the curve with the given
+ /// <see cref="DerObjectIdentifier">OID</see>.</summary>
+ /// <param name="oid">The <see cref="DerObjectIdentifier">OID</see> for the curve.</param>
+ public static X9ECParameters GetByOid(DerObjectIdentifier oid)
{
- return NistNamedCurves.GetByOid(OidMap[sshName.ToLower()]);
+ return GetByOidLazy(oid)?.Parameters;
}
- public static X9ECParameters GetParameters(DerObjectIdentifier oid)
+ /// <summary>Look up an <see cref="X9ECParametersHolder"/> for the curve with the given
+ /// <see cref="DerObjectIdentifier">OID</see>.</summary>
+ /// <remarks>
+ /// Allows accessing the <see cref="Math.EC.ECCurve">curve</see> without necessarily triggering the creation of
+ /// the full <see cref="X9ECParameters"/>.
+ /// </remarks>
+ /// <param name="oid">The <see cref="DerObjectIdentifier">OID</see> for the curve.</param>
+ public static X9ECParametersHolder GetByOidLazy(DerObjectIdentifier oid)
{
- return NistNamedCurves.GetByOid(oid);
+ return names.ContainsKey(oid) ? FindByOidLazy(oid) : null;
}
+ /// <summary>Look up the name of the curve with the given <see cref="DerObjectIdentifier">OID</see>.</summary>
+ /// <param name="oid">The <see cref="DerObjectIdentifier">OID</see> for the curve.</param>
public static string GetName(DerObjectIdentifier oid)
{
- return OidToName[oid];
+ return CollectionUtilities.GetValueOrNull(names, oid);
}
- public static string GetNameForParameters(ECDomainParameters parameters)
+ /// <summary>Look up the <see cref="DerObjectIdentifier">OID</see> of the curve with the given name.</summary>
+ /// <param name="name">The name of the curve.</param>
+ public static DerObjectIdentifier GetOid(string name)
{
- if (parameters is ECNamedDomainParameters)
- {
- return GetName(((ECNamedDomainParameters)parameters).Name);
- }
-
- return GetNameForParameters(parameters.Curve);
+ return CollectionUtilities.GetValueOrNull(objIds, name);
}
- public static string GetNameForParameters(ECCurve curve)
+ /// <summary>Enumerate the available curve names in this registry.</summary>
+ public static IEnumerable<string> Names
{
- return CurveNameToSSHName[CurveMap[curve]];
+ get { return CollectionUtilities.Proxy(objIds.Keys); }
}
}
}
diff --git a/crypto/test/src/crypto/test/OpenSshKeyParsingTest.cs b/crypto/test/src/crypto/test/OpenSshKeyParsingTest.cs
index 46cac0f4c..02559b5c9 100644
--- a/crypto/test/src/crypto/test/OpenSshKeyParsingTest.cs
+++ b/crypto/test/src/crypto/test/OpenSshKeyParsingTest.cs
@@ -16,7 +16,7 @@ using Org.BouncyCastle.Utilities.IO.Pem;
namespace Org.BouncyCastle.Crypto.Tests
{
[TestFixture]
- public class OpenSshKeyParsingTests
+ public class OpenSshKeyParsingTest
{
private static SecureRandom secureRandom = new SecureRandom();
|