From ba8033a0bd947c58a109ae20d89f8b3817d3d0db Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sat, 15 Apr 2023 19:47:09 +0700 Subject: Move/rename files --- .../src/crypto/util/OpenSshPrivateKeyUtilities.cs | 302 +++++++++++++++++++++ .../src/crypto/util/OpenSshPublicKeyUtilities.cs | 167 ++++++++++++ crypto/src/crypto/util/SshBuffer.cs | 152 +++++++++++ crypto/src/crypto/util/SshBuilder.cs | 80 ++++++ crypto/src/crypto/util/SshNamedCurves.cs | 93 +++++++ crypto/src/util/ssh/OpenSSHPrivateKeyUtil.cs | 302 --------------------- crypto/src/util/ssh/OpenSSHPublicKeyUtil.cs | 168 ------------ crypto/src/util/ssh/SSHBuffer.cs | 151 ----------- crypto/src/util/ssh/SSHBuilder.cs | 79 ------ crypto/src/util/ssh/SSHNamedCurves.cs | 93 ------- 10 files changed, 794 insertions(+), 793 deletions(-) create mode 100644 crypto/src/crypto/util/OpenSshPrivateKeyUtilities.cs create mode 100644 crypto/src/crypto/util/OpenSshPublicKeyUtilities.cs create mode 100644 crypto/src/crypto/util/SshBuffer.cs create mode 100644 crypto/src/crypto/util/SshBuilder.cs create mode 100644 crypto/src/crypto/util/SshNamedCurves.cs delete mode 100644 crypto/src/util/ssh/OpenSSHPrivateKeyUtil.cs delete mode 100644 crypto/src/util/ssh/OpenSSHPublicKeyUtil.cs delete mode 100644 crypto/src/util/ssh/SSHBuffer.cs delete mode 100644 crypto/src/util/ssh/SSHBuilder.cs delete mode 100644 crypto/src/util/ssh/SSHNamedCurves.cs (limited to 'crypto/src') diff --git a/crypto/src/crypto/util/OpenSshPrivateKeyUtilities.cs b/crypto/src/crypto/util/OpenSshPrivateKeyUtilities.cs new file mode 100644 index 000000000..187ecc39e --- /dev/null +++ b/crypto/src/crypto/util/OpenSshPrivateKeyUtilities.cs @@ -0,0 +1,302 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Sec; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Pkcs; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Utilities +{ + public static class OpenSshPrivateKeyUtilities + { + /// Magic value for proprietary OpenSSH private key. + /// C string so null terminated. + private static readonly byte[] AUTH_MAGIC = Strings.ToByteArray("openssh-key-v1\0"); + + /** + * Encode a cipher parameters into an OpenSSH private key. + * This does not add headers like ----BEGIN RSA PRIVATE KEY---- + * + * @param parameters the cipher parameters. + * @return a byte array + */ + public static byte[] EncodePrivateKey(AsymmetricKeyParameter parameters) + { + if (parameters == null) + throw new ArgumentNullException(nameof(parameters)); + + if (parameters is RsaPrivateCrtKeyParameters || parameters is ECPrivateKeyParameters) + { + PrivateKeyInfo pInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(parameters); + return pInfo.ParsePrivateKey().GetEncoded(); + } + else if (parameters is DsaPrivateKeyParameters dsaPrivateKey) + { + DsaParameters dsaparameters = dsaPrivateKey.Parameters; + + Asn1EncodableVector vec = new Asn1EncodableVector + { + new DerInteger(0), + new DerInteger(dsaparameters.P), + new DerInteger(dsaparameters.Q), + new DerInteger(dsaparameters.G) + }; + + // public key = g.modPow(x, p); + BigInteger pubKey = dsaparameters.P.ModPow(dsaPrivateKey.X, dsaparameters.P); + vec.Add(new DerInteger(pubKey)); + vec.Add(new DerInteger(dsaPrivateKey.X)); + try + { + return new DerSequence(vec).GetEncoded(); + } + catch (Exception ex) + { + throw new InvalidOperationException("unable to encode DSAPrivateKeyParameters " + ex.Message); + } + } + else if (parameters is Ed25519PrivateKeyParameters ed25519PrivateKey) + { + Ed25519PublicKeyParameters publicKeyParameters = ed25519PrivateKey.GeneratePublicKey(); + + SshBuilder builder = new SshBuilder(); + builder.WriteBytes(AUTH_MAGIC); + builder.WriteString("none"); // cipher name + builder.WriteString("none"); // KDF name + builder.WriteString(""); // KDF options + + builder.U32(1); // Number of keys + + { + byte[] pkEncoded = OpenSshPublicKeyUtilities.EncodePublicKey(publicKeyParameters); + builder.WriteBlock(pkEncoded); + } + + { + SshBuilder pkBuild = new SshBuilder(); + + int checkint = CryptoServicesRegistrar.GetSecureRandom().NextInt(); + pkBuild.U32((uint)checkint); + pkBuild.U32((uint)checkint); + + pkBuild.WriteString("ssh-ed25519"); + + // Public key (as part of private key pair) + byte[] pubKeyEncoded = publicKeyParameters.GetEncoded(); + pkBuild.WriteBlock(pubKeyEncoded); + + // The private key in SSH is 64 bytes long and is the concatenation of the private and the public keys + pkBuild.WriteBlock(Arrays.Concatenate(ed25519PrivateKey.GetEncoded(), pubKeyEncoded)); + + // Comment for this private key (empty) + pkBuild.WriteString(""); + + builder.WriteBlock(pkBuild.GetPaddedBytes()); + } + + return builder.GetBytes(); + } + + throw new ArgumentException("unable to convert " + parameters.GetType().Name + " to openssh private key"); + + } + + /** + * Parse a private key. + *

+ * This method accepts the body of the OpenSSH private key. + * The easiest way to extract the body is to use PemReader, for example: + *

+ * byte[] blob = new PemReader([reader]).readPemObject().getContent(); + * CipherParameters params = parsePrivateKeyBlob(blob); + * + * @param blob The key. + * @return A cipher parameters instance. + */ + public static AsymmetricKeyParameter ParsePrivateKeyBlob(byte[] blob) + { + AsymmetricKeyParameter result = null; + + if (blob[0] == 0x30) + { + Asn1Sequence sequence = Asn1Sequence.GetInstance(blob); + + if (sequence.Count == 6) + { + if (AllIntegers(sequence) && ((DerInteger)sequence[0]).PositiveValue.Equals(BigIntegers.Zero)) + { + // length of 6 and all Integers -- DSA + result = new DsaPrivateKeyParameters( + ((DerInteger)sequence[5]).PositiveValue, + new DsaParameters( + ((DerInteger)sequence[1]).PositiveValue, + ((DerInteger)sequence[2]).PositiveValue, + ((DerInteger)sequence[3]).PositiveValue) + ); + } + } + else if (sequence.Count == 9) + { + if (AllIntegers(sequence) && ((DerInteger)sequence[0]).PositiveValue.Equals(BigIntegers.Zero)) + { + // length of 8 and all Integers -- RSA + RsaPrivateKeyStructure rsaPrivateKey = RsaPrivateKeyStructure.GetInstance(sequence); + + result = new RsaPrivateCrtKeyParameters( + rsaPrivateKey.Modulus, + rsaPrivateKey.PublicExponent, + rsaPrivateKey.PrivateExponent, + rsaPrivateKey.Prime1, + rsaPrivateKey.Prime2, + rsaPrivateKey.Exponent1, + rsaPrivateKey.Exponent2, + rsaPrivateKey.Coefficient); + } + } + else if (sequence.Count == 4) + { + if (sequence[3] is Asn1TaggedObject && sequence[2] is Asn1TaggedObject) + { + ECPrivateKeyStructure ecPrivateKey = ECPrivateKeyStructure.GetInstance(sequence); + DerObjectIdentifier curveOID = DerObjectIdentifier.GetInstance(ecPrivateKey.GetParameters()); + X9ECParameters x9Params = ECNamedCurveTable.GetByOid(curveOID); + result = new ECPrivateKeyParameters( + ecPrivateKey.GetKey(), + new ECNamedDomainParameters( + curveOID, + x9Params)); + } + } + } + else + { + SshBuffer kIn = new SshBuffer(AUTH_MAGIC, blob); + + string cipherName = kIn.ReadString(); + if (!"none".Equals(cipherName)) + { + throw new InvalidOperationException("encrypted keys not supported"); + } + + // KDF name + kIn.SkipBlock(); + + // KDF options + kIn.SkipBlock(); + + int publicKeyCount = kIn.ReadU32(); + if (publicKeyCount != 1) + { + throw new InvalidOperationException("multiple keys not supported"); + } + + // Burn off public key. + OpenSshPublicKeyUtilities.ParsePublicKey(kIn.ReadBlock()); + + 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(); + + if ("ssh-ed25519".Equals(keyType)) + { + // Public key + pkIn.ReadBlock(); + // Private key value.. + byte[] edPrivateKey = pkIn.ReadBlock(); + if (edPrivateKey.Length != Ed25519PrivateKeyParameters.KeySize + Ed25519PublicKeyParameters.KeySize) + { + throw new InvalidOperationException("private key value of wrong length"); + } + + result = new Ed25519PrivateKeyParameters(edPrivateKey, 0); + } + else if (keyType.StartsWith("ecdsa")) + { + DerObjectIdentifier oid = SshNamedCurves.GetByName(Strings.FromByteArray(pkIn.ReadBlock())) ?? + throw new InvalidOperationException("OID not found for: " + keyType); + X9ECParameters curveParams = NistNamedCurves.GetByOid(oid) ?? throw new InvalidOperationException("Curve not found for: " + oid); + + // Skip public key. + pkIn.ReadBlock(); + byte[] privKey = pkIn.ReadBlock(); + + result = new ECPrivateKeyParameters(new BigInteger(1, privKey), + new ECNamedDomainParameters(oid, curveParams)); + } + 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 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); + } + + // 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; + } + + /** + * allIntegers returns true if the sequence holds only DerInteger types. + **/ + private static bool AllIntegers(Asn1Sequence sequence) + { + 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 new file mode 100644 index 000000000..cdb16b06a --- /dev/null +++ b/crypto/src/crypto/util/OpenSshPublicKeyUtilities.cs @@ -0,0 +1,167 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Crypto.Utilities +{ + public static class OpenSshPublicKeyUtilities + { + private static readonly string RSA = "ssh-rsa"; + private static readonly string ECDSA = "ecdsa"; + private static readonly string ED_25519 = "ssh-ed25519"; + private static readonly string DSS = "ssh-dss"; + + /** + * Parse a public key. + *

+ * This method accepts the bytes that are Base64 encoded in an OpenSSH public key file. + * + * @param encoded The key. + * @return An AsymmetricKeyParameter instance. + */ + public static AsymmetricKeyParameter ParsePublicKey(byte[] encoded) + { + SshBuffer buffer = new SshBuffer(encoded); + return ParsePublicKey(buffer); + } + + /** + * Encode a public key from an AsymmetricKeyParameter instance. + * + * @param cipherParameters The key to encode. + * @return the key OpenSSH encoded. + * @throws IOException + */ + public static byte[] EncodePublicKey(AsymmetricKeyParameter cipherParameters) + { + if (cipherParameters == null) + { + throw new ArgumentException("cipherParameters was null."); + } + + if (cipherParameters is RsaKeyParameters) + { + 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); + + return builder.GetBytes(); + + } + else if (cipherParameters is ECPublicKeyParameters ecPublicKey) + { + SshBuilder builder = new SshBuilder(); + + // + // checked for named curve parameters.. + // + string name = SshNamedCurves.GetNameForParameters(ecPublicKey.Parameters); + + if (name == null) + { + throw new ArgumentException("unable to derive ssh curve name for " + ecPublicKey.Parameters.Curve.GetType().Name); + } + + builder.WriteString(ECDSA + "-sha2-" + name); // Magic + builder.WriteString(name); + builder.WriteBlock(ecPublicKey.Q.GetEncoded(false)); //Uncompressed + return builder.GetBytes(); + } + else if (cipherParameters is DsaPublicKeyParameters dsaPubKey) + { + 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); + return builder.GetBytes(); + } + else if (cipherParameters is Ed25519PublicKeyParameters ed25519PublicKey) + { + SshBuilder builder = new SshBuilder(); + builder.WriteString(ED_25519); + builder.WriteBlock(ed25519PublicKey.GetEncoded()); + return builder.GetBytes(); + } + + throw new ArgumentException("unable to convert " + cipherParameters.GetType().Name + " to private key"); + } + + /** + * Parse a public key from an SSHBuffer instance. + * + * @param buffer containing the SSH public key. + * @return A CipherParameters instance. + */ + private static AsymmetricKeyParameter ParsePublicKey(SshBuffer buffer) + { + AsymmetricKeyParameter result = null; + + string magic = buffer.ReadString(); + if (RSA.Equals(magic)) + { + BigInteger e = buffer.ReadBigNumPositive(); + BigInteger n = buffer.ReadBigNumPositive(); + 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(); + + 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)); + } + else if (ED_25519.Equals(magic)) + { + byte[] pubKeyBytes = buffer.ReadBlock(); + if (pubKeyBytes.Length != Ed25519PublicKeyParameters.KeySize) + { + throw new InvalidOperationException("public key value of wrong length"); + } + + result = new Ed25519PublicKeyParameters(pubKeyBytes, 0); + } + + 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 new file mode 100644 index 000000000..094b85364 --- /dev/null +++ b/crypto/src/crypto/util/SshBuffer.cs @@ -0,0 +1,152 @@ +using System; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Utilities +{ + internal class SshBuffer + { + private readonly byte[] buffer; + private int pos = 0; + + internal SshBuffer(byte[] magic, byte[] buffer) + { + this.buffer = buffer; + for (int i = 0; i != magic.Length; i++) + { + if (magic[i] != buffer[i]) + { + throw new ArgumentException("magic-number incorrect"); + } + } + + pos += magic.Length; + } + + internal SshBuffer(byte[] buffer) + { + this.buffer = buffer; + } + + 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; + + return i; + } + + public string ReadString() + { + return Strings.FromByteArray(ReadBlock()); + } + + public byte[] ReadBlock() + { + int len = ReadU32(); + if (len == 0) + { + return new byte[0]; + } + + if (pos > buffer.Length - len) + { + throw new ArgumentException("not enough data for block"); + } + + int start = pos; pos += len; + return Arrays.CopyOfRange(buffer, start, pos); + } + + public void SkipBlock() + { + int len = ReadU32(); + if (pos > buffer.Length - len) + { + throw new ArgumentException("not enough data for block"); + } + + pos += len; + } + + public byte[] ReadPaddedBlock() + { + return ReadPaddedBlock(8); + } + + public byte[] ReadPaddedBlock(int blockSize) + { + int len = ReadU32(); + if (len == 0) + { + return new byte[0]; + } + + if (pos > buffer.Length - len) + { + throw new ArgumentException("not enough data for block"); + } + + int align = len % blockSize; + if (0 != align) + { + throw new ArgumentException("missing padding"); + } + + int start = pos; pos += len; + int end = pos; + + if (len > 0) + { + // TODO If encryption is supported, should be constant-time + int lastByte = buffer[pos - 1] & 0xFF; + if (0 < lastByte && lastByte < blockSize) + { + int padCount = lastByte; + end -= padCount; + + for (int i = 1, padPos = end; i <= padCount; ++i, ++padPos) + { + if (i != (buffer[padPos] & 0xFF)) + { + throw new ArgumentException("incorrect padding"); + } + } + } + } + + return Arrays.CopyOfRange(buffer, start, end); + } + + public BigInteger ReadBigNumPositive() + { + int len = ReadU32(); + if (pos + len > buffer.Length) + { + throw new ArgumentException("not enough data for big num"); + } + + int start = pos; pos += len; + byte[] d = Arrays.CopyOfRange(buffer, start, pos); + return new BigInteger(1, d); + } + + public byte[] GetBuffer() + { + return Arrays.Clone(buffer); + } + + public bool HasRemaining() + { + return pos < buffer.Length; + } + } +} diff --git a/crypto/src/crypto/util/SshBuilder.cs b/crypto/src/crypto/util/SshBuilder.cs new file mode 100644 index 000000000..9f2f35360 --- /dev/null +++ b/crypto/src/crypto/util/SshBuilder.cs @@ -0,0 +1,80 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Utilities +{ + internal class SshBuilder + { + private readonly MemoryStream bos = new MemoryStream(); + + public void U32(uint value) + { + bos.WriteByte(Convert.ToByte(value >> 24 & 0xFF)); + bos.WriteByte(Convert.ToByte(value >> 16 & 0xFF)); + bos.WriteByte(Convert.ToByte(value >> 8 & 0xFF)); + bos.WriteByte(Convert.ToByte(value & 0xFF)); + } + + public void WriteBigNum(BigInteger n) + { + WriteBlock(n.ToByteArray()); + } + + 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); + } + } + + public void WriteBytes(byte[] value) + { + try + { + bos.Write(value, 0, value.Length); + } + catch (IOException e) + { + throw new InvalidOperationException(e.Message, e); + } + } + + public void WriteString(string str) + { + WriteBlock(Strings.ToByteArray(str)); + } + + public byte[] GetBytes() + { + return bos.ToArray(); + } + + public byte[] GetPaddedBytes() + { + return GetPaddedBytes(8); + } + + public byte[] GetPaddedBytes(int blockSize) + { + int align = (int)bos.Length % blockSize; + if (0 != align) + { + int padCount = blockSize - align; + for (int i = 1; i <= padCount; ++i) + { + bos.WriteByte(Convert.ToByte(i)); + } + } + return bos.ToArray(); + } + } +} diff --git a/crypto/src/crypto/util/SshNamedCurves.cs b/crypto/src/crypto/util/SshNamedCurves.cs new file mode 100644 index 000000000..d97c2476e --- /dev/null +++ b/crypto/src/crypto/util/SshNamedCurves.cs @@ -0,0 +1,93 @@ +using System.Collections.Generic; +using System.Linq; + +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; + +namespace Org.BouncyCastle.Crypto.Utilities +{ + public class SshNamedCurves + { + private static readonly Dictionary OidMap = + new Dictionary + { + { "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 CurveNameToSSHName = + new Dictionary + { + {"secp256r1", "nistp256"}, + {"secp384r1", "nistp384"}, + {"secp521r1", "nistp521"}, + {"sect163k1", "nistk163"}, + {"secp192r1", "nistp192"}, + {"secp224r1", "nistp224"}, + {"sect233k1", "nistk233"}, + {"sect233r1", "nistb233"}, + {"sect283k1", "nistk283"}, + {"sect409k1", "nistk409"}, + {"sect409r1", "nistb409"}, + {"sect571k1", "nistt571"} + }; + + private static readonly Dictionary CurveMap = + CustomNamedCurves.Names.ToDictionary(k => CustomNamedCurves.GetByNameLazy(k).Curve, v => v); + + private static readonly Dictionary OidToName = + OidMap.ToDictionary(k => k.Value, v => v.Key); + + + public static DerObjectIdentifier GetByName(string sshName) + { + return OidMap[sshName]; + } + + public static X9ECParameters GetParameters(string sshName) + { + return NistNamedCurves.GetByOid(OidMap[sshName.ToLower()]); + } + + public static X9ECParameters GetParameters(DerObjectIdentifier oid) + { + return NistNamedCurves.GetByOid(oid); + } + + public static string GetName(DerObjectIdentifier oid) + { + return OidToName[oid]; + } + + public static string GetNameForParameters(ECDomainParameters parameters) + { + if (parameters is ECNamedDomainParameters) + { + return GetName(((ECNamedDomainParameters)parameters).Name); + } + + return GetNameForParameters(parameters.Curve); + } + + public static string GetNameForParameters(ECCurve curve) + { + return CurveNameToSSHName[CurveMap[curve]]; + } + } +} diff --git a/crypto/src/util/ssh/OpenSSHPrivateKeyUtil.cs b/crypto/src/util/ssh/OpenSSHPrivateKeyUtil.cs deleted file mode 100644 index 0ddd90773..000000000 --- a/crypto/src/util/ssh/OpenSSHPrivateKeyUtil.cs +++ /dev/null @@ -1,302 +0,0 @@ -using System; - -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.Nist; -using Org.BouncyCastle.Asn1.Pkcs; -using Org.BouncyCastle.Asn1.Sec; -using Org.BouncyCastle.Asn1.X9; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Math; -using Org.BouncyCastle.Pkcs; - -namespace Org.BouncyCastle.Utilities.SSH -{ - public static class OpenSshPrivateKeyUtilities - { - ///

Magic value for proprietary OpenSSH private key. - /// C string so null terminated. - private static readonly byte[] AUTH_MAGIC = Strings.ToByteArray("openssh-key-v1\0"); - - /** - * Encode a cipher parameters into an OpenSSH private key. - * This does not add headers like ----BEGIN RSA PRIVATE KEY---- - * - * @param parameters the cipher parameters. - * @return a byte array - */ - public static byte[] EncodePrivateKey(AsymmetricKeyParameter parameters) - { - if (parameters == null) - throw new ArgumentNullException(nameof(parameters)); - - if (parameters is RsaPrivateCrtKeyParameters || parameters is ECPrivateKeyParameters) - { - PrivateKeyInfo pInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(parameters); - return pInfo.ParsePrivateKey().GetEncoded(); - } - else if (parameters is DsaPrivateKeyParameters dsaPrivateKey) - { - DsaParameters dsaparameters = dsaPrivateKey.Parameters; - - Asn1EncodableVector vec = new Asn1EncodableVector - { - new DerInteger(0), - new DerInteger(dsaparameters.P), - new DerInteger(dsaparameters.Q), - new DerInteger(dsaparameters.G) - }; - - // public key = g.modPow(x, p); - BigInteger pubKey = dsaparameters.P.ModPow(dsaPrivateKey.X, dsaparameters.P); - vec.Add(new DerInteger(pubKey)); - vec.Add(new DerInteger(dsaPrivateKey.X)); - try - { - return new DerSequence(vec).GetEncoded(); - } - catch (Exception ex) - { - throw new InvalidOperationException("unable to encode DSAPrivateKeyParameters " + ex.Message); - } - } - else if (parameters is Ed25519PrivateKeyParameters ed25519PrivateKey) - { - Ed25519PublicKeyParameters publicKeyParameters = ed25519PrivateKey.GeneratePublicKey(); - - SshBuilder builder = new SshBuilder(); - builder.WriteBytes(AUTH_MAGIC); - builder.WriteString("none"); // cipher name - builder.WriteString("none"); // KDF name - builder.WriteString(""); // KDF options - - builder.U32(1); // Number of keys - - { - byte[] pkEncoded = OpenSshPublicKeyUtilities.EncodePublicKey(publicKeyParameters); - builder.WriteBlock(pkEncoded); - } - - { - SshBuilder pkBuild = new SshBuilder(); - - int checkint = CryptoServicesRegistrar.GetSecureRandom().NextInt(); - pkBuild.U32((uint)checkint); - pkBuild.U32((uint)checkint); - - pkBuild.WriteString("ssh-ed25519"); - - // Public key (as part of private key pair) - byte[] pubKeyEncoded = publicKeyParameters.GetEncoded(); - pkBuild.WriteBlock(pubKeyEncoded); - - // The private key in SSH is 64 bytes long and is the concatenation of the private and the public keys - pkBuild.WriteBlock(Arrays.Concatenate(ed25519PrivateKey.GetEncoded(), pubKeyEncoded)); - - // Comment for this private key (empty) - pkBuild.WriteString(""); - - builder.WriteBlock(pkBuild.GetPaddedBytes()); - } - - return builder.GetBytes(); - } - - throw new ArgumentException("unable to convert " + parameters.GetType().Name + " to openssh private key"); - - } - - /** - * Parse a private key. - *

- * This method accepts the body of the OpenSSH private key. - * The easiest way to extract the body is to use PemReader, for example: - *

- * byte[] blob = new PemReader([reader]).readPemObject().getContent(); - * CipherParameters params = parsePrivateKeyBlob(blob); - * - * @param blob The key. - * @return A cipher parameters instance. - */ - public static AsymmetricKeyParameter ParsePrivateKeyBlob(byte[] blob) - { - AsymmetricKeyParameter result = null; - - if (blob[0] == 0x30) - { - Asn1Sequence sequence = Asn1Sequence.GetInstance(blob); - - if (sequence.Count == 6) - { - if (AllIntegers(sequence) && ((DerInteger)sequence[0]).PositiveValue.Equals(BigIntegers.Zero)) - { - // length of 6 and all Integers -- DSA - result = new DsaPrivateKeyParameters( - ((DerInteger)sequence[5]).PositiveValue, - new DsaParameters( - ((DerInteger)sequence[1]).PositiveValue, - ((DerInteger)sequence[2]).PositiveValue, - ((DerInteger)sequence[3]).PositiveValue) - ); - } - } - else if (sequence.Count == 9) - { - if (AllIntegers(sequence) && ((DerInteger)sequence[0]).PositiveValue.Equals(BigIntegers.Zero)) - { - // length of 8 and all Integers -- RSA - RsaPrivateKeyStructure rsaPrivateKey = RsaPrivateKeyStructure.GetInstance(sequence); - - result = new RsaPrivateCrtKeyParameters( - rsaPrivateKey.Modulus, - rsaPrivateKey.PublicExponent, - rsaPrivateKey.PrivateExponent, - rsaPrivateKey.Prime1, - rsaPrivateKey.Prime2, - rsaPrivateKey.Exponent1, - rsaPrivateKey.Exponent2, - rsaPrivateKey.Coefficient); - } - } - else if (sequence.Count == 4) - { - if (sequence[3] is Asn1TaggedObject && sequence[2] is Asn1TaggedObject) - { - ECPrivateKeyStructure ecPrivateKey = ECPrivateKeyStructure.GetInstance(sequence); - DerObjectIdentifier curveOID = DerObjectIdentifier.GetInstance(ecPrivateKey.GetParameters()); - X9ECParameters x9Params = ECNamedCurveTable.GetByOid(curveOID); - result = new ECPrivateKeyParameters( - ecPrivateKey.GetKey(), - new ECNamedDomainParameters( - curveOID, - x9Params)); - } - } - } - else - { - SshBuffer kIn = new SshBuffer(AUTH_MAGIC, blob); - - String cipherName = kIn.ReadString(); - if (!"none".Equals(cipherName)) - { - throw new InvalidOperationException("encrypted keys not supported"); - } - - // KDF name - kIn.SkipBlock(); - - // KDF options - kIn.SkipBlock(); - - int publicKeyCount = kIn.ReadU32(); - if (publicKeyCount != 1) - { - throw new InvalidOperationException("multiple keys not supported"); - } - - // Burn off public key. - OpenSshPublicKeyUtilities.ParsePublicKey(kIn.ReadBlock()); - - 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(); - - if ("ssh-ed25519".Equals(keyType)) - { - // Public key - pkIn.ReadBlock(); - // Private key value.. - byte[] edPrivateKey = pkIn.ReadBlock(); - if (edPrivateKey.Length != Ed25519PrivateKeyParameters.KeySize + Ed25519PublicKeyParameters.KeySize) - { - throw new InvalidOperationException("private key value of wrong length"); - } - - result = new Ed25519PrivateKeyParameters(edPrivateKey, 0); - } - else if (keyType.StartsWith("ecdsa")) - { - DerObjectIdentifier oid = SshNamedCurves.GetByName(Strings.FromByteArray(pkIn.ReadBlock())) ?? - throw new InvalidOperationException("OID not found for: " + keyType); - X9ECParameters curveParams = NistNamedCurves.GetByOid(oid) ?? throw new InvalidOperationException("Curve not found for: " + oid); - - // Skip public key. - pkIn.ReadBlock(); - byte[] privKey = pkIn.ReadBlock(); - - result = new ECPrivateKeyParameters(new BigInteger(1, privKey), - new ECNamedDomainParameters(oid, curveParams)); - } - 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 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); - } - - // 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; - } - - /** - * allIntegers returns true if the sequence holds only DerInteger types. - **/ - private static Boolean AllIntegers(Asn1Sequence sequence) - { - for (int t = 0; t < sequence.Count; t++) - { - if (!(sequence[t] is DerInteger)) - { - return false; - } - } - return true; - } -} -} diff --git a/crypto/src/util/ssh/OpenSSHPublicKeyUtil.cs b/crypto/src/util/ssh/OpenSSHPublicKeyUtil.cs deleted file mode 100644 index 02e6928e0..000000000 --- a/crypto/src/util/ssh/OpenSSHPublicKeyUtil.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; - -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.X9; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Math; - -namespace Org.BouncyCastle.Utilities.SSH -{ - public static class OpenSshPublicKeyUtilities - { - private static readonly String RSA = "ssh-rsa"; - private static readonly String ECDSA = "ecdsa"; - private static readonly String ED_25519 = "ssh-ed25519"; - private static readonly String DSS = "ssh-dss"; - - /** - * Parse a public key. - *

- * This method accepts the bytes that are Base64 encoded in an OpenSSH public key file. - * - * @param encoded The key. - * @return An AsymmetricKeyParameter instance. - */ - public static AsymmetricKeyParameter ParsePublicKey(byte[] encoded) - { - SshBuffer buffer = new SshBuffer(encoded); - return ParsePublicKey(buffer); - } - - /** - * Encode a public key from an AsymmetricKeyParameter instance. - * - * @param cipherParameters The key to encode. - * @return the key OpenSSH encoded. - * @throws IOException - */ - public static byte[] EncodePublicKey(AsymmetricKeyParameter cipherParameters) - { - if (cipherParameters == null) - { - throw new ArgumentException("cipherParameters was null."); - } - - if (cipherParameters is RsaKeyParameters) - { - 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); - - return builder.GetBytes(); - - } - else if (cipherParameters is ECPublicKeyParameters ecPublicKey) - { - SshBuilder builder = new SshBuilder(); - - // - // checked for named curve parameters.. - // - String name = SshNamedCurves.GetNameForParameters(ecPublicKey.Parameters); - - if (name == null) - { - throw new ArgumentException("unable to derive ssh curve name for " + ecPublicKey.Parameters.Curve.GetType().Name); - } - - builder.WriteString(ECDSA + "-sha2-" + name); // Magic - builder.WriteString(name); - builder.WriteBlock(ecPublicKey.Q.GetEncoded(false)); //Uncompressed - return builder.GetBytes(); - } - else if (cipherParameters is DsaPublicKeyParameters dsaPubKey) - { - 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); - return builder.GetBytes(); - } - else if (cipherParameters is Ed25519PublicKeyParameters ed25519PublicKey) - { - SshBuilder builder = new SshBuilder(); - builder.WriteString(ED_25519); - builder.WriteBlock(ed25519PublicKey.GetEncoded()); - return builder.GetBytes(); - } - - throw new ArgumentException("unable to convert " + cipherParameters.GetType().Name + " to private key"); - } - - /** - * Parse a public key from an SSHBuffer instance. - * - * @param buffer containing the SSH public key. - * @return A CipherParameters instance. - */ - private static AsymmetricKeyParameter ParsePublicKey(SshBuffer buffer) - { - AsymmetricKeyParameter result = null; - - string magic = buffer.ReadString(); - if (RSA.Equals(magic)) - { - BigInteger e = buffer.ReadBigNumPositive(); - BigInteger n = buffer.ReadBigNumPositive(); - 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(); - - 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)); - } - else if (ED_25519.Equals(magic)) - { - byte[] pubKeyBytes = buffer.ReadBlock(); - if (pubKeyBytes.Length != Ed25519PublicKeyParameters.KeySize) - { - throw new InvalidOperationException("public key value of wrong length"); - } - - result = new Ed25519PublicKeyParameters(pubKeyBytes, 0); - } - - 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/util/ssh/SSHBuffer.cs b/crypto/src/util/ssh/SSHBuffer.cs deleted file mode 100644 index 795641032..000000000 --- a/crypto/src/util/ssh/SSHBuffer.cs +++ /dev/null @@ -1,151 +0,0 @@ -using System; - -using Org.BouncyCastle.Math; - -namespace Org.BouncyCastle.Utilities.SSH -{ - internal class SshBuffer - { - private readonly byte[] buffer; - private int pos = 0; - - internal SshBuffer(byte[] magic, byte[] buffer) - { - this.buffer = buffer; - for (int i = 0; i != magic.Length; i++) - { - if (magic[i] != buffer[i]) - { - throw new ArgumentException("magic-number incorrect"); - } - } - - pos += magic.Length; - } - - internal SshBuffer(byte[] buffer) - { - this.buffer = buffer; - } - - 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); - - return i; - } - - public String ReadString() - { - return Strings.FromByteArray(ReadBlock()); - } - - public byte[] ReadBlock() - { - int len = ReadU32(); - if (len == 0) - { - return new byte[0]; - } - - if (pos > (buffer.Length - len)) - { - throw new ArgumentException("not enough data for block"); - } - - int start = pos; pos += len; - return Arrays.CopyOfRange(buffer, start, pos); - } - - public void SkipBlock() - { - int len = ReadU32(); - if (pos > (buffer.Length - len)) - { - throw new ArgumentException("not enough data for block"); - } - - pos += len; - } - - public byte[] ReadPaddedBlock() - { - return ReadPaddedBlock(8); - } - - public byte[] ReadPaddedBlock(int blockSize) - { - int len = ReadU32(); - if (len == 0) - { - return new byte[0]; - } - - if (pos > (buffer.Length - len)) - { - throw new ArgumentException("not enough data for block"); - } - - int align = len % blockSize; - if (0 != align) - { - throw new ArgumentException("missing padding"); - } - - int start = pos; pos += len; - int end = pos; - - if (len > 0) - { - // TODO If encryption is supported, should be constant-time - int lastByte = buffer[pos - 1] & 0xFF; - if (0 < lastByte && lastByte < blockSize) - { - int padCount = lastByte; - end -= padCount; - - for (int i = 1, padPos = end; i <= padCount; ++i, ++padPos) - { - if (i != (buffer[padPos] & 0xFF)) - { - throw new ArgumentException("incorrect padding"); - } - } - } - } - - return Arrays.CopyOfRange(buffer, start, end); - } - - public BigInteger ReadBigNumPositive() - { - int len = ReadU32(); - if (pos + len > buffer.Length) - { - throw new ArgumentException("not enough data for big num"); - } - - int start = pos; pos += len; - byte[] d = Arrays.CopyOfRange(buffer, start, pos); - return new BigInteger(1, d); - } - - public byte[] GetBuffer() - { - return Arrays.Clone(buffer); - } - - public Boolean HasRemaining() - { - return pos < buffer.Length; - } - } -} diff --git a/crypto/src/util/ssh/SSHBuilder.cs b/crypto/src/util/ssh/SSHBuilder.cs deleted file mode 100644 index 24121d0d8..000000000 --- a/crypto/src/util/ssh/SSHBuilder.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.IO; - -using Org.BouncyCastle.Math; - -namespace Org.BouncyCastle.Utilities.SSH -{ - internal class SshBuilder - { - private readonly MemoryStream bos = new MemoryStream(); - - public void U32(uint value) - { - bos.WriteByte(Convert.ToByte((value >> 24) & 0xFF)); - bos.WriteByte(Convert.ToByte((value >> 16) & 0xFF)); - bos.WriteByte(Convert.ToByte((value >> 8) & 0xFF)); - bos.WriteByte(Convert.ToByte(value & 0xFF)); - } - - public void WriteBigNum(BigInteger n) - { - WriteBlock(n.ToByteArray()); - } - - 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); - } - } - - public void WriteBytes(byte[] value) - { - try - { - bos.Write(value, 0, value.Length); - } - catch (IOException e) - { - throw new InvalidOperationException(e.Message, e); - } - } - - public void WriteString(String str) - { - WriteBlock(Strings.ToByteArray(str)); - } - - public byte[] GetBytes() - { - return bos.ToArray(); - } - - public byte[] GetPaddedBytes() - { - return GetPaddedBytes(8); - } - - public byte[] GetPaddedBytes(int blockSize) - { - int align = (int)bos.Length % blockSize; - if (0 != align) - { - int padCount = blockSize - align; - for (int i = 1; i <= padCount; ++i) - { - bos.WriteByte(Convert.ToByte(i)); - } - } - return bos.ToArray(); - } - } -} diff --git a/crypto/src/util/ssh/SSHNamedCurves.cs b/crypto/src/util/ssh/SSHNamedCurves.cs deleted file mode 100644 index 6839627b8..000000000 --- a/crypto/src/util/ssh/SSHNamedCurves.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -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; - -namespace Org.BouncyCastle.Utilities.SSH -{ - public class SshNamedCurves - { - private static readonly Dictionary OidMap = - new Dictionary - { - { "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 CurveNameToSSHName = - new Dictionary - { - {"secp256r1", "nistp256"}, - {"secp384r1", "nistp384"}, - {"secp521r1", "nistp521"}, - {"sect163k1", "nistk163"}, - {"secp192r1", "nistp192"}, - {"secp224r1", "nistp224"}, - {"sect233k1", "nistk233"}, - {"sect233r1", "nistb233"}, - {"sect283k1", "nistk283"}, - {"sect409k1", "nistk409"}, - {"sect409r1", "nistb409"}, - {"sect571k1", "nistt571"} - }; - - private static readonly Dictionary CurveMap = - CustomNamedCurves.Names.ToDictionary(k => CustomNamedCurves.GetByNameLazy(k).Curve, v => v); - - private static readonly Dictionary OidToName = - OidMap.ToDictionary(k => k.Value, v => v.Key); - - - public static DerObjectIdentifier GetByName(string sshName) - { - return OidMap[sshName]; - } - - public static X9ECParameters GetParameters(string sshName) - { - return NistNamedCurves.GetByOid(OidMap[sshName.ToLower()]); - } - - public static X9ECParameters GetParameters(DerObjectIdentifier oid) - { - return NistNamedCurves.GetByOid(oid); - } - - public static string GetName(DerObjectIdentifier oid) - { - return OidToName[oid]; - } - - public static string GetNameForParameters(ECDomainParameters parameters) - { - if (parameters is ECNamedDomainParameters) - { - return GetName(((ECNamedDomainParameters)parameters).Name); - } - - return GetNameForParameters(parameters.Curve); - } - - public static string GetNameForParameters(ECCurve curve) - { - return CurveNameToSSHName[CurveMap[curve]]; - } - } -} -- cgit 1.4.1