From e6d689a505ae4425e3aeeab864469b00da0f8ac4 Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Mon, 16 Sep 2024 16:16:39 +0800 Subject: [PATCH 1/7] Add support for OpenSSL PKCS#8 private key format --- README.md | 28 +- src/Renci.SshNet/PrivateKeyConnectionInfo.cs | 2 +- src/Renci.SshNet/PrivateKeyFile.cs | 357 ++++++++++++++++-- .../Security/Cryptography/DsaKey.cs | 37 +- .../Security/Cryptography/EcdsaKey.cs | 27 +- .../Security/Cryptography/RsaKey.cs | 38 +- ....PKCS8.DSA.Encrypted.Aes.256.CBC.12345.txt | 18 + test/Data/Key.PKCS8.DSA.pub | 20 + test/Data/Key.PKCS8.DSA.txt | 15 + ...KCS8.ECDSA.Encrypted.Aes.256.CBC.12345.txt | 7 + test/Data/Key.PKCS8.ECDSA.pub | 4 + test/Data/Key.PKCS8.ECDSA.txt | 5 + ...S8.ED25519.Encrypted.Aes.256.CBC.12345.txt | 6 + test/Data/Key.PKCS8.ED25519.pub | 3 + test/Data/Key.PKCS8.ED25519.txt | 3 + ....PKCS8.RSA.Encrypted.Aes.256.CBC.12345.txt | 30 ++ test/Data/Key.PKCS8.RSA.pub | 9 + test/Data/Key.PKCS8.RSA.txt | 28 ++ .../Classes/PrivateKeyFileTest.cs | 88 +++++ 19 files changed, 605 insertions(+), 120 deletions(-) create mode 100644 test/Data/Key.PKCS8.DSA.Encrypted.Aes.256.CBC.12345.txt create mode 100644 test/Data/Key.PKCS8.DSA.pub create mode 100644 test/Data/Key.PKCS8.DSA.txt create mode 100644 test/Data/Key.PKCS8.ECDSA.Encrypted.Aes.256.CBC.12345.txt create mode 100644 test/Data/Key.PKCS8.ECDSA.pub create mode 100644 test/Data/Key.PKCS8.ECDSA.txt create mode 100644 test/Data/Key.PKCS8.ED25519.Encrypted.Aes.256.CBC.12345.txt create mode 100644 test/Data/Key.PKCS8.ED25519.pub create mode 100644 test/Data/Key.PKCS8.ED25519.txt create mode 100644 test/Data/Key.PKCS8.RSA.Encrypted.Aes.256.CBC.12345.txt create mode 100644 test/Data/Key.PKCS8.RSA.pub create mode 100644 test/Data/Key.PKCS8.RSA.txt diff --git a/README.md b/README.md index b3cc4ec1d..54de905ee 100644 --- a/README.md +++ b/README.md @@ -96,12 +96,23 @@ The main types provided by this library are: ## Public Key Authentication **SSH.NET** supports the following private key formats: -* RSA in OpenSSL PEM ("BEGIN RSA PRIVATE KEY") and ssh.com ("BEGIN SSH2 ENCRYPTED PRIVATE KEY") format -* DSA in OpenSSL PEM ("BEGIN DSA PRIVATE KEY") and ssh.com ("BEGIN SSH2 ENCRYPTED PRIVATE KEY") format -* ECDSA 256/384/521 in OpenSSL PEM format ("BEGIN EC PRIVATE KEY") -* ECDSA 256/384/521, ED25519 and RSA in OpenSSH key format ("BEGIN OPENSSH PRIVATE KEY") - -Private keys in OpenSSL PEM and ssh.com format can be encrypted using one of the following cipher methods: +* RSA in + * OpenSSL traditional PEM format ("BEGIN RSA PRIVATE KEY") + * OpenSSL PKCS#8 PEM format ("BEGIN PRIVATE KEY", "BEGIN ENCRYPTED PRIVATE KEY") + * ssh.com format ("BEGIN SSH2 ENCRYPTED PRIVATE KEY") + * OpenSSH key format ("BEGIN OPENSSH PRIVATE KEY") +* DSA in + * OpenSSL traditional PEM format ("BEGIN DSA PRIVATE KEY") + * OpenSSL PKCS#8 PEM format ("BEGIN PRIVATE KEY", "BEGIN ENCRYPTED PRIVATE KEY") + * ssh.com format ("BEGIN SSH2 ENCRYPTED PRIVATE KEY") +* ECDSA 256/384/521 in + * OpenSSL traditional PEM format ("BEGIN EC PRIVATE KEY") + * OpenSSL PKCS#8 PEM format ("BEGIN PRIVATE KEY", "BEGIN ENCRYPTED PRIVATE KEY") + * OpenSSH key format ("BEGIN OPENSSH PRIVATE KEY") +* ED25519 in + * OpenSSH key format ("BEGIN OPENSSH PRIVATE KEY") + +Private keys in OpenSSL traditional PEM format can be encrypted using one of the following cipher methods: * DES-EDE3-CBC * DES-EDE3-CFB * DES-CBC @@ -109,6 +120,11 @@ Private keys in OpenSSL PEM and ssh.com format can be encrypted using one of the * AES-192-CBC * AES-256-CBC +Private keys in OpenSSL PKCS#8 PEM format can be encrypted using any cipher method BouncyCastle supports. + +Private keys in ssh.com format can be encrypted using one of the following cipher methods: +* 3des-cbc + Private keys in OpenSSH key format can be encrypted using one of the following cipher methods: * 3des-cbc * aes128-cbc diff --git a/src/Renci.SshNet/PrivateKeyConnectionInfo.cs b/src/Renci.SshNet/PrivateKeyConnectionInfo.cs index 86d50a2fd..e1de72d02 100644 --- a/src/Renci.SshNet/PrivateKeyConnectionInfo.cs +++ b/src/Renci.SshNet/PrivateKeyConnectionInfo.cs @@ -22,7 +22,7 @@ public class PrivateKeyConnectionInfo : ConnectionInfo, IDisposable /// Connection host. /// Connection username. /// Connection key files. - public PrivateKeyConnectionInfo(string host, string username, params PrivateKeyFile[] keyFiles) + public PrivateKeyConnectionInfo(string host, string username, params IPrivateKeySource[] keyFiles) : this(host, DefaultPort, username, ProxyTypes.None, string.Empty, 0, string.Empty, string.Empty, keyFiles) { } diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index bdc9a4c91..95164d9d7 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Formats.Asn1; using System.Globalization; using System.IO; using System.Numerics; @@ -8,6 +9,12 @@ using System.Text; using System.Text.RegularExpressions; +using Org.BouncyCastle.Asn1.EdEC; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto.Utilities; +using Org.BouncyCastle.Pkcs; + using Renci.SshNet.Common; using Renci.SshNet.Security; using Renci.SshNet.Security.Cryptography; @@ -39,7 +46,7 @@ namespace Renci.SshNet /// /// /// - /// The following encryption algorithms are supported for OpenSSL PEM and ssh.com format: + /// The following encryption algorithms are supported for OpenSSL traditional PEM: /// /// /// DES-EDE3-CBC @@ -60,6 +67,19 @@ namespace Renci.SshNet /// AES-256-CBC /// /// + /// + /// + /// Private keys in OpenSSL PKCS#8 PEM format can be encrypted using any cipher method BouncyCastle supports. + /// + /// + /// The following encryption algorithms are supported for ssh.com format: + /// + /// + /// 3des-cbc + /// + /// + /// + /// /// The following encryption algorithms are supported for OpenSSH format: /// /// @@ -97,7 +117,7 @@ namespace Renci.SshNet /// public partial class PrivateKeyFile : IPrivateKeySource, IDisposable { - private const string PrivateKeyPattern = @"^-+ *BEGIN (?\w+( \w+)*) PRIVATE KEY *-+\r?\n((Proc-Type: 4,ENCRYPTED\r?\nDEK-Info: (?[A-Z0-9-]+),(?[A-F0-9]+)\r?\n\r?\n)|(Comment: ""?[^\r\n]*""?\r?\n))?(?([a-zA-Z0-9/+=]{1,80}\r?\n)+)(\r?\n)?-+ *END \k PRIVATE KEY *-+"; + private const string PrivateKeyPattern = @"^-+ *BEGIN (?\w+( \w+)*) *-+\r?\n((Proc-Type: 4,ENCRYPTED\r?\nDEK-Info: (?[A-Z0-9-]+),(?[A-F0-9]+)\r?\n\r?\n)|(Comment: ""?[^\r\n]*""?\r?\n))?(?([a-zA-Z0-9/+=]{1,80}\r?\n)+)(\r?\n)?-+ *END \k *-+"; #if NET7_0_OR_GREATER private static readonly Regex PrivateKeyRegex = GetPrivateKeyRegex(); @@ -231,6 +251,11 @@ private void Open(Stream privateKey, string passPhrase) } var keyName = privateKeyMatch.Result("${keyName}"); + if (!keyName.EndsWith("PRIVATE KEY", StringComparison.Ordinal)) + { + throw new SshException("Invalid private key file."); + } + var cipherName = privateKeyMatch.Result("${cipherName}"); var salt = privateKeyMatch.Result("${salt}"); var data = privateKeyMatch.Result("${data}"); @@ -286,40 +311,28 @@ private void Open(Stream privateKey, string passPhrase) switch (keyName) { - case "RSA": - var rsaKey = new RsaKey(decryptedData); - _key = rsaKey; - _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); -#pragma warning disable CA2000 // Dispose objects before losing scope - _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(rsaKey, HashAlgorithmName.SHA512))); - _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(rsaKey, HashAlgorithmName.SHA256))); -#pragma warning restore CA2000 // Dispose objects before losing scope + case "RSA PRIVATE KEY": + _key = ParseRSAPrivateKey_Pkcs1(decryptedData); + break; + case "DSA PRIVATE KEY": + _key = ParseDSSPrivateKey_OpenSSL(decryptedData); + break; + case "EC PRIVATE KEY": + _key = ParseECPrivateKey_SEC1(decryptedData); break; - case "DSA": - _key = new DsaKey(decryptedData); - _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-dss", _key)); + case "PRIVATE KEY": + var privateKeyInfo = PrivateKeyInfo.GetInstance(binaryData); + _key = ParsePkcs8PrivateKey(privateKeyInfo); break; - case "EC": - _key = new EcdsaKey(decryptedData); - _hostAlgorithms.Add(new KeyHostAlgorithm(_key.ToString(), _key)); + case "ENCRYPTED PRIVATE KEY": + var encryptedPrivateKeyInfo = EncryptedPrivateKeyInfo.GetInstance(binaryData); + privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(passPhrase.ToCharArray(), encryptedPrivateKeyInfo); + _key = ParsePkcs8PrivateKey(privateKeyInfo); break; - case "OPENSSH": + case "OPENSSH PRIVATE KEY": _key = ParseOpenSshV1Key(decryptedData, passPhrase); - if (_key is RsaKey parsedRsaKey) - { - _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); -#pragma warning disable CA2000 // Dispose objects before losing scope - _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(parsedRsaKey, HashAlgorithmName.SHA512))); - _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(parsedRsaKey, HashAlgorithmName.SHA256))); -#pragma warning restore CA2000 // Dispose objects before losing scope - } - else - { - _hostAlgorithms.Add(new KeyHostAlgorithm(_key.ToString(), _key)); - } - break; - case "SSH2 ENCRYPTED": + case "SSH2 ENCRYPTED PRIVATE KEY": var reader = new SshDataReader(decryptedData); var magicNumber = reader.ReadUInt32(); if (magicNumber != 0x3f6ff9eb) @@ -374,13 +387,7 @@ private void Open(Stream privateKey, string passPhrase) var inverseQ = reader.ReadBigIntWithBits(); // u var q = reader.ReadBigIntWithBits(); // p var p = reader.ReadBigIntWithBits(); // q - var decryptedRsaKey = new RsaKey(modulus, exponent, d, p, q, inverseQ); - _key = decryptedRsaKey; - _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); -#pragma warning disable CA2000 // Dispose objects before losing scope - _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(decryptedRsaKey, HashAlgorithmName.SHA512))); - _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(decryptedRsaKey, HashAlgorithmName.SHA256))); -#pragma warning restore CA2000 // Dispose objects before losing scope + _key = new RsaKey(modulus, exponent, d, p, q, inverseQ); } else if (keyType.Contains("dsa")) { @@ -396,7 +403,6 @@ private void Open(Stream privateKey, string passPhrase) var y = reader.ReadBigIntWithBits(); var x = reader.ReadBigIntWithBits(); _key = new DsaKey(p, q, g, y, x); - _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-dss", _key)); } else { @@ -407,6 +413,19 @@ private void Open(Stream privateKey, string passPhrase) default: throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Key '{0}' is not supported.", keyName)); } + + if (_key is RsaKey parsedRsaKey) + { + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); +#pragma warning disable CA2000 // Dispose objects before losing scope + _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(parsedRsaKey, HashAlgorithmName.SHA512))); + _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(parsedRsaKey, HashAlgorithmName.SHA256))); +#pragma warning restore CA2000 // Dispose objects before losing scope + } + else + { + _hostAlgorithms.Add(new KeyHostAlgorithm(_key.ToString(), _key)); + } } private static byte[] GetCipherKey(string passphrase, int length) @@ -678,14 +697,15 @@ private static Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) case "ecdsa-sha2-nistp521": // curve var len = (int)privateKeyReader.ReadUInt32(); - var curve = Encoding.ASCII.GetString(privateKeyReader.ReadBytes(len)); + var curveName = Encoding.ASCII.GetString(privateKeyReader.ReadBytes(len)); + var curveOid = SshNamedCurves.GetOid(curveName).GetID(); // public key publicKey = privateKeyReader.ReadBignum2(); // private key unencryptedPrivateKey = privateKeyReader.ReadBignum2(); - parsedKey = new EcdsaKey(curve, publicKey, unencryptedPrivateKey.TrimLeadingZeros()); + parsedKey = new EcdsaKey(curveOid, publicKey, unencryptedPrivateKey); break; case "ssh-rsa": var modulus = privateKeyReader.ReadBignum(); // n @@ -717,6 +737,261 @@ private static Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) return parsedKey; } + /// + /// Parses PKCS#8 PrivateKeyInfo. + /// + /// The PKCS#8 PrivateKeyInfo. + /// + /// . + /// + /// The . + /// Algorithm not supported. + private static Key ParsePkcs8PrivateKey(PrivateKeyInfo privateKeyInfo) + { + var algorithmOid = privateKeyInfo.PrivateKeyAlgorithm.Algorithm; + var key = privateKeyInfo.PrivateKey.GetOctets(); + if (algorithmOid.Equals(PkcsObjectIdentifiers.RsaEncryption)) + { + return ParseRSAPrivateKey_Pkcs1(key); + } + + if (algorithmOid.Equals(X9ObjectIdentifiers.IdDsa)) + { + var parameters = privateKeyInfo.PrivateKeyAlgorithm.Parameters.GetDerEncoded(); + return ParseDSAPrivateKey_Pkcs8_OpenSSL(parameters, key); + } + + if (algorithmOid.Equals(X9ObjectIdentifiers.IdECPublicKey)) + { + var parameters2 = privateKeyInfo.PrivateKeyAlgorithm.Parameters.GetDerEncoded(); + return ParseECPrivateKey_Pkcs8_OpenSSL(parameters2, key); + } + + if (algorithmOid.Equals(EdECObjectIdentifiers.id_Ed25519)) + { + return new ED25519Key(key); + } + + throw new SshException(string.Format(CultureInfo.InvariantCulture, "Private key algorithm \"{0}\" is not supported.", algorithmOid)); + } + + /// + /// Parses PKCS#1 RSA private key. + /// + /// + /// . + /// + /// RSAPrivateKey ::= SEQUENCE { + /// version INTEGER, + /// modulus INTEGER, -- n + /// publicExponent INTEGER, -- e + /// privateExponent INTEGER, -- d + /// prime1 INTEGER, -- p + /// prime2 INTEGER, -- q + /// exponent1 INTEGER, -- d mod (p-1) + /// exponent2 INTEGER, -- d mod (q-1) + /// coefficient INTEGER -- (inverse of q) mod p + /// } + /// + /// + /// The key data. + /// The . + private static RsaKey ParseRSAPrivateKey_Pkcs1(byte[] keyData) + { + var keyReader = new AsnReader(keyData, AsnEncodingRules.BER); + var sequenceReader = keyReader.ReadSequence(); + + // Some key has extra byte, for example 'Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt' at the test data folder. + ////keyReader.ThrowIfNotEmpty(); + + var version = sequenceReader.ReadInteger(); + if (version != BigInteger.Zero) + { + throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "RSA version '{0}' is not supported.", version)); + } + + var modulus = sequenceReader.ReadInteger(); + var exponent = sequenceReader.ReadInteger(); + var d = sequenceReader.ReadInteger(); + var p = sequenceReader.ReadInteger(); + var q = sequenceReader.ReadInteger(); + var dp = sequenceReader.ReadInteger(); + var dq = sequenceReader.ReadInteger(); + var inverseQ = sequenceReader.ReadInteger(); + sequenceReader.ThrowIfNotEmpty(); + + return new RsaKey(modulus, exponent, d, p, q, dp, dq, inverseQ); + } + + /// + /// Parses OpenSSL DSA private key. + /// + /// The key data. + /// + /// OpenSSL produces ASN.1 DER encoded form of an ASN.1 SEQUENCE consisting of the values of + /// version (currently zero), p, q, g, the public and private key components respectively as ASN.1 INTEGERs. + /// . + /// + /// DSSPrivatKey_OpenSSL ::= SEQUENCE { + /// version INTEGER, + /// p INTEGER, + /// q INTEGER, + /// g INTEGER, + /// y INTEGER, + /// x INTEGER + /// } + /// + /// + /// The . + private static DsaKey ParseDSSPrivateKey_OpenSSL(byte[] keyData) + { + var keyReader = new AsnReader(keyData, AsnEncodingRules.BER); + var sequenceReader = keyReader.ReadSequence(); + keyReader.ThrowIfNotEmpty(); + + var version = sequenceReader.ReadInteger(); + if (version != BigInteger.Zero) + { + throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "DSA version '{0}' is not supported.", version)); + } + + var p = sequenceReader.ReadInteger(); + var q = sequenceReader.ReadInteger(); + var g = sequenceReader.ReadInteger(); + var y = sequenceReader.ReadInteger(); + var x = sequenceReader.ReadInteger(); + sequenceReader.ThrowIfNotEmpty(); + + return new DsaKey(p, q, g, y, x); + } + + /// + /// Parses OpenSSL DSA private key in Pkcs#8 format. + /// + /// The parameters data. + /// The key data. + /// + /// The format of PKCS#8 DSA (and other) private keys is not well documented: + /// it is hidden away in PKCS#11 v2.01, section 11.9. + /// OpenSSL's default DSA PKCS#8 private key format complies with this standard. + /// + /// . + /// + /// Dss-Parms ::= SEQUENCE { + /// p INTEGER, + /// q INTEGER, + /// g INTEGER + /// } + /// + /// DSAprivatekeys are represented as BER-encoded ASN.1 type INTEGER. + /// + /// The . + private static DsaKey ParseDSAPrivateKey_Pkcs8_OpenSSL(byte[] parametersData, byte[] keyData) + { + var parametersReader = new AsnReader(parametersData, AsnEncodingRules.BER); + var sequenceReader = parametersReader.ReadSequence(); + parametersReader.ThrowIfNotEmpty(); + + var p = sequenceReader.ReadInteger(); + var q = sequenceReader.ReadInteger(); + var g = sequenceReader.ReadInteger(); + sequenceReader.ThrowIfNotEmpty(); + + var keyReader = new AsnReader(keyData, AsnEncodingRules.BER); + var x = keyReader.ReadInteger(); + keyReader.ThrowIfNotEmpty(); + + var y = BigInteger.ModPow(g, x, p); + + return new DsaKey(p, q, g, y, x); + } + + /// + /// Parses OpenSSL EC private key. + /// + /// The key data. + /// + /// OpenSSL produces ASN.1 DER encoded SEC1 private key. + /// + /// . + /// Republished as RFC5915 , + /// See answer at . + /// + /// ECPrivateKey ::= SEQUENCE { + /// version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + /// privateKey OCTET STRING, + /// parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL, + /// publicKey [1] BIT STRING OPTIONAL + /// } + /// + /// When generating a transfer encoding, generators SHOULD use + /// Distinguished Encoding Rules (DER) and receivers SHOULD be + /// prepared to handle Basic Encoding Rules (BER) and DER. + /// + /// The . + private static EcdsaKey ParseECPrivateKey_SEC1(byte[] keyData) + { + var keyReader = new AsnReader(keyData, AsnEncodingRules.DER); + var sequenceReader = keyReader.ReadSequence(); + keyReader.ThrowIfNotEmpty(); + + var version = sequenceReader.ReadInteger(); + if (version != BigInteger.One) + { + throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "EC version '{0}' is not supported.", version)); + } + + var privatekey = sequenceReader.ReadOctetString(); + + var parametersReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0, isConstructed: true)); + var curve = parametersReader.ReadObjectIdentifier(); + parametersReader.ThrowIfNotEmpty(); + + var publicKeyReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1, isConstructed: true)); + var publickey = publicKeyReader.ReadBitString(out _); + publicKeyReader.ThrowIfNotEmpty(); + + sequenceReader.ThrowIfNotEmpty(); + + return new EcdsaKey(curve, publickey, privatekey); + } + + /// + /// Parses OpenSSL EC private key in Pkcs#8 format. + /// + /// The parameters data. + /// The key data. + /// + /// The format of PKCS#8 EC private keys is not well documented. + /// + /// The . + private static EcdsaKey ParseECPrivateKey_Pkcs8_OpenSSL(byte[] parametersData, byte[] keyData) + { + var parametersReader = new AsnReader(parametersData, AsnEncodingRules.DER); + var curve = parametersReader.ReadObjectIdentifier(); + parametersReader.ThrowIfNotEmpty(); + + var privateKeyReader = new AsnReader(keyData, AsnEncodingRules.DER); + var sequenceReader = privateKeyReader.ReadSequence(); + privateKeyReader.ThrowIfNotEmpty(); + + var version = sequenceReader.ReadInteger(); + if (version != BigInteger.One) + { + throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "EC version '{0}' is not supported.", version)); + } + + var privatekey = sequenceReader.ReadOctetString(); + + var publicKeyReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1, isConstructed: true)); + var publickey = publicKeyReader.ReadBitString(out _); + publicKeyReader.ThrowIfNotEmpty(); + + sequenceReader.ThrowIfNotEmpty(); + + return new EcdsaKey(curve, publickey, privatekey); + } + /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// diff --git a/src/Renci.SshNet/Security/Cryptography/DsaKey.cs b/src/Renci.SshNet/Security/Cryptography/DsaKey.cs index 41f62f059..a95dee614 100644 --- a/src/Renci.SshNet/Security/Cryptography/DsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/DsaKey.cs @@ -1,6 +1,5 @@ #nullable enable using System; -using System.Formats.Asn1; using System.Numerics; using System.Security.Cryptography; @@ -16,6 +15,17 @@ public class DsaKey : Key, IDisposable { private DsaDigitalSignature? _digitalSignature; + /// + /// Gets the SSH name of the DSA Key. + /// + /// + /// The SSH name of the DSA Key. + /// + public override string ToString() + { + return "ssh-dss"; + } + internal DSA DSA { get; } /// @@ -108,31 +118,6 @@ public DsaKey(SshKeyData publicKeyData) DSA = LoadDSA(); } - /// - /// Initializes a new instance of the class. - /// - /// DER encoded private key data. - public DsaKey(byte[] privateKeyData) - { - if (privateKeyData is null) - { - throw new ArgumentNullException(nameof(privateKeyData)); - } - - var der = new AsnReader(privateKeyData, AsnEncodingRules.DER).ReadSequence(); - _ = der.ReadInteger(); // skip version - - P = der.ReadInteger(); - Q = der.ReadInteger(); - G = der.ReadInteger(); - Y = der.ReadInteger(); - X = der.ReadInteger(); - - der.ThrowIfNotEmpty(); - - DSA = LoadDSA(); - } - /// /// Initializes a new instance of the class. /// diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs index 70e2e1a9d..1520c98d0 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs @@ -1,7 +1,6 @@ #nullable enable using System; using System.Diagnostics; -using System.Formats.Asn1; using System.Numerics; using System.Security.Cryptography; using System.Text; @@ -207,34 +206,12 @@ public EcdsaKey(SshKeyData publicKeyData) /// /// Initializes a new instance of the class. /// - /// The curve name. + /// The curve oid. /// Value of publickey. /// Value of privatekey. public EcdsaKey(string curve, byte[] publickey, byte[] privatekey) { - _impl = Import(GetCurveOid(curve), publickey, privatekey); - } - - /// - /// Initializes a new instance of the class. - /// - /// DER encoded private key data. - public EcdsaKey(byte[] data) - { - var der = new AsnReader(data, AsnEncodingRules.DER).ReadSequence(); - _ = der.ReadInteger(); // skip version - - var privatekey = der.ReadOctetString().TrimLeadingZeros(); - - var s0 = der.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0, isConstructed: true)); - var curve = s0.ReadObjectIdentifier(); - - var s1 = der.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1, isConstructed: true)); - var pubkey = s1.ReadBitString(out _); - - der.ThrowIfNotEmpty(); - - _impl = Import(curve, pubkey, privatekey); + _impl = Import(curve, publickey, privatekey.TrimLeadingZeros()); } #pragma warning disable CA1859 // Use concrete types when possible for improved performance diff --git a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs index d77d7bf3e..9567056a8 100644 --- a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs @@ -1,6 +1,5 @@ #nullable enable using System; -using System.Formats.Asn1; using System.Numerics; using System.Security.Cryptography; @@ -159,27 +158,24 @@ public RsaKey(SshKeyData publicKeyData) /// /// Initializes a new instance of the class. /// - /// DER encoded private key data. - public RsaKey(byte[] privateKeyData) + /// The modulus. + /// The exponent. + /// The d. + /// The p. + /// The q. + /// The dp. + /// The dq. + /// The inverse Q. + public RsaKey(BigInteger modulus, BigInteger exponent, BigInteger d, BigInteger p, BigInteger q, BigInteger dp, BigInteger dq, BigInteger inverseQ) { - if (privateKeyData is null) - { - throw new ArgumentNullException(nameof(privateKeyData)); - } - - var der = new AsnReader(privateKeyData, AsnEncodingRules.DER).ReadSequence(); - _ = der.ReadInteger(); // skip version - - Modulus = der.ReadInteger(); - Exponent = der.ReadInteger(); - D = der.ReadInteger(); - P = der.ReadInteger(); - Q = der.ReadInteger(); - DP = der.ReadInteger(); - DQ = der.ReadInteger(); - InverseQ = der.ReadInteger(); - - der.ThrowIfNotEmpty(); + Modulus = modulus; + Exponent = exponent; + D = d; + P = p; + Q = q; + DP = dp; + DQ = dq; + InverseQ = inverseQ; RSA = RSA.Create(); RSA.ImportParameters(GetRSAParameters()); diff --git a/test/Data/Key.PKCS8.DSA.Encrypted.Aes.256.CBC.12345.txt b/test/Data/Key.PKCS8.DSA.Encrypted.Aes.256.CBC.12345.txt new file mode 100644 index 000000000..cccd30899 --- /dev/null +++ b/test/Data/Key.PKCS8.DSA.Encrypted.Aes.256.CBC.12345.txt @@ -0,0 +1,18 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIICzTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIx8zJRpH4NWQCAggA +MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBCZ4Xbron+SzM6N2XBp7VaaBIIC +cMGjuaBslmf40+dbnXzyVm+i9sSvlJqpV5h03fOtBOYBZHWESNur8nw3J+taon/M +lTla0Mty70Cb+jMR+fehMmaGbVmkwSjrwi1ac4zIEZiFs0seEJUUmgDdh9Z0o6UG +VlUqMzmHJpHw4e+ywui7KOB2NNtz28C9Imgy+6ISMhsJfSYgo0pmI3L7n2Z6qm32 +Ng0DES1oBdvSZkycV2Iy1ImbI6sJlWwd/WKGea6JBwo3n9UTHbzKcDoq+3Ze7JAb +Rok+UMf3gkoke1S0DmQFcpFbEy00yZUCcNrAYNcif4Ge/wQJ3sYBhXZbMhGhOjtK +jbBEcOzwdcF4iSvWRHyzzL3xsQ2M0s/Ss1OsALnTMfvtp6SYgXs8yvMZ907naxqQ +lWk0H8kKt6m/Gq4t12pl0HyaaFBi6gcvrxXmUFOIMZfa+p10cEwPHBXtEBqfr6dI +Kn/cJ7LV1cqHr2gogoruR23kLPFv8ANsaAdEty0VIfUDSc10dxxWYIYVzTDGilbE +dEHpMg5zYLyZyabwAt25YmlVeOtu80mBQI/HSQsNOifetbB0NuqDO+ZRj5Ka+6aY +ZazID+IuCLpOBCEEzEkA3G3t0Uc9gWZXh5M0VQAJmShmiE96JZLyoZLv/6XS3x00 +m6wB/8y9eQ+/uIovmz+mqOmfyPkyK6gTmRyt1avdNbVQeqVPp0beStAhGHm0FvHN +qv7fkGrBWhK4GT5agrkwQeqrcksvZm1xOolIGHz7czMcU2Bkbbe1jc+bJAnZ691J +Bg5YOD/GVbPV2EuV9Bfo9DgFWu0WcXVR3xspIDVMyk0ZW2tl69ADQOZqsBetwnkP +/A== +-----END ENCRYPTED PRIVATE KEY----- diff --git a/test/Data/Key.PKCS8.DSA.pub b/test/Data/Key.PKCS8.DSA.pub new file mode 100644 index 000000000..82bb5ca0a --- /dev/null +++ b/test/Data/Key.PKCS8.DSA.pub @@ -0,0 +1,20 @@ +-----BEGIN PUBLIC KEY----- +MIIDRzCCAjkGByqGSM44BAEwggIsAoIBAQC4ZsyBM8/72HeXKbEQP6jFPl8dmT+/ +OtdMLHh28xZ4zn3YhIrAdkj0jbp9+neYfLV+6cbDyOlUUJNi3UXpHLQP6o2o3oVx +zCu+SXl/PmOpT5l6rKalcf32fyOyVkYahnUCWrjNvkB3VhmNLt6sGHMfU4JMc/ZK +nQrsZDnRvqP51QUOUX5ib+j7s04CPCaUc1eap+Wdvgf8RNvZlIC1wmPtbOhE7MMh +xp/ITBiTpBIYfzPWXCpi/vfybCzHReSgK+CyQ+Vl7kYG1oB6RsY/u4xFmP/Xns0R +WT61KaxznYcjBWEdDLQw0iqrFfikt5r1VSb58ofrwIY6W41X7Y68QOQDAiEAzKy8 +LKPsvuFXLJtxISpkGdb05lMyuKzZYadz7u+dBw0CggEATVKeR1s+PuLUfVyoXXKn +jmPdHagz7+DGXGOtT4sFqMQ3QwBudNQYd4DrXmYf7/9bTaWZMJL76L+FJsbcQ7Kn +e+V5JsLpcoWz5iW6RAHPEf0GpvdgYrAz+5z0m/ImsX0ebUYTi/YyB/GL7LntvfOO +8U5E3EMhM6aoQQs5ZsxdV53PHx526r/+0Dbj+T7l5OczyEYscY34iXna0qwhKFQk +uCKWjmXEVTb+Ni0zco0/HVpaOL+1GtALzjil7662STmJ0eZR6MhGCaEzXc/DZy/v +WodE57gpX9QDXv5PT3xhWYAzgoVgq3F54umcBNRNuc7cAXTk8CEr4OW3HhlahJ8P +SgOCAQYAAoIBAQCMgluSOc42b3n4eYXPZXtSxzVUxmvnma3UQLlXB1dHSW0ZKGk5 +YbQLorMgvP3DSPFgvfvISdrQvr7qjgE+Pf9nMwKmAMeKnnHs2+P7WWSH21ZA0Fcg +SPPhcyy5JluN0ReanTfXDRqU+OGX5uIO3I462C5F2KcJPuIL7l2hNG4eNO9Bfbjf +nHG537KSsrMTTLqlwd+bKpmmLZLV7LjeRQygtx6gEnnD8Nou4j2Mvw2ksZVxlT3g +A8w6ah/+ygL7S5rCzptKWtehhyhSQ2F46TuMX+8e0mcptnpsi2P1ON95UGcH1531 +Nc9JCcTMqW5thCsNn1Ztku7k/AxtedMV8IiR +-----END PUBLIC KEY----- diff --git a/test/Data/Key.PKCS8.DSA.txt b/test/Data/Key.PKCS8.DSA.txt new file mode 100644 index 000000000..d5f353964 --- /dev/null +++ b/test/Data/Key.PKCS8.DSA.txt @@ -0,0 +1,15 @@ +-----BEGIN PRIVATE KEY----- +MIICZAIBADCCAjkGByqGSM44BAEwggIsAoIBAQC4ZsyBM8/72HeXKbEQP6jFPl8d +mT+/OtdMLHh28xZ4zn3YhIrAdkj0jbp9+neYfLV+6cbDyOlUUJNi3UXpHLQP6o2o +3oVxzCu+SXl/PmOpT5l6rKalcf32fyOyVkYahnUCWrjNvkB3VhmNLt6sGHMfU4JM +c/ZKnQrsZDnRvqP51QUOUX5ib+j7s04CPCaUc1eap+Wdvgf8RNvZlIC1wmPtbOhE +7MMhxp/ITBiTpBIYfzPWXCpi/vfybCzHReSgK+CyQ+Vl7kYG1oB6RsY/u4xFmP/X +ns0RWT61KaxznYcjBWEdDLQw0iqrFfikt5r1VSb58ofrwIY6W41X7Y68QOQDAiEA +zKy8LKPsvuFXLJtxISpkGdb05lMyuKzZYadz7u+dBw0CggEATVKeR1s+PuLUfVyo +XXKnjmPdHagz7+DGXGOtT4sFqMQ3QwBudNQYd4DrXmYf7/9bTaWZMJL76L+FJsbc +Q7Kne+V5JsLpcoWz5iW6RAHPEf0GpvdgYrAz+5z0m/ImsX0ebUYTi/YyB/GL7Lnt +vfOO8U5E3EMhM6aoQQs5ZsxdV53PHx526r/+0Dbj+T7l5OczyEYscY34iXna0qwh +KFQkuCKWjmXEVTb+Ni0zco0/HVpaOL+1GtALzjil7662STmJ0eZR6MhGCaEzXc/D +Zy/vWodE57gpX9QDXv5PT3xhWYAzgoVgq3F54umcBNRNuc7cAXTk8CEr4OW3Hhla +hJ8PSgQiAiBdup1WajP2Gjaw0DZcgmhyIJU5Vr/gpr2YamP4o7toGg== +-----END PRIVATE KEY----- diff --git a/test/Data/Key.PKCS8.ECDSA.Encrypted.Aes.256.CBC.12345.txt b/test/Data/Key.PKCS8.ECDSA.Encrypted.Aes.256.CBC.12345.txt new file mode 100644 index 000000000..b60156457 --- /dev/null +++ b/test/Data/Key.PKCS8.ECDSA.Encrypted.Aes.256.CBC.12345.txt @@ -0,0 +1,7 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIHsMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAjrR3XqO9Py4wICCAAw +DAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEFwxueoXqeP7MFQLhPwl5lYEgZAp +rAlg8R/BEmtwr9FocvmRtw3SD3EQ5fJEJ2Jwtarca0owoLN9tFiVkEfJOaoMnZYI +OKFnRsV+Hs9QpkGsfo8y0hU3F1rtS6Ra0lrbZQZR5zrdFQC8RWSm0f4XjRATp9Fp +ZP5MokTvJYQXKNiFzMRV52K82Be/71B0Qn1E3FTSB+tV9KPffhkVf26U9H+VV5s= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/test/Data/Key.PKCS8.ECDSA.pub b/test/Data/Key.PKCS8.ECDSA.pub new file mode 100644 index 000000000..88f1f3b41 --- /dev/null +++ b/test/Data/Key.PKCS8.ECDSA.pub @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETyPeCi/ijYovYBoxbs2s7/8yPShy +94SMKf1noNO7c8hb3QeIU9bU5T46xloudiWb4aKWtKtVUzpd/nuE3RCYNA== +-----END PUBLIC KEY----- diff --git a/test/Data/Key.PKCS8.ECDSA.txt b/test/Data/Key.PKCS8.ECDSA.txt new file mode 100644 index 000000000..e5bc39ca1 --- /dev/null +++ b/test/Data/Key.PKCS8.ECDSA.txt @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQghQBqtoVk/j7xffGP +HDJbLo+rti8YCRSUd3WCH2+/izKhRANCAARPI94KL+KNii9gGjFuzazv/zI9KHL3 +hIwp/Weg07tzyFvdB4hT1tTlPjrGWi52JZvhopa0q1VTOl3+e4TdEJg0 +-----END PRIVATE KEY----- diff --git a/test/Data/Key.PKCS8.ED25519.Encrypted.Aes.256.CBC.12345.txt b/test/Data/Key.PKCS8.ED25519.Encrypted.Aes.256.CBC.12345.txt new file mode 100644 index 000000000..5931f80b9 --- /dev/null +++ b/test/Data/Key.PKCS8.ED25519.Encrypted.Aes.256.CBC.12345.txt @@ -0,0 +1,6 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIGbMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAj6QC1PblxAhgICCAAw +DAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEECLlSAnzDE8JfUSJOvQKBlsEQEU4 +sZQ9g5YV1pT0sVq63P13eTzCyFkSHm9MAAAYaZUjml9gEc0Y97mtRQyJitH8v/uO +GC1oQbbTG8xSSaXGUp8= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/test/Data/Key.PKCS8.ED25519.pub b/test/Data/Key.PKCS8.ED25519.pub new file mode 100644 index 000000000..00889ae8a --- /dev/null +++ b/test/Data/Key.PKCS8.ED25519.pub @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAFbHwYpK7u/6Xj8vjFjwV3Lz+8BX8nWV82eq8A2sYYXc= +-----END PUBLIC KEY----- diff --git a/test/Data/Key.PKCS8.ED25519.txt b/test/Data/Key.PKCS8.ED25519.txt new file mode 100644 index 000000000..950523402 --- /dev/null +++ b/test/Data/Key.PKCS8.ED25519.txt @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIOf/LplXypaNcx42cZLGc2YsFlGjmNYvsavMHyOPa7HK +-----END PRIVATE KEY----- diff --git a/test/Data/Key.PKCS8.RSA.Encrypted.Aes.256.CBC.12345.txt b/test/Data/Key.PKCS8.RSA.Encrypted.Aes.256.CBC.12345.txt new file mode 100644 index 000000000..303cc08b9 --- /dev/null +++ b/test/Data/Key.PKCS8.RSA.Encrypted.Aes.256.CBC.12345.txt @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQI/Zxlf/qHxdACAggA +MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBD5R1OO/2oOTK+1d4whXAgyBIIE +0ORLrx28RVHcjqRlgY1iRbvZNaTEDLkDiJrb3Qv2rBATw8UIWxf2B52cys4ogofL +LbWJI0hfRnAi8Fbt7tmi6Ap9n3ftAlVA6ITBeWVToXzRTrR5FHSMST9c3XwUEZ2L +5QEm3uM++fmxDXehrDKTmY/nWG9R12cKGqce5oOS1W5ObsgCnp40I4TmF5mFFcc1 +RMex1gpgux3IYk2ysc6WGYZjlqFp0+yBdsEnS+jkJsVTA4/GSZbQY9BcGJA7fLta +/kHZ/+MDI3P5X/dMJUFZwHFk1lWmNeUE1TXqiwzeGo/+echgy1M0hK/gjlG7daJB +noCXTv6NPq6L3LGyTq+fOiGIxBFb8yimx16/osk3mQp/BgsTEuIRKgvAX2IkhYLF +CKPIYXUT7N/oo05S808Cid0kVdlKIPE/LQ3oYOJcB9mZ1e7EzqiwE3I26Cmm/Oon +6hexcTiVeRwnAdmpTiM2PMNEJdGUrfFgS2EGw3KgQhf2FimQE6bxJAh9mG7xppEb +l3FgwWHk42hCV8FtBSke9XLSpdu5VSiR0cj3wTnHP21dtkUjYQnfcNd9Wp0/CO7m +fY1WxsdrjZ2+yOtECaLNeF4qYjDJaak4/OHiS7VNGKEbuoma7NQajqYbozOyNIzS +ZZXC1YJCkudqVPd4+Kou2Cbvn6PZ100oo6Cyt6yf6K7CU+u960Tqg3TSW6gct7XX +EcRThVvPq+qqTI1hhYL+rYD/Sr2TgV5XkCG4zlF0TM53kJME9xTIvOlbDfTcrhqC +z8p6fCnbN7Irc01h2f9LYtoynlOtRKIQN077aJ8Hg9EdF2lYuTaReVf2Jwx/4Ir7 +SaySo2mE3h543FjEMQghf6oUPFVNwPsnsTsS7mKgMvyI6VSZCx0+lGPyaUJI/No8 +Zl5yk/N3wDUwIE44qYyW85wzIgwlUHVoTC/mpifJd4RUJ2FR2o76Cpsca03qltKB ++S4kVJOA4ijdB0zYo4FOyzaWSlzt9+/zS5kw+LYvTRFKcWxLC+VNOtfPmXiF8fZ4 +TnhNdURMGJoxJ6WS26PhkRAgbom4tKJgbfmS+6cUyoinW+OCCVyU5uGBQQk/sL8M +YxqI3OfsfOlEaCXGjcc3OrRibVqm18cEadF04AC2kEa19RQU1STWs3lOLzBWNjsf +NNiKqiOqVee2QN3kflcSbK/IrAoZqqk3AWSNeof00QCrqkEt73ap0rY8UgYx5+9o +JinybftWyxk4MvJY/JWhjacSCMDQQfnDBSUEu1I0/8K6Y+HkzGNMEUVlCgYRyzGZ +jBEXQ/dKdGAa+2p4aI1dWeSJhJo7LC6vzAL18tUreFDwhxUk06hMjGsu0oXduIyL +GFv6DiM6KO4sVyRL54masPBPGEzOSaEqhQFlYf4R2LldR4wEYb6yGMlYXGPiXNfT +IB2vqkoTUyxeocKENPRt44rJ/eq2nOkaOqvh63pBUUSPn7rrDOdcFea9pVny9XaW +Ij6Qd1OOa3c00D/E+qojp4wXEiyLlyL1Y5yuL580ixQRF7xAKPenZ4sSjw/HqsG9 +WILKpM9/jt1MYhEd+gKZOllMvyTJVV31EULoo/StubTBh9XF0hk9yEHgQ/ug+W8D +l05OpVnES4rr4Pnl/uEwOkrseWCgK0tm4LB7p+yWLCDp +-----END ENCRYPTED PRIVATE KEY----- diff --git a/test/Data/Key.PKCS8.RSA.pub b/test/Data/Key.PKCS8.RSA.pub new file mode 100644 index 000000000..7bcc04b51 --- /dev/null +++ b/test/Data/Key.PKCS8.RSA.pub @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv8xngYSu++gf77hpagAN +eVOju5c0vnTwpzN1IM+2O0DWw4OFosenjCsCTCIxmQxSqaZTwl/SeFB7AI7lTqIB +X1DT4loA8lUJFwJIymFCXqfsFe68cHDdYeDzcYuOaeny5RD1G9zAbeVjaNp/QvZT +wQjihAguP59AfCpcWHmvtMf7mqhfIvJQkuGvQufWwybbOL9sIvDpgY0ejhmimEVY +c7jIjga+hpWbPJUQb7xvzlySBfvV/wrh8arxvafzhhEl0bCmirwkatTp6NUnX6sa +S+cH/uxdtwbaXVpVqmnjan2eVQIoMrwb2JuUL6LcgjJfFR7wYWWkUPP87IiPTpqa +tQIDAQAB +-----END PUBLIC KEY----- diff --git a/test/Data/Key.PKCS8.RSA.txt b/test/Data/Key.PKCS8.RSA.txt new file mode 100644 index 000000000..65d46a1d4 --- /dev/null +++ b/test/Data/Key.PKCS8.RSA.txt @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/zGeBhK776B/v +uGlqAA15U6O7lzS+dPCnM3Ugz7Y7QNbDg4Wix6eMKwJMIjGZDFKpplPCX9J4UHsA +juVOogFfUNPiWgDyVQkXAkjKYUJep+wV7rxwcN1h4PNxi45p6fLlEPUb3MBt5WNo +2n9C9lPBCOKECC4/n0B8KlxYea+0x/uaqF8i8lCS4a9C59bDJts4v2wi8OmBjR6O +GaKYRVhzuMiOBr6GlZs8lRBvvG/OXJIF+9X/CuHxqvG9p/OGESXRsKaKvCRq1Ono +1SdfqxpL5wf+7F23BtpdWlWqaeNqfZ5VAigyvBvYm5QvotyCMl8VHvBhZaRQ8/zs +iI9Ompq1AgMBAAECggEAAaQ9TuI6Fi1cgp0nMnv5duGfS+Elgit2434hAUIjMDrO +lmyh1Zdps3KAdJ2Go6WeRStHhGkfYHNojhlq/y3gnvZ5OHLRQcG2ZXREomN2jDVZ +465//eK1aQZMxxrCQgf5fHo/7Xhe9ux+RJI5gchLxgyZAGIf3+BcJAPqd5ZjtC4j +M/Iiuyq6hnqqELkJujIb9J9mIbokxrUdRuLnHqpY7dDs3ImjZDCDvDrnZw354Uf1 +HDhNJtXOzJ6SiHGoYNiiQwqjjr5pHRZRMr2GmSK10wgZWlFiFtus4yfw50+grPcd +bCM3PQpff37hbES4RBgYhfLFMYzPyPqO0FmtbVKm8QKBgQDV+0AXXipHHiwBg+Rk +XQeiZuyh/O9olb3Cdv6Swe219aqefHV/UhhTj0F1q1WFCCvacntBxRFvFb80JL1v +07vNgEEBxpBSPljRl0gqPr4Dalv/WzuQuDOtfkURvDX2sMVusZLSAvIet0vy4zmB +eLXyF7V627XxL/laJQkpELEShQKBgQDldgZqsm4KC7CtEzWY25D8UUMjFo2KHfMK +swj0kxOz6beYpb52ZLhXbNXOlkkNkjKEJpP/EylFVCnknJgj2gjF9pUjDSIJGCsu +xRGbgBiUUUfrlQQsYthP0xrd9o5MEdyFU1m25tQzurcnrVScpx6ornlBCunZ8SrN +3+F5VZIWcQKBgQDNt7VQQelnYexwsHo8uuuCCG1q9p6772n1sSzhrqt4Cey0XXcg +pq5Ydxs5ozSeptJyOymge3NdVozx9nhhMDAXSzw0Fs/dIa+GIGjypEtNQU2c2/sS +EOUt4H1KpaVDu4Kz/ufmG4rmWNYddrJsdL6HNp/0s5HhhHu3XG/IGRIDeQKBgC/R +BYtMfYPYZcvbWertrmv2HzB7rakfjpsnLfGRiKSQSrMjruoLGSMWygNP7A9I7P/+ +7g5UluAcptI+E7I86GEgfnmcbgBJKg6IAKBP9E9MFNmx5vm862jPDCU/EO4nNrYN +5X8o4QWanjpFc4Fljg0GtrvoI01IZWwbgGgBffzxAoGAManlzlx4Mqw1pr0hJTaH +Ro894B9uY3rdYnWGGm/HpqLuCBnshthTZw5ny6QjIX8FPT3Y811B5e8nAMV7OdCI +RdsW/jj0ELr6lRw1xnPjZp3OFGykHM+mYFO+yDFXBw/3eJXJgVqcA2lOIlD3lBvU +4+YTBzctcKHE1H/CVV1DYO4= +-----END PRIVATE KEY----- diff --git a/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs b/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs index 009c9d915..9cbc47599 100644 --- a/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs +++ b/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs @@ -759,6 +759,94 @@ public void Test_PrivateKey_OPENSSH_ECDSA521_ENCRYPTED() } } + [TestMethod] + [Owner("scott-xu")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_PKCS8_RSA() + { + using (var stream = GetData("Key.PKCS8.RSA.txt")) + { + TestRsaKeyFile(new PrivateKeyFile(stream)); + } + } + + [TestMethod] + [Owner("scott-xu")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_PKCS8_RSA_Encrypted() + { + using (var stream = GetData("Key.PKCS8.RSA.Encrypted.Aes.256.CBC.12345.txt")) + { + TestRsaKeyFile(new PrivateKeyFile(stream, "12345")); + } + } + + [TestMethod] + [Owner("scott-xu")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_PKCS8_DSA() + { + using (var stream = GetData("Key.PKCS8.DSA.txt")) + { + _ = new PrivateKeyFile(stream); + } + } + + [TestMethod] + [Owner("scott-xu")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_PKCS8_DSA_Encrypted() + { + using (var stream = GetData("Key.PKCS8.DSA.Encrypted.Aes.256.CBC.12345.txt")) + { + _ = new PrivateKeyFile(stream, "12345"); + } + } + + [TestMethod] + [Owner("scott-xu")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_PKCS8_ECDSA() + { + using (var stream = GetData("Key.PKCS8.ECDSA.txt")) + { + _ = new PrivateKeyFile(stream); + } + } + + [TestMethod] + [Owner("scott-xu")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_PKCS8_ECDSA_Encrypted() + { + using (var stream = GetData("Key.PKCS8.ECDSA.Encrypted.Aes.256.CBC.12345.txt")) + { + _ = new PrivateKeyFile(stream, "12345"); + } + } + + [TestMethod] + [Owner("scott-xu")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_PKCS8_ED25519() + { + using (var stream = GetData("Key.PKCS8.ED25519.txt")) + { + _ = new PrivateKeyFile(stream); + } + } + + [TestMethod] + [Owner("scott-xu")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_PKCS8_ED25519_Encrypted() + { + using (var stream = GetData("Key.PKCS8.ED25519.Encrypted.Aes.256.CBC.12345.txt")) + { + _ = new PrivateKeyFile(stream, "12345"); + } + } + private void SaveStreamToFile(Stream stream, string fileName) { var buffer = new byte[4000]; From a2f4f550623d33f142435348fdb83d4edb64d9cb Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Tue, 17 Sep 2024 08:30:33 +0800 Subject: [PATCH 2/7] Update comments --- README.md | 1 + src/Renci.SshNet/PrivateKeyFile.cs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 54de905ee..8d2b99d25 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,7 @@ The main types provided by this library are: * OpenSSL PKCS#8 PEM format ("BEGIN PRIVATE KEY", "BEGIN ENCRYPTED PRIVATE KEY") * OpenSSH key format ("BEGIN OPENSSH PRIVATE KEY") * ED25519 in + * OpenSSL PKCS#8 PEM format ("BEGIN PRIVATE KEY", "BEGIN ENCRYPTED PRIVATE KEY") * OpenSSH key format ("BEGIN OPENSSH PRIVATE KEY") Private keys in OpenSSL traditional PEM format can be encrypted using one of the following cipher methods: diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index 95164d9d7..15a0b9f68 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -41,7 +41,7 @@ namespace Renci.SshNet /// ECDSA 256/384/521 in OpenSSL PEM and OpenSSH key format /// /// - /// ED25519 in OpenSSH key format + /// ED25519 in OpenSSL PEM and OpenSSH key format /// /// /// @@ -943,10 +943,14 @@ private static EcdsaKey ParseECPrivateKey_SEC1(byte[] keyData) var privatekey = sequenceReader.ReadOctetString(); + // Though the ASN.1 indicates that the parameters field is OPTIONAL, + // implementations that conform to this document MUST always include the parameters field. var parametersReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0, isConstructed: true)); var curve = parametersReader.ReadObjectIdentifier(); parametersReader.ThrowIfNotEmpty(); + // Though the ASN.1 indicates publicKey is OPTIONAL, + // implementations that conform to this document SHOULD always include the publicKey field. var publicKeyReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1, isConstructed: true)); var publickey = publicKeyReader.ReadBitString(out _); publicKeyReader.ThrowIfNotEmpty(); From 58f67ad6dc1c4eab74d92e31fae877069435a60c Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Tue, 17 Sep 2024 13:20:21 +0800 Subject: [PATCH 3/7] Convert public key to ssh format --- test/Data/Key.PKCS8.DSA.pub | 21 +-------------------- test/Data/Key.PKCS8.ECDSA.pub | 5 +---- test/Data/Key.PKCS8.ED25519.pub | 4 +--- test/Data/Key.PKCS8.RSA.pub | 10 +--------- 4 files changed, 4 insertions(+), 36 deletions(-) diff --git a/test/Data/Key.PKCS8.DSA.pub b/test/Data/Key.PKCS8.DSA.pub index 82bb5ca0a..f15c76e6b 100644 --- a/test/Data/Key.PKCS8.DSA.pub +++ b/test/Data/Key.PKCS8.DSA.pub @@ -1,20 +1 @@ ------BEGIN PUBLIC KEY----- -MIIDRzCCAjkGByqGSM44BAEwggIsAoIBAQC4ZsyBM8/72HeXKbEQP6jFPl8dmT+/ -OtdMLHh28xZ4zn3YhIrAdkj0jbp9+neYfLV+6cbDyOlUUJNi3UXpHLQP6o2o3oVx -zCu+SXl/PmOpT5l6rKalcf32fyOyVkYahnUCWrjNvkB3VhmNLt6sGHMfU4JMc/ZK -nQrsZDnRvqP51QUOUX5ib+j7s04CPCaUc1eap+Wdvgf8RNvZlIC1wmPtbOhE7MMh -xp/ITBiTpBIYfzPWXCpi/vfybCzHReSgK+CyQ+Vl7kYG1oB6RsY/u4xFmP/Xns0R -WT61KaxznYcjBWEdDLQw0iqrFfikt5r1VSb58ofrwIY6W41X7Y68QOQDAiEAzKy8 -LKPsvuFXLJtxISpkGdb05lMyuKzZYadz7u+dBw0CggEATVKeR1s+PuLUfVyoXXKn -jmPdHagz7+DGXGOtT4sFqMQ3QwBudNQYd4DrXmYf7/9bTaWZMJL76L+FJsbcQ7Kn -e+V5JsLpcoWz5iW6RAHPEf0GpvdgYrAz+5z0m/ImsX0ebUYTi/YyB/GL7LntvfOO -8U5E3EMhM6aoQQs5ZsxdV53PHx526r/+0Dbj+T7l5OczyEYscY34iXna0qwhKFQk -uCKWjmXEVTb+Ni0zco0/HVpaOL+1GtALzjil7662STmJ0eZR6MhGCaEzXc/DZy/v -WodE57gpX9QDXv5PT3xhWYAzgoVgq3F54umcBNRNuc7cAXTk8CEr4OW3HhlahJ8P -SgOCAQYAAoIBAQCMgluSOc42b3n4eYXPZXtSxzVUxmvnma3UQLlXB1dHSW0ZKGk5 -YbQLorMgvP3DSPFgvfvISdrQvr7qjgE+Pf9nMwKmAMeKnnHs2+P7WWSH21ZA0Fcg -SPPhcyy5JluN0ReanTfXDRqU+OGX5uIO3I462C5F2KcJPuIL7l2hNG4eNO9Bfbjf -nHG537KSsrMTTLqlwd+bKpmmLZLV7LjeRQygtx6gEnnD8Nou4j2Mvw2ksZVxlT3g -A8w6ah/+ygL7S5rCzptKWtehhyhSQ2F46TuMX+8e0mcptnpsi2P1ON95UGcH1531 -Nc9JCcTMqW5thCsNn1Ztku7k/AxtedMV8IiR ------END PUBLIC KEY----- +ssh-dss AAAAB3NzaC1kc3MAAAEBALhmzIEzz/vYd5cpsRA/qMU+Xx2ZP78610wseHbzFnjOfdiEisB2SPSNun36d5h8tX7pxsPI6VRQk2LdRekctA/qjajehXHMK75JeX8+Y6lPmXqspqVx/fZ/I7JWRhqGdQJauM2+QHdWGY0u3qwYcx9Tgkxz9kqdCuxkOdG+o/nVBQ5RfmJv6PuzTgI8JpRzV5qn5Z2+B/xE29mUgLXCY+1s6ETswyHGn8hMGJOkEhh/M9ZcKmL+9/JsLMdF5KAr4LJD5WXuRgbWgHpGxj+7jEWY/9eezRFZPrUprHOdhyMFYR0MtDDSKqsV+KS3mvVVJvnyh+vAhjpbjVftjrxA5AMAAAAhAMysvCyj7L7hVyybcSEqZBnW9OZTMris2WGnc+7vnQcNAAABAE1SnkdbPj7i1H1cqF1yp45j3R2oM+/gxlxjrU+LBajEN0MAbnTUGHeA615mH+//W02lmTCS++i/hSbG3EOyp3vleSbC6XKFs+YlukQBzxH9Bqb3YGKwM/uc9JvyJrF9Hm1GE4v2Mgfxi+y57b3zjvFORNxDITOmqEELOWbMXVedzx8eduq//tA24/k+5eTnM8hGLHGN+Il52tKsIShUJLgilo5lxFU2/jYtM3KNPx1aWji/tRrQC844pe+utkk5idHmUejIRgmhM13Pw2cv71qHROe4KV/UA17+T098YVmAM4KFYKtxeeLpnATUTbnO3AF05PAhK+Dltx4ZWoSfD0oAAAEBAIyCW5I5zjZvefh5hc9le1LHNVTGa+eZrdRAuVcHV0dJbRkoaTlhtAuisyC8/cNI8WC9+8hJ2tC+vuqOAT49/2czAqYAx4qecezb4/tZZIfbVkDQVyBI8+FzLLkmW43RF5qdN9cNGpT44Zfm4g7cjjrYLkXYpwk+4gvuXaE0bh4070F9uN+ccbnfspKysxNMuqXB35sqmaYtktXsuN5FDKC3HqASecPw2i7iPYy/DaSxlXGVPeADzDpqH/7KAvtLmsLOm0pa16GHKFJDYXjpO4xf7x7SZym2emyLY/U433lQZwfXnfU1z0kJxMypbm2EKw2fVm2S7uT8DG150xXwiJE= \ No newline at end of file diff --git a/test/Data/Key.PKCS8.ECDSA.pub b/test/Data/Key.PKCS8.ECDSA.pub index 88f1f3b41..b5d70296c 100644 --- a/test/Data/Key.PKCS8.ECDSA.pub +++ b/test/Data/Key.PKCS8.ECDSA.pub @@ -1,4 +1 @@ ------BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETyPeCi/ijYovYBoxbs2s7/8yPShy -94SMKf1noNO7c8hb3QeIU9bU5T46xloudiWb4aKWtKtVUzpd/nuE3RCYNA== ------END PUBLIC KEY----- +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBE8j3gov4o2KL2AaMW7NrO//Mj0ocveEjCn9Z6DTu3PIW90HiFPW1OU+OsZaLnYlm+GilrSrVVM6Xf57hN0QmDQ= \ No newline at end of file diff --git a/test/Data/Key.PKCS8.ED25519.pub b/test/Data/Key.PKCS8.ED25519.pub index 00889ae8a..4531d766a 100644 --- a/test/Data/Key.PKCS8.ED25519.pub +++ b/test/Data/Key.PKCS8.ED25519.pub @@ -1,3 +1 @@ ------BEGIN PUBLIC KEY----- -MCowBQYDK2VwAyEAFbHwYpK7u/6Xj8vjFjwV3Lz+8BX8nWV82eq8A2sYYXc= ------END PUBLIC KEY----- +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBWx8GKSu7v+l4/L4xY8Fdy8/vAV/J1lfNnqvANrGGF3 \ No newline at end of file diff --git a/test/Data/Key.PKCS8.RSA.pub b/test/Data/Key.PKCS8.RSA.pub index 7bcc04b51..c7c3a4a0f 100644 --- a/test/Data/Key.PKCS8.RSA.pub +++ b/test/Data/Key.PKCS8.RSA.pub @@ -1,9 +1 @@ ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv8xngYSu++gf77hpagAN -eVOju5c0vnTwpzN1IM+2O0DWw4OFosenjCsCTCIxmQxSqaZTwl/SeFB7AI7lTqIB -X1DT4loA8lUJFwJIymFCXqfsFe68cHDdYeDzcYuOaeny5RD1G9zAbeVjaNp/QvZT -wQjihAguP59AfCpcWHmvtMf7mqhfIvJQkuGvQufWwybbOL9sIvDpgY0ejhmimEVY -c7jIjga+hpWbPJUQb7xvzlySBfvV/wrh8arxvafzhhEl0bCmirwkatTp6NUnX6sa -S+cH/uxdtwbaXVpVqmnjan2eVQIoMrwb2JuUL6LcgjJfFR7wYWWkUPP87IiPTpqa -tQIDAQAB ------END PUBLIC KEY----- +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/zGeBhK776B/vuGlqAA15U6O7lzS+dPCnM3Ugz7Y7QNbDg4Wix6eMKwJMIjGZDFKpplPCX9J4UHsAjuVOogFfUNPiWgDyVQkXAkjKYUJep+wV7rxwcN1h4PNxi45p6fLlEPUb3MBt5WNo2n9C9lPBCOKECC4/n0B8KlxYea+0x/uaqF8i8lCS4a9C59bDJts4v2wi8OmBjR6OGaKYRVhzuMiOBr6GlZs8lRBvvG/OXJIF+9X/CuHxqvG9p/OGESXRsKaKvCRq1Ono1SdfqxpL5wf+7F23BtpdWlWqaeNqfZ5VAigyvBvYm5QvotyCMl8VHvBhZaRQ8/zsiI9Ompq1 \ No newline at end of file From 8be690ca9c6b25d520b349055e57184ee752ba23 Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Thu, 19 Sep 2024 22:55:28 +0800 Subject: [PATCH 4/7] Convert existing keys instead of generate new keys; Use DataRow for testing --- ....DSA.PKCS8.Encrypted.Aes.256.CBC.12345.txt | 12 +++ test/Data/Key.DSA.PKCS8.txt | 9 ++ ...CDSA.PKCS8.Encrypted.Aes.256.CBC.12345.txt | 7 ++ test/Data/Key.ECDSA.PKCS8.txt | 5 + ...5519.PKCS8.Encrypted.Aes.256.CBC.12345.txt | 6 ++ test/Data/Key.OPENSSH.ED25519.PKCS8.txt | 3 + ....PKCS8.DSA.Encrypted.Aes.256.CBC.12345.txt | 18 ---- test/Data/Key.PKCS8.DSA.pub | 1 - test/Data/Key.PKCS8.DSA.txt | 15 --- ...KCS8.ECDSA.Encrypted.Aes.256.CBC.12345.txt | 7 -- test/Data/Key.PKCS8.ECDSA.pub | 1 - test/Data/Key.PKCS8.ECDSA.txt | 5 - ...S8.ED25519.Encrypted.Aes.256.CBC.12345.txt | 6 -- test/Data/Key.PKCS8.ED25519.pub | 1 - test/Data/Key.PKCS8.ED25519.txt | 3 - ....PKCS8.RSA.Encrypted.Aes.256.CBC.12345.txt | 30 ------ test/Data/Key.PKCS8.RSA.pub | 1 - test/Data/Key.PKCS8.RSA.txt | 28 ------ ....RSA.PKCS8.Encrypted.Aes.256.CBC.12345.txt | 30 ++++++ test/Data/Key.RSA.PKCS8.txt | 28 ++++++ .../Classes/PrivateKeyFileTest.cs | 96 ++----------------- 21 files changed, 108 insertions(+), 204 deletions(-) create mode 100644 test/Data/Key.DSA.PKCS8.Encrypted.Aes.256.CBC.12345.txt create mode 100644 test/Data/Key.DSA.PKCS8.txt create mode 100644 test/Data/Key.ECDSA.PKCS8.Encrypted.Aes.256.CBC.12345.txt create mode 100644 test/Data/Key.ECDSA.PKCS8.txt create mode 100644 test/Data/Key.OPENSSH.ED25519.PKCS8.Encrypted.Aes.256.CBC.12345.txt create mode 100644 test/Data/Key.OPENSSH.ED25519.PKCS8.txt delete mode 100644 test/Data/Key.PKCS8.DSA.Encrypted.Aes.256.CBC.12345.txt delete mode 100644 test/Data/Key.PKCS8.DSA.pub delete mode 100644 test/Data/Key.PKCS8.DSA.txt delete mode 100644 test/Data/Key.PKCS8.ECDSA.Encrypted.Aes.256.CBC.12345.txt delete mode 100644 test/Data/Key.PKCS8.ECDSA.pub delete mode 100644 test/Data/Key.PKCS8.ECDSA.txt delete mode 100644 test/Data/Key.PKCS8.ED25519.Encrypted.Aes.256.CBC.12345.txt delete mode 100644 test/Data/Key.PKCS8.ED25519.pub delete mode 100644 test/Data/Key.PKCS8.ED25519.txt delete mode 100644 test/Data/Key.PKCS8.RSA.Encrypted.Aes.256.CBC.12345.txt delete mode 100644 test/Data/Key.PKCS8.RSA.pub delete mode 100644 test/Data/Key.PKCS8.RSA.txt create mode 100644 test/Data/Key.RSA.PKCS8.Encrypted.Aes.256.CBC.12345.txt create mode 100644 test/Data/Key.RSA.PKCS8.txt diff --git a/test/Data/Key.DSA.PKCS8.Encrypted.Aes.256.CBC.12345.txt b/test/Data/Key.DSA.PKCS8.Encrypted.Aes.256.CBC.12345.txt new file mode 100644 index 000000000..03773bbfb --- /dev/null +++ b/test/Data/Key.DSA.PKCS8.Encrypted.Aes.256.CBC.12345.txt @@ -0,0 +1,12 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIBrTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIjn9BgD9X0loCAggA +MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBB3Zthr23nQDulzKryFEUTFBIIB +UDW8/IR0K5DRScH4Cl7HOoK20aR+TmUOGczE027RL++iosgk5rYUpIKn0pxIKM0U +StFGTqLz3G+bEh/Bm2Vt03Qv0Q2QZoX2e1Vktt32X2cLBNzGWfEpLuCD4vG8QDRW +uGkE1NHxJKQTJWQt/gwGituyhMThGoE3ZcuqeLmRlhUSgRccO6WJ2HkNOW7TM5RB +QbeBXmYB1H5S3FjpRAvd2p9dEzDsyquQaltFM4kekIxGjwiw5WSd+KsCGXFLa2Y2 +OXvcjRIIqGBJr+xvEVA86TNTfad+sKGqGUFszRmnGXA+VxEZju2OCpVhxTLEMX4Q +2vYz9i8jE78tpx7C6PTKoJe5FTdlTatvWvYD5cvcbazPUjuZbraI9ha4XvNtERGC +J0voz/7yeuNkW1ofxTUOu+snGhySC4AXkC44eZG4wUPfuQAswP8dFiQi2BthgVyP +kA== +-----END ENCRYPTED PRIVATE KEY----- diff --git a/test/Data/Key.DSA.PKCS8.txt b/test/Data/Key.DSA.PKCS8.txt new file mode 100644 index 000000000..f5baf96e5 --- /dev/null +++ b/test/Data/Key.DSA.PKCS8.txt @@ -0,0 +1,9 @@ +-----BEGIN PRIVATE KEY----- +MIIBSgIBADCCASsGByqGSM44BAEwggEeAoGBALVl3fae2O4qwsAK95SUShX0KMUN +P+yl/uT3lGH9T/ZptnHSlrTxnTWXCl0g91KEeCaEnDDhLxm4aCv1Ag4B/yvcM4u3 +4qkmaNLy2LiAxiqdobZcNG61Pqwqd5IDkp38LBsn8tmb12xu9NalpUfOiSEB1cyC +r4zFZMrm0wtdyJQVAhUArvojZKn/2DgGI2Kx0ghxZlgHxGECgYAOVJ434UAR3Hn6 +lA5nWNfFOuUVH3W7nJaP0FQJiIPx7GUbdxO9qtDNTbWkWL3c9qx5+B7Ole4xM7cv +yXPrNQUYDHCFlS+Ue2x3IeJrkdfZkH9ePP25y5A0J4/c+8XXvQaj4zA5nfw13oy5 +Ptyd7d3Kq5tEDM8KiVdIhwkXjUA3PQQWAhQYRjs5PgIpnqG/euBPPh7EDZcnXg== +-----END PRIVATE KEY----- diff --git a/test/Data/Key.ECDSA.PKCS8.Encrypted.Aes.256.CBC.12345.txt b/test/Data/Key.ECDSA.PKCS8.Encrypted.Aes.256.CBC.12345.txt new file mode 100644 index 000000000..03fe0acbd --- /dev/null +++ b/test/Data/Key.ECDSA.PKCS8.Encrypted.Aes.256.CBC.12345.txt @@ -0,0 +1,7 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIHsMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAithDR1n5wCYQICCAAw +DAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEMSzAQ3FSZ5hQHbmb7K9aB0EgZCS +RVfVmMp1SBllrUMvdMEz5Zwvthaa1/M3Mc6MEVEzgROEXY3X+ywECU9q18aIOct+ +m5bmFcRcwoxo/hj6fsnmeH567KRfnN4Al219azq5ccwTr68y8tasYsZHOFCkn3ve +Hkzu0+gylHZGWqo5TWif9O9DrII/KszsoX86jJxhORwqCnxMmKQQ/gGvexpAYJA= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/test/Data/Key.ECDSA.PKCS8.txt b/test/Data/Key.ECDSA.PKCS8.txt new file mode 100644 index 000000000..49b96064f --- /dev/null +++ b/test/Data/Key.ECDSA.PKCS8.txt @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgR2poUqAkEiJtWPJS +HW/tjfkvAhAmuhx1NpgUvCXuIHShRANCAARAPkw7+f3KpINOzPDNWkCkvHlJAV5w +Tll8OSDGpV0dB5ybUEA+jNnh4oY2EqfvaFPv2YuWn0ddf6g0Ry5VPzcf +-----END PRIVATE KEY----- diff --git a/test/Data/Key.OPENSSH.ED25519.PKCS8.Encrypted.Aes.256.CBC.12345.txt b/test/Data/Key.OPENSSH.ED25519.PKCS8.Encrypted.Aes.256.CBC.12345.txt new file mode 100644 index 000000000..63aebfa2c --- /dev/null +++ b/test/Data/Key.OPENSSH.ED25519.PKCS8.Encrypted.Aes.256.CBC.12345.txt @@ -0,0 +1,6 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIGbMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAhiAnoQd2VMZwICCAAw +DAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEENed/l3AFuDblxDnswMZXDcEQIpo +fCVdEbDerN0Rrh9i+Ymu+qpEqGlc6jycwR3rPtyL9jy0k5kauBxRn3Z5uCSlGzJL +JXxlMR+DWG6QDJdxrHI= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/test/Data/Key.OPENSSH.ED25519.PKCS8.txt b/test/Data/Key.OPENSSH.ED25519.PKCS8.txt new file mode 100644 index 000000000..28bf6cafa --- /dev/null +++ b/test/Data/Key.OPENSSH.ED25519.PKCS8.txt @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIADMEXUw9TGuz7JykmHbzPOj8XebpZwo76iuxJtHkvAp +-----END PRIVATE KEY----- diff --git a/test/Data/Key.PKCS8.DSA.Encrypted.Aes.256.CBC.12345.txt b/test/Data/Key.PKCS8.DSA.Encrypted.Aes.256.CBC.12345.txt deleted file mode 100644 index cccd30899..000000000 --- a/test/Data/Key.PKCS8.DSA.Encrypted.Aes.256.CBC.12345.txt +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN ENCRYPTED PRIVATE KEY----- -MIICzTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIx8zJRpH4NWQCAggA -MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBCZ4Xbron+SzM6N2XBp7VaaBIIC -cMGjuaBslmf40+dbnXzyVm+i9sSvlJqpV5h03fOtBOYBZHWESNur8nw3J+taon/M -lTla0Mty70Cb+jMR+fehMmaGbVmkwSjrwi1ac4zIEZiFs0seEJUUmgDdh9Z0o6UG -VlUqMzmHJpHw4e+ywui7KOB2NNtz28C9Imgy+6ISMhsJfSYgo0pmI3L7n2Z6qm32 -Ng0DES1oBdvSZkycV2Iy1ImbI6sJlWwd/WKGea6JBwo3n9UTHbzKcDoq+3Ze7JAb -Rok+UMf3gkoke1S0DmQFcpFbEy00yZUCcNrAYNcif4Ge/wQJ3sYBhXZbMhGhOjtK -jbBEcOzwdcF4iSvWRHyzzL3xsQ2M0s/Ss1OsALnTMfvtp6SYgXs8yvMZ907naxqQ -lWk0H8kKt6m/Gq4t12pl0HyaaFBi6gcvrxXmUFOIMZfa+p10cEwPHBXtEBqfr6dI -Kn/cJ7LV1cqHr2gogoruR23kLPFv8ANsaAdEty0VIfUDSc10dxxWYIYVzTDGilbE -dEHpMg5zYLyZyabwAt25YmlVeOtu80mBQI/HSQsNOifetbB0NuqDO+ZRj5Ka+6aY -ZazID+IuCLpOBCEEzEkA3G3t0Uc9gWZXh5M0VQAJmShmiE96JZLyoZLv/6XS3x00 -m6wB/8y9eQ+/uIovmz+mqOmfyPkyK6gTmRyt1avdNbVQeqVPp0beStAhGHm0FvHN -qv7fkGrBWhK4GT5agrkwQeqrcksvZm1xOolIGHz7czMcU2Bkbbe1jc+bJAnZ691J -Bg5YOD/GVbPV2EuV9Bfo9DgFWu0WcXVR3xspIDVMyk0ZW2tl69ADQOZqsBetwnkP -/A== ------END ENCRYPTED PRIVATE KEY----- diff --git a/test/Data/Key.PKCS8.DSA.pub b/test/Data/Key.PKCS8.DSA.pub deleted file mode 100644 index f15c76e6b..000000000 --- a/test/Data/Key.PKCS8.DSA.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-dss AAAAB3NzaC1kc3MAAAEBALhmzIEzz/vYd5cpsRA/qMU+Xx2ZP78610wseHbzFnjOfdiEisB2SPSNun36d5h8tX7pxsPI6VRQk2LdRekctA/qjajehXHMK75JeX8+Y6lPmXqspqVx/fZ/I7JWRhqGdQJauM2+QHdWGY0u3qwYcx9Tgkxz9kqdCuxkOdG+o/nVBQ5RfmJv6PuzTgI8JpRzV5qn5Z2+B/xE29mUgLXCY+1s6ETswyHGn8hMGJOkEhh/M9ZcKmL+9/JsLMdF5KAr4LJD5WXuRgbWgHpGxj+7jEWY/9eezRFZPrUprHOdhyMFYR0MtDDSKqsV+KS3mvVVJvnyh+vAhjpbjVftjrxA5AMAAAAhAMysvCyj7L7hVyybcSEqZBnW9OZTMris2WGnc+7vnQcNAAABAE1SnkdbPj7i1H1cqF1yp45j3R2oM+/gxlxjrU+LBajEN0MAbnTUGHeA615mH+//W02lmTCS++i/hSbG3EOyp3vleSbC6XKFs+YlukQBzxH9Bqb3YGKwM/uc9JvyJrF9Hm1GE4v2Mgfxi+y57b3zjvFORNxDITOmqEELOWbMXVedzx8eduq//tA24/k+5eTnM8hGLHGN+Il52tKsIShUJLgilo5lxFU2/jYtM3KNPx1aWji/tRrQC844pe+utkk5idHmUejIRgmhM13Pw2cv71qHROe4KV/UA17+T098YVmAM4KFYKtxeeLpnATUTbnO3AF05PAhK+Dltx4ZWoSfD0oAAAEBAIyCW5I5zjZvefh5hc9le1LHNVTGa+eZrdRAuVcHV0dJbRkoaTlhtAuisyC8/cNI8WC9+8hJ2tC+vuqOAT49/2czAqYAx4qecezb4/tZZIfbVkDQVyBI8+FzLLkmW43RF5qdN9cNGpT44Zfm4g7cjjrYLkXYpwk+4gvuXaE0bh4070F9uN+ccbnfspKysxNMuqXB35sqmaYtktXsuN5FDKC3HqASecPw2i7iPYy/DaSxlXGVPeADzDpqH/7KAvtLmsLOm0pa16GHKFJDYXjpO4xf7x7SZym2emyLY/U433lQZwfXnfU1z0kJxMypbm2EKw2fVm2S7uT8DG150xXwiJE= \ No newline at end of file diff --git a/test/Data/Key.PKCS8.DSA.txt b/test/Data/Key.PKCS8.DSA.txt deleted file mode 100644 index d5f353964..000000000 --- a/test/Data/Key.PKCS8.DSA.txt +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIICZAIBADCCAjkGByqGSM44BAEwggIsAoIBAQC4ZsyBM8/72HeXKbEQP6jFPl8d -mT+/OtdMLHh28xZ4zn3YhIrAdkj0jbp9+neYfLV+6cbDyOlUUJNi3UXpHLQP6o2o -3oVxzCu+SXl/PmOpT5l6rKalcf32fyOyVkYahnUCWrjNvkB3VhmNLt6sGHMfU4JM -c/ZKnQrsZDnRvqP51QUOUX5ib+j7s04CPCaUc1eap+Wdvgf8RNvZlIC1wmPtbOhE -7MMhxp/ITBiTpBIYfzPWXCpi/vfybCzHReSgK+CyQ+Vl7kYG1oB6RsY/u4xFmP/X -ns0RWT61KaxznYcjBWEdDLQw0iqrFfikt5r1VSb58ofrwIY6W41X7Y68QOQDAiEA -zKy8LKPsvuFXLJtxISpkGdb05lMyuKzZYadz7u+dBw0CggEATVKeR1s+PuLUfVyo -XXKnjmPdHagz7+DGXGOtT4sFqMQ3QwBudNQYd4DrXmYf7/9bTaWZMJL76L+FJsbc -Q7Kne+V5JsLpcoWz5iW6RAHPEf0GpvdgYrAz+5z0m/ImsX0ebUYTi/YyB/GL7Lnt -vfOO8U5E3EMhM6aoQQs5ZsxdV53PHx526r/+0Dbj+T7l5OczyEYscY34iXna0qwh -KFQkuCKWjmXEVTb+Ni0zco0/HVpaOL+1GtALzjil7662STmJ0eZR6MhGCaEzXc/D -Zy/vWodE57gpX9QDXv5PT3xhWYAzgoVgq3F54umcBNRNuc7cAXTk8CEr4OW3Hhla -hJ8PSgQiAiBdup1WajP2Gjaw0DZcgmhyIJU5Vr/gpr2YamP4o7toGg== ------END PRIVATE KEY----- diff --git a/test/Data/Key.PKCS8.ECDSA.Encrypted.Aes.256.CBC.12345.txt b/test/Data/Key.PKCS8.ECDSA.Encrypted.Aes.256.CBC.12345.txt deleted file mode 100644 index b60156457..000000000 --- a/test/Data/Key.PKCS8.ECDSA.Encrypted.Aes.256.CBC.12345.txt +++ /dev/null @@ -1,7 +0,0 @@ ------BEGIN ENCRYPTED PRIVATE KEY----- -MIHsMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAjrR3XqO9Py4wICCAAw -DAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEFwxueoXqeP7MFQLhPwl5lYEgZAp -rAlg8R/BEmtwr9FocvmRtw3SD3EQ5fJEJ2Jwtarca0owoLN9tFiVkEfJOaoMnZYI -OKFnRsV+Hs9QpkGsfo8y0hU3F1rtS6Ra0lrbZQZR5zrdFQC8RWSm0f4XjRATp9Fp -ZP5MokTvJYQXKNiFzMRV52K82Be/71B0Qn1E3FTSB+tV9KPffhkVf26U9H+VV5s= ------END ENCRYPTED PRIVATE KEY----- diff --git a/test/Data/Key.PKCS8.ECDSA.pub b/test/Data/Key.PKCS8.ECDSA.pub deleted file mode 100644 index b5d70296c..000000000 --- a/test/Data/Key.PKCS8.ECDSA.pub +++ /dev/null @@ -1 +0,0 @@ -ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBE8j3gov4o2KL2AaMW7NrO//Mj0ocveEjCn9Z6DTu3PIW90HiFPW1OU+OsZaLnYlm+GilrSrVVM6Xf57hN0QmDQ= \ No newline at end of file diff --git a/test/Data/Key.PKCS8.ECDSA.txt b/test/Data/Key.PKCS8.ECDSA.txt deleted file mode 100644 index e5bc39ca1..000000000 --- a/test/Data/Key.PKCS8.ECDSA.txt +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQghQBqtoVk/j7xffGP -HDJbLo+rti8YCRSUd3WCH2+/izKhRANCAARPI94KL+KNii9gGjFuzazv/zI9KHL3 -hIwp/Weg07tzyFvdB4hT1tTlPjrGWi52JZvhopa0q1VTOl3+e4TdEJg0 ------END PRIVATE KEY----- diff --git a/test/Data/Key.PKCS8.ED25519.Encrypted.Aes.256.CBC.12345.txt b/test/Data/Key.PKCS8.ED25519.Encrypted.Aes.256.CBC.12345.txt deleted file mode 100644 index 5931f80b9..000000000 --- a/test/Data/Key.PKCS8.ED25519.Encrypted.Aes.256.CBC.12345.txt +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN ENCRYPTED PRIVATE KEY----- -MIGbMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAj6QC1PblxAhgICCAAw -DAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEECLlSAnzDE8JfUSJOvQKBlsEQEU4 -sZQ9g5YV1pT0sVq63P13eTzCyFkSHm9MAAAYaZUjml9gEc0Y97mtRQyJitH8v/uO -GC1oQbbTG8xSSaXGUp8= ------END ENCRYPTED PRIVATE KEY----- diff --git a/test/Data/Key.PKCS8.ED25519.pub b/test/Data/Key.PKCS8.ED25519.pub deleted file mode 100644 index 4531d766a..000000000 --- a/test/Data/Key.PKCS8.ED25519.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBWx8GKSu7v+l4/L4xY8Fdy8/vAV/J1lfNnqvANrGGF3 \ No newline at end of file diff --git a/test/Data/Key.PKCS8.ED25519.txt b/test/Data/Key.PKCS8.ED25519.txt deleted file mode 100644 index 950523402..000000000 --- a/test/Data/Key.PKCS8.ED25519.txt +++ /dev/null @@ -1,3 +0,0 @@ ------BEGIN PRIVATE KEY----- -MC4CAQAwBQYDK2VwBCIEIOf/LplXypaNcx42cZLGc2YsFlGjmNYvsavMHyOPa7HK ------END PRIVATE KEY----- diff --git a/test/Data/Key.PKCS8.RSA.Encrypted.Aes.256.CBC.12345.txt b/test/Data/Key.PKCS8.RSA.Encrypted.Aes.256.CBC.12345.txt deleted file mode 100644 index 303cc08b9..000000000 --- a/test/Data/Key.PKCS8.RSA.Encrypted.Aes.256.CBC.12345.txt +++ /dev/null @@ -1,30 +0,0 @@ ------BEGIN ENCRYPTED PRIVATE KEY----- -MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQI/Zxlf/qHxdACAggA -MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBD5R1OO/2oOTK+1d4whXAgyBIIE -0ORLrx28RVHcjqRlgY1iRbvZNaTEDLkDiJrb3Qv2rBATw8UIWxf2B52cys4ogofL -LbWJI0hfRnAi8Fbt7tmi6Ap9n3ftAlVA6ITBeWVToXzRTrR5FHSMST9c3XwUEZ2L -5QEm3uM++fmxDXehrDKTmY/nWG9R12cKGqce5oOS1W5ObsgCnp40I4TmF5mFFcc1 -RMex1gpgux3IYk2ysc6WGYZjlqFp0+yBdsEnS+jkJsVTA4/GSZbQY9BcGJA7fLta -/kHZ/+MDI3P5X/dMJUFZwHFk1lWmNeUE1TXqiwzeGo/+echgy1M0hK/gjlG7daJB -noCXTv6NPq6L3LGyTq+fOiGIxBFb8yimx16/osk3mQp/BgsTEuIRKgvAX2IkhYLF -CKPIYXUT7N/oo05S808Cid0kVdlKIPE/LQ3oYOJcB9mZ1e7EzqiwE3I26Cmm/Oon -6hexcTiVeRwnAdmpTiM2PMNEJdGUrfFgS2EGw3KgQhf2FimQE6bxJAh9mG7xppEb -l3FgwWHk42hCV8FtBSke9XLSpdu5VSiR0cj3wTnHP21dtkUjYQnfcNd9Wp0/CO7m -fY1WxsdrjZ2+yOtECaLNeF4qYjDJaak4/OHiS7VNGKEbuoma7NQajqYbozOyNIzS -ZZXC1YJCkudqVPd4+Kou2Cbvn6PZ100oo6Cyt6yf6K7CU+u960Tqg3TSW6gct7XX -EcRThVvPq+qqTI1hhYL+rYD/Sr2TgV5XkCG4zlF0TM53kJME9xTIvOlbDfTcrhqC -z8p6fCnbN7Irc01h2f9LYtoynlOtRKIQN077aJ8Hg9EdF2lYuTaReVf2Jwx/4Ir7 -SaySo2mE3h543FjEMQghf6oUPFVNwPsnsTsS7mKgMvyI6VSZCx0+lGPyaUJI/No8 -Zl5yk/N3wDUwIE44qYyW85wzIgwlUHVoTC/mpifJd4RUJ2FR2o76Cpsca03qltKB -+S4kVJOA4ijdB0zYo4FOyzaWSlzt9+/zS5kw+LYvTRFKcWxLC+VNOtfPmXiF8fZ4 -TnhNdURMGJoxJ6WS26PhkRAgbom4tKJgbfmS+6cUyoinW+OCCVyU5uGBQQk/sL8M -YxqI3OfsfOlEaCXGjcc3OrRibVqm18cEadF04AC2kEa19RQU1STWs3lOLzBWNjsf -NNiKqiOqVee2QN3kflcSbK/IrAoZqqk3AWSNeof00QCrqkEt73ap0rY8UgYx5+9o -JinybftWyxk4MvJY/JWhjacSCMDQQfnDBSUEu1I0/8K6Y+HkzGNMEUVlCgYRyzGZ -jBEXQ/dKdGAa+2p4aI1dWeSJhJo7LC6vzAL18tUreFDwhxUk06hMjGsu0oXduIyL -GFv6DiM6KO4sVyRL54masPBPGEzOSaEqhQFlYf4R2LldR4wEYb6yGMlYXGPiXNfT -IB2vqkoTUyxeocKENPRt44rJ/eq2nOkaOqvh63pBUUSPn7rrDOdcFea9pVny9XaW -Ij6Qd1OOa3c00D/E+qojp4wXEiyLlyL1Y5yuL580ixQRF7xAKPenZ4sSjw/HqsG9 -WILKpM9/jt1MYhEd+gKZOllMvyTJVV31EULoo/StubTBh9XF0hk9yEHgQ/ug+W8D -l05OpVnES4rr4Pnl/uEwOkrseWCgK0tm4LB7p+yWLCDp ------END ENCRYPTED PRIVATE KEY----- diff --git a/test/Data/Key.PKCS8.RSA.pub b/test/Data/Key.PKCS8.RSA.pub deleted file mode 100644 index c7c3a4a0f..000000000 --- a/test/Data/Key.PKCS8.RSA.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/zGeBhK776B/vuGlqAA15U6O7lzS+dPCnM3Ugz7Y7QNbDg4Wix6eMKwJMIjGZDFKpplPCX9J4UHsAjuVOogFfUNPiWgDyVQkXAkjKYUJep+wV7rxwcN1h4PNxi45p6fLlEPUb3MBt5WNo2n9C9lPBCOKECC4/n0B8KlxYea+0x/uaqF8i8lCS4a9C59bDJts4v2wi8OmBjR6OGaKYRVhzuMiOBr6GlZs8lRBvvG/OXJIF+9X/CuHxqvG9p/OGESXRsKaKvCRq1Ono1SdfqxpL5wf+7F23BtpdWlWqaeNqfZ5VAigyvBvYm5QvotyCMl8VHvBhZaRQ8/zsiI9Ompq1 \ No newline at end of file diff --git a/test/Data/Key.PKCS8.RSA.txt b/test/Data/Key.PKCS8.RSA.txt deleted file mode 100644 index 65d46a1d4..000000000 --- a/test/Data/Key.PKCS8.RSA.txt +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC/zGeBhK776B/v -uGlqAA15U6O7lzS+dPCnM3Ugz7Y7QNbDg4Wix6eMKwJMIjGZDFKpplPCX9J4UHsA -juVOogFfUNPiWgDyVQkXAkjKYUJep+wV7rxwcN1h4PNxi45p6fLlEPUb3MBt5WNo -2n9C9lPBCOKECC4/n0B8KlxYea+0x/uaqF8i8lCS4a9C59bDJts4v2wi8OmBjR6O -GaKYRVhzuMiOBr6GlZs8lRBvvG/OXJIF+9X/CuHxqvG9p/OGESXRsKaKvCRq1Ono -1SdfqxpL5wf+7F23BtpdWlWqaeNqfZ5VAigyvBvYm5QvotyCMl8VHvBhZaRQ8/zs -iI9Ompq1AgMBAAECggEAAaQ9TuI6Fi1cgp0nMnv5duGfS+Elgit2434hAUIjMDrO -lmyh1Zdps3KAdJ2Go6WeRStHhGkfYHNojhlq/y3gnvZ5OHLRQcG2ZXREomN2jDVZ -465//eK1aQZMxxrCQgf5fHo/7Xhe9ux+RJI5gchLxgyZAGIf3+BcJAPqd5ZjtC4j -M/Iiuyq6hnqqELkJujIb9J9mIbokxrUdRuLnHqpY7dDs3ImjZDCDvDrnZw354Uf1 -HDhNJtXOzJ6SiHGoYNiiQwqjjr5pHRZRMr2GmSK10wgZWlFiFtus4yfw50+grPcd -bCM3PQpff37hbES4RBgYhfLFMYzPyPqO0FmtbVKm8QKBgQDV+0AXXipHHiwBg+Rk -XQeiZuyh/O9olb3Cdv6Swe219aqefHV/UhhTj0F1q1WFCCvacntBxRFvFb80JL1v -07vNgEEBxpBSPljRl0gqPr4Dalv/WzuQuDOtfkURvDX2sMVusZLSAvIet0vy4zmB -eLXyF7V627XxL/laJQkpELEShQKBgQDldgZqsm4KC7CtEzWY25D8UUMjFo2KHfMK -swj0kxOz6beYpb52ZLhXbNXOlkkNkjKEJpP/EylFVCnknJgj2gjF9pUjDSIJGCsu -xRGbgBiUUUfrlQQsYthP0xrd9o5MEdyFU1m25tQzurcnrVScpx6ornlBCunZ8SrN -3+F5VZIWcQKBgQDNt7VQQelnYexwsHo8uuuCCG1q9p6772n1sSzhrqt4Cey0XXcg -pq5Ydxs5ozSeptJyOymge3NdVozx9nhhMDAXSzw0Fs/dIa+GIGjypEtNQU2c2/sS -EOUt4H1KpaVDu4Kz/ufmG4rmWNYddrJsdL6HNp/0s5HhhHu3XG/IGRIDeQKBgC/R -BYtMfYPYZcvbWertrmv2HzB7rakfjpsnLfGRiKSQSrMjruoLGSMWygNP7A9I7P/+ -7g5UluAcptI+E7I86GEgfnmcbgBJKg6IAKBP9E9MFNmx5vm862jPDCU/EO4nNrYN -5X8o4QWanjpFc4Fljg0GtrvoI01IZWwbgGgBffzxAoGAManlzlx4Mqw1pr0hJTaH -Ro894B9uY3rdYnWGGm/HpqLuCBnshthTZw5ny6QjIX8FPT3Y811B5e8nAMV7OdCI -RdsW/jj0ELr6lRw1xnPjZp3OFGykHM+mYFO+yDFXBw/3eJXJgVqcA2lOIlD3lBvU -4+YTBzctcKHE1H/CVV1DYO4= ------END PRIVATE KEY----- diff --git a/test/Data/Key.RSA.PKCS8.Encrypted.Aes.256.CBC.12345.txt b/test/Data/Key.RSA.PKCS8.Encrypted.Aes.256.CBC.12345.txt new file mode 100644 index 000000000..b7bdf6bd6 --- /dev/null +++ b/test/Data/Key.RSA.PKCS8.Encrypted.Aes.256.CBC.12345.txt @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFHTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIr0PK2BHcNKsCAggA +MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBCClZC7H7nFtlsAd+cURqvqBIIE +wOYCGtgoABpWHCk5chj4EF3t2T+Eu753vz5FudgbFkkoMFVmxKLGB0BYVyxMIws/ +GLj6WYq8o51E867hr3f3XOc5nIJEffGSxF/fhYIMGuE9teOWYVTAc/vGlFzEWska +cXGgffBT+DqA4uaLEgcuYHd+hjhlNhKmNIFDsIP40sbHMP31NhuQyd1a63sTUJro +lcLEsESC1H4jru36RrrlRUrTjdgwPrraeu/GUw3Dq7Op5wTfLTsv06Ci3OAKWkGs +SMog36KgvU834YC1btAHL/T/R7lE2QFp8bHPSHA0iigsDiO6NoGcn5Ktvj0yxYzm +8T+uiKs0aEzHWRX+08J8iBIhbSuNm6z/J+CILT3ce5/1vE9Kc2Ml4iVAvwvIYvKB +TO1ZPe4/8gou/pMAHZ39/4euywZpYn9dMSPrsbLt0Wmqg+vVg9mVPD57eZiBgj0j +RqgOlrhymaIA/tDYQTt+DJOKVtGNMbPrXqVpkpaAbXVa7uXYq/euTi2OgzMOSIZj +JFLCWyZo/kpHa6/scIiRjFEDRLqIuhgKca5c4HQ23tRrtWvI+kMd5FK6IAAUplOy +rP1EOztLrwk7NmSpL/zbOJ585AgiGPkq8AAxWfEpMt5GTvcomMjQpv1bs82jLPSG +dC3N+7AOgMQQBDamwfallDgDpvlS7+pgmQJVsv9oT+XoHIXrkD7q7junA8T8Zd9a +LsBgFxMVid2X1PWRkC8+5M4zb7HZdqIyK/vI1kPVWvdUYTvRMHgXxa5wBW/kB3q9 +CQYGfOvg/Gsk7h/WqzlApqvcNZ8OJsxkhlElr2KkH5R9W3snAGedm/fHd1XWpkkL +tY7qHb9z4WW2QOZWBkFY1mfUTU0wrYexAsgLhVniHTy71zj3LLVmezPxDCIvYslX +hSY9/cofCsTx4W5toh/jh1NMsgQgaN2dGgCmHL+PwQTN3bL13KtKQUogNmHxKBMc +QZepJqoiiOtjT6LjBkQI9PY+Yzky4zToo/3Gh5i7ohYAABvT9MXtK4hbQP26JB0T +GL8pVLJSUCBQFj+87sJVILW+n1ak8OoEZQLNgs/V6lbtSc+0TW6t1ixZs7Xxh6KJ +1zLDu0IwebONt8R8KVLUPeV0aFAjr5R9KGNvaL+F0EexG+fNSe1vJ+iBf3fhQLb1 +EDI20FGYBlMfSwtNw0OhKZ5cG1lSx3BUtW1/nl3Y0+sYhRRtP628JjZ2YYifJZdc ++iNGSC2m4r6li9spPvQUyJLHb2vMIwHEqbAi+OE4fNCBVgm0vNPdhEZHAwa8HvRt +iQd2vsEE1tKSfj8z0XQl0T3u4WDVB0DvQqsSjVIfDL+vxlCZ540l26KWd1rJJOWi +fWRF4+MV07GQgoE8aL8bbLUNBJq5OJPTHSgUs7ke7D0sHas1Z2ue/LccZeMbi39U +kTqAyB0ag2/aaqL3/sUo1mi2HZBtqjg4P2gI6ymeVHeSQu8Hx62mw58C8WmoRk12 +3YfiHXZI6LHBt+CK+nIXvsf7ZXeHHVnvRJEJaeX+jrCyCKyqCz8r47ZUUb2sgqFf +8hTpheQKvCbYM+XtkkkuiudVevY67xrHpjAjDIU/4BXxC5KvlBQ8i8u21qtSq70P +fFQUbG2XVVscckIFQa8DuDc= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/test/Data/Key.RSA.PKCS8.txt b/test/Data/Key.RSA.PKCS8.txt new file mode 100644 index 000000000..723bd0f0a --- /dev/null +++ b/test/Data/Key.RSA.PKCS8.txt @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQC5O1ef4Fq1fWgm +6+Gp8lnDmNz+lwjElQ+a6gUIff5td8oEn/3iLE0RPNkFqzK9P+jNugBsIbepwk5j +F/YER5MAhd7WMsChN3UYoLAy9k7KOew833n+UKHB92cFszOllhMZ+hTKVeZ7+bOO +Mu78nSpeBHmXKT0cVP7HlgS1GXxVIeIOQspNnft3CGyqByz4+R+9gxQr4Lx6+d8T +S2BaApmTQRq2XzuctbJVcHgvOFIO0YosI8A6Ctft9h+mUPAnZYrU3qcbQWfFbUeE +N5Irt7ZNsBra9lCC8Vcxac7g781kqngI6k5F7KWJaF20oCOv/5wPjIN8+OGOMo5h +/Fu91EbhAgEjAoIBACpWtPFX2jgcqheGX3dNVliX9/+tfljRnSq5JbjMV2l6d1GD +p76rCk0VOOtaVL2K82I5JKsAZH6S0BamZB48PtuMUDD1qF9dIhRB/GNrf7kxz5ji +n4qWFlg4jJOWrLgiTYJHyjzgbzJHtAM+14oyjVdReuC4+AZ509XZJaW8rrRfIBeq +x7AOGLtJ4iZmiYrNuHfdJeNXFqTMd9rwERR4gh5H2gWVAy5h2jgaseEU7ZP6D+Cr +D+RV3XOR4TC3Tp9lUMStXCn63B7DHG/CuTgIpQLNq9+EN+Lmwnlh3OEMFGCTIGAk +j5/Xl0rKqo6IClqtX367OsPq8i42eVWipACK6AsCgYEA8GWLLfZ7zeeyEGScGfkc +4ras7drXMfG9iv83MhNe11k6Nq03J9e2TCIuX96Xm1mEm8p72ci1Ij/jDua+W9dl +9byHcxHSpvxq3iNZrzJraHAR6upomieqONv54GGDbuW1khBGTwG/oCldMBaRz50U +aEQjKyiQNBftXvYF2uLO6nUCgYEAxUEscrTkgVvzHt1qeUCYNfpuoI5sh3g9x7Y5 +440UiPWMijC8JdoTS33NThflJ03m6Oq7gOpeDNR014pwnFakU7vgwNHFPcJszPfp ++KQme/FaX/6rQdqVi4JjyCbXhVhxOFQECujdz3jUg257JsY0sgD2NztEyewW3JVO +81ilpT0CgYAUmv1NFSCN/eqw8q5LXn7RmqEbs6wLmGC0JIES67esDvZcdT897esN +1wtKC8PaHZ2m9Bk+jYveXT9ZDHa3ajvwfd+5Z+18BwHYhq/qcgk01mfvkG9dq6Dg +TV6Pk1Rol1i0v5D/dS2upHWzqinBVptZZO0SU+8aaHNuih3CTfR6fwKBgDK4/M0J +8Z2bTSUxnwk8fulPBoEOrjF2sMz0WAdQKdoTQWVc/S5OBPYnqdJAqKO08jvklp1+ +GC8vUT69MuZfbBWIFTjle9yuVn3ZWWvScEvBuCdQHWi0jNq7IPj0C4iwV6DFJZxn +xAImYogyWi6KvRfUXJHcCl/O/pB+Kj6TI0e/AoGBAK3DGiOTNRJ9XfMO3pthIsHO +BeCj9mv2VL6BKCA/vYPMg2ZbaBsDR+QzZm4mW1x9qQq/iBVf/XOijP7u37huPp2q +35uXuFjPRWdNINka6jksoOJ//iBIat1uULZAtO5fYeNYJl2y57uZHAvtxdHjOUig +T335HKF3G9znAdJ9iv8k +-----END PRIVATE KEY----- diff --git a/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs b/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs index 49cdee29d..261455332 100644 --- a/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs +++ b/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs @@ -303,8 +303,12 @@ public void ConstructorWithFileNameAndPassPhraseShouldBeAbleToReadFileThatIsShar } [TestMethod] + [DataRow("Key.DSA.PKCS8.Encrypted.Aes.256.CBC.12345.txt", "12345", typeof(DsaKey))] + [DataRow("Key.DSA.PKCS8.txt", null, typeof(DsaKey))] [DataRow("Key.DSA.txt", null, typeof(DsaKey))] [DataRow("Key.ECDSA.Encrypted.txt", "12345", typeof(EcdsaKey))] + [DataRow("Key.ECDSA.PKCS8.Encrypted.Aes.256.CBC.12345.txt", "12345", typeof(EcdsaKey))] + [DataRow("Key.ECDSA.PKCS8.txt", null, typeof(EcdsaKey))] [DataRow("Key.ECDSA.txt", null, typeof(EcdsaKey))] [DataRow("Key.ECDSA384.Encrypted.txt", "12345", typeof(EcdsaKey))] [DataRow("Key.ECDSA384.txt", null, typeof(EcdsaKey))] @@ -326,6 +330,8 @@ public void ConstructorWithFileNameAndPassPhraseShouldBeAbleToReadFileThatIsShar [DataRow("Key.OPENSSH.ED25519.Encrypted.Aes.256.CTR.txt", "12345", typeof(ED25519Key))] [DataRow("Key.OPENSSH.ED25519.Encrypted.ChaCha20.Poly1305.txt", "12345", typeof(ED25519Key))] [DataRow("Key.OPENSSH.ED25519.Encrypted.txt", "12345", typeof(ED25519Key))] + [DataRow("Key.OPENSSH.ED25519.PKCS8.Encrypted.Aes.256.CBC.12345.txt", "12345", typeof(ED25519Key))] + [DataRow("Key.OPENSSH.ED25519.PKCS8.txt", null, typeof(ED25519Key))] [DataRow("Key.OPENSSH.ED25519.txt", null, typeof(ED25519Key))] [DataRow("Key.OPENSSH.RSA.Encrypted.Aes.192.CTR.txt", "12345", typeof(RsaKey))] [DataRow("Key.OPENSSH.RSA.Encrypted.txt", "12345", typeof(RsaKey))] @@ -336,6 +342,8 @@ public void ConstructorWithFileNameAndPassPhraseShouldBeAbleToReadFileThatIsShar [DataRow("Key.RSA.Encrypted.Des.CBC.12345.txt", "12345", typeof(RsaKey))] [DataRow("Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt", "12345", typeof(RsaKey))] [DataRow("Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt", "1234567890", typeof(RsaKey))] + [DataRow("Key.RSA.PKCS8.Encrypted.Aes.256.CBC.12345.txt", "12345", typeof(RsaKey))] + [DataRow("Key.RSA.PKCS8.txt", null, typeof(RsaKey))] [DataRow("Key.RSA.txt", null, typeof(RsaKey))] [DataRow("Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt", "12345", typeof(DsaKey))] [DataRow("Key.SSH2.DSA.txt", null, typeof(DsaKey))] @@ -356,94 +364,6 @@ public void Test_PrivateKey(string name, string passPhrase, Type expectedKeyType } } - [TestMethod] - [Owner("scott-xu")] - [TestCategory("PrivateKey")] - public void Test_PrivateKey_PKCS8_RSA() - { - using (var stream = GetData("Key.PKCS8.RSA.txt")) - { - TestRsaKeyFile(new PrivateKeyFile(stream)); - } - } - - [TestMethod] - [Owner("scott-xu")] - [TestCategory("PrivateKey")] - public void Test_PrivateKey_PKCS8_RSA_Encrypted() - { - using (var stream = GetData("Key.PKCS8.RSA.Encrypted.Aes.256.CBC.12345.txt")) - { - TestRsaKeyFile(new PrivateKeyFile(stream, "12345")); - } - } - - [TestMethod] - [Owner("scott-xu")] - [TestCategory("PrivateKey")] - public void Test_PrivateKey_PKCS8_DSA() - { - using (var stream = GetData("Key.PKCS8.DSA.txt")) - { - _ = new PrivateKeyFile(stream); - } - } - - [TestMethod] - [Owner("scott-xu")] - [TestCategory("PrivateKey")] - public void Test_PrivateKey_PKCS8_DSA_Encrypted() - { - using (var stream = GetData("Key.PKCS8.DSA.Encrypted.Aes.256.CBC.12345.txt")) - { - _ = new PrivateKeyFile(stream, "12345"); - } - } - - [TestMethod] - [Owner("scott-xu")] - [TestCategory("PrivateKey")] - public void Test_PrivateKey_PKCS8_ECDSA() - { - using (var stream = GetData("Key.PKCS8.ECDSA.txt")) - { - _ = new PrivateKeyFile(stream); - } - } - - [TestMethod] - [Owner("scott-xu")] - [TestCategory("PrivateKey")] - public void Test_PrivateKey_PKCS8_ECDSA_Encrypted() - { - using (var stream = GetData("Key.PKCS8.ECDSA.Encrypted.Aes.256.CBC.12345.txt")) - { - _ = new PrivateKeyFile(stream, "12345"); - } - } - - [TestMethod] - [Owner("scott-xu")] - [TestCategory("PrivateKey")] - public void Test_PrivateKey_PKCS8_ED25519() - { - using (var stream = GetData("Key.PKCS8.ED25519.txt")) - { - _ = new PrivateKeyFile(stream); - } - } - - [TestMethod] - [Owner("scott-xu")] - [TestCategory("PrivateKey")] - public void Test_PrivateKey_PKCS8_ED25519_Encrypted() - { - using (var stream = GetData("Key.PKCS8.ED25519.Encrypted.Aes.256.CBC.12345.txt")) - { - _ = new PrivateKeyFile(stream, "12345"); - } - } - private void SaveStreamToFile(Stream stream, string fileName) { var buffer = new byte[4000]; From 70976072d3d010222cb9d02900be1f493b916c87 Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Fri, 20 Sep 2024 22:49:17 +0800 Subject: [PATCH 5/7] Minimize the change --- src/Renci.SshNet/PrivateKeyFile.cs | 282 +++--------------- .../Security/Cryptography/DsaKey.cs | 26 ++ .../Security/Cryptography/EcdsaKey.cs | 40 ++- .../Security/Cryptography/RsaKey.cs | 34 +-- 4 files changed, 125 insertions(+), 257 deletions(-) diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index b46e23796..2b00d30b5 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -314,22 +314,22 @@ private void Open(Stream privateKey, string? passPhrase) switch (keyName) { case "RSA PRIVATE KEY": - _key = ParseRSAPrivateKey_Pkcs1(decryptedData); + _key = new RsaKey(decryptedData); break; case "DSA PRIVATE KEY": - _key = ParseDSSPrivateKey_OpenSSL(decryptedData); + _key = new DsaKey(decryptedData); break; case "EC PRIVATE KEY": - _key = ParseECPrivateKey_SEC1(decryptedData); + _key = new EcdsaKey(decryptedData); break; case "PRIVATE KEY": var privateKeyInfo = PrivateKeyInfo.GetInstance(binaryData); - _key = ParsePkcs8PrivateKey(privateKeyInfo); + _key = ParseOpenSslPkcs8PrivateKey(privateKeyInfo); break; case "ENCRYPTED PRIVATE KEY": var encryptedPrivateKeyInfo = EncryptedPrivateKeyInfo.GetInstance(binaryData); privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(passPhrase?.ToCharArray(), encryptedPrivateKeyInfo); - _key = ParsePkcs8PrivateKey(privateKeyInfo); + _key = ParseOpenSslPkcs8PrivateKey(privateKeyInfo); break; case "OPENSSH PRIVATE KEY": _key = ParseOpenSshV1Key(decryptedData, passPhrase); @@ -507,8 +507,8 @@ private static byte[] DecryptKey(CipherInfo cipherInfo, byte[] cipherData, strin } /// - /// Parses an OpenSSH V1 key file (i.e. ED25519 key) according to the the key spec: - /// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key. + /// Parses an OpenSSH V1 key file according to the key spec: + /// . /// /// The key file data (i.e. base64 encoded data between the header/footer). /// Passphrase or if there isn't one. @@ -733,262 +733,78 @@ private static Key ParseOpenSshV1Key(byte[] keyFileData, string? passPhrase) } /// - /// Parses PKCS#8 PrivateKeyInfo. + /// Parses an OpenSSL PKCS#8 key file according to RFC5208: + /// . /// - /// The PKCS#8 PrivateKeyInfo. - /// - /// . - /// - /// The . + /// The . + /// + /// The . + /// /// Algorithm not supported. - private static Key ParsePkcs8PrivateKey(PrivateKeyInfo privateKeyInfo) + private static Key ParseOpenSslPkcs8PrivateKey(PrivateKeyInfo privateKeyInfo) { var algorithmOid = privateKeyInfo.PrivateKeyAlgorithm.Algorithm; var key = privateKeyInfo.PrivateKey.GetOctets(); if (algorithmOid.Equals(PkcsObjectIdentifiers.RsaEncryption)) { - return ParseRSAPrivateKey_Pkcs1(key); + return new RsaKey(key); } if (algorithmOid.Equals(X9ObjectIdentifiers.IdDsa)) { var parameters = privateKeyInfo.PrivateKeyAlgorithm.Parameters.GetDerEncoded(); - return ParseDSAPrivateKey_Pkcs8_OpenSSL(parameters, key); - } + var parametersReader = new AsnReader(parameters, AsnEncodingRules.BER); + var sequenceReader = parametersReader.ReadSequence(); + parametersReader.ThrowIfNotEmpty(); - if (algorithmOid.Equals(X9ObjectIdentifiers.IdECPublicKey)) - { - var parameters2 = privateKeyInfo.PrivateKeyAlgorithm.Parameters.GetDerEncoded(); - return ParseECPrivateKey_Pkcs8_OpenSSL(parameters2, key); - } + var p = sequenceReader.ReadInteger(); + var q = sequenceReader.ReadInteger(); + var g = sequenceReader.ReadInteger(); + sequenceReader.ThrowIfNotEmpty(); - if (algorithmOid.Equals(EdECObjectIdentifiers.id_Ed25519)) - { - return new ED25519Key(key); - } + var keyReader = new AsnReader(key, AsnEncodingRules.BER); + var x = keyReader.ReadInteger(); + keyReader.ThrowIfNotEmpty(); - throw new SshException(string.Format(CultureInfo.InvariantCulture, "Private key algorithm \"{0}\" is not supported.", algorithmOid)); - } + var y = BigInteger.ModPow(g, x, p); - /// - /// Parses PKCS#1 RSA private key. - /// - /// - /// . - /// - /// RSAPrivateKey ::= SEQUENCE { - /// version INTEGER, - /// modulus INTEGER, -- n - /// publicExponent INTEGER, -- e - /// privateExponent INTEGER, -- d - /// prime1 INTEGER, -- p - /// prime2 INTEGER, -- q - /// exponent1 INTEGER, -- d mod (p-1) - /// exponent2 INTEGER, -- d mod (q-1) - /// coefficient INTEGER -- (inverse of q) mod p - /// } - /// - /// - /// The key data. - /// The . - private static RsaKey ParseRSAPrivateKey_Pkcs1(byte[] keyData) - { - var keyReader = new AsnReader(keyData, AsnEncodingRules.BER); - var sequenceReader = keyReader.ReadSequence(); - - // Some key has extra byte, for example 'Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt' at the test data folder. - ////keyReader.ThrowIfNotEmpty(); - - var version = sequenceReader.ReadInteger(); - if (version != BigInteger.Zero) - { - throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "RSA version '{0}' is not supported.", version)); + return new DsaKey(p, q, g, y, x); } - var modulus = sequenceReader.ReadInteger(); - var exponent = sequenceReader.ReadInteger(); - var d = sequenceReader.ReadInteger(); - var p = sequenceReader.ReadInteger(); - var q = sequenceReader.ReadInteger(); - var dp = sequenceReader.ReadInteger(); - var dq = sequenceReader.ReadInteger(); - var inverseQ = sequenceReader.ReadInteger(); - sequenceReader.ThrowIfNotEmpty(); - - return new RsaKey(modulus, exponent, d, p, q, dp, dq, inverseQ); - } - - /// - /// Parses OpenSSL DSA private key. - /// - /// The key data. - /// - /// OpenSSL produces ASN.1 DER encoded form of an ASN.1 SEQUENCE consisting of the values of - /// version (currently zero), p, q, g, the public and private key components respectively as ASN.1 INTEGERs. - /// . - /// - /// DSSPrivatKey_OpenSSL ::= SEQUENCE { - /// version INTEGER, - /// p INTEGER, - /// q INTEGER, - /// g INTEGER, - /// y INTEGER, - /// x INTEGER - /// } - /// - /// - /// The . - private static DsaKey ParseDSSPrivateKey_OpenSSL(byte[] keyData) - { - var keyReader = new AsnReader(keyData, AsnEncodingRules.BER); - var sequenceReader = keyReader.ReadSequence(); - keyReader.ThrowIfNotEmpty(); - - var version = sequenceReader.ReadInteger(); - if (version != BigInteger.Zero) + if (algorithmOid.Equals(X9ObjectIdentifiers.IdECPublicKey)) { - throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "DSA version '{0}' is not supported.", version)); - } - - var p = sequenceReader.ReadInteger(); - var q = sequenceReader.ReadInteger(); - var g = sequenceReader.ReadInteger(); - var y = sequenceReader.ReadInteger(); - var x = sequenceReader.ReadInteger(); - sequenceReader.ThrowIfNotEmpty(); - - return new DsaKey(p, q, g, y, x); - } - - /// - /// Parses OpenSSL DSA private key in Pkcs#8 format. - /// - /// The parameters data. - /// The key data. - /// - /// The format of PKCS#8 DSA (and other) private keys is not well documented: - /// it is hidden away in PKCS#11 v2.01, section 11.9. - /// OpenSSL's default DSA PKCS#8 private key format complies with this standard. - /// - /// . - /// - /// Dss-Parms ::= SEQUENCE { - /// p INTEGER, - /// q INTEGER, - /// g INTEGER - /// } - /// - /// DSAprivatekeys are represented as BER-encoded ASN.1 type INTEGER. - /// - /// The . - private static DsaKey ParseDSAPrivateKey_Pkcs8_OpenSSL(byte[] parametersData, byte[] keyData) - { - var parametersReader = new AsnReader(parametersData, AsnEncodingRules.BER); - var sequenceReader = parametersReader.ReadSequence(); - parametersReader.ThrowIfNotEmpty(); + var parameters = privateKeyInfo.PrivateKeyAlgorithm.Parameters.GetDerEncoded(); + var parametersReader = new AsnReader(parameters, AsnEncodingRules.DER); + var curve = parametersReader.ReadObjectIdentifier(); + parametersReader.ThrowIfNotEmpty(); - var p = sequenceReader.ReadInteger(); - var q = sequenceReader.ReadInteger(); - var g = sequenceReader.ReadInteger(); - sequenceReader.ThrowIfNotEmpty(); + var privateKeyReader = new AsnReader(key, AsnEncodingRules.DER); + var sequenceReader = privateKeyReader.ReadSequence(); + privateKeyReader.ThrowIfNotEmpty(); - var keyReader = new AsnReader(keyData, AsnEncodingRules.BER); - var x = keyReader.ReadInteger(); - keyReader.ThrowIfNotEmpty(); + var version = sequenceReader.ReadInteger(); + if (version != BigInteger.One) + { + throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "EC version '{0}' is not supported.", version)); + } - var y = BigInteger.ModPow(g, x, p); + var privatekey = sequenceReader.ReadOctetString(); - return new DsaKey(p, q, g, y, x); - } + var publicKeyReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1, isConstructed: true)); + var publickey = publicKeyReader.ReadBitString(out _); + publicKeyReader.ThrowIfNotEmpty(); - /// - /// Parses OpenSSL EC private key. - /// - /// The key data. - /// - /// OpenSSL produces ASN.1 DER encoded SEC1 private key. - /// - /// . - /// Republished as RFC5915 , - /// See answer at . - /// - /// ECPrivateKey ::= SEQUENCE { - /// version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), - /// privateKey OCTET STRING, - /// parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL, - /// publicKey [1] BIT STRING OPTIONAL - /// } - /// - /// When generating a transfer encoding, generators SHOULD use - /// Distinguished Encoding Rules (DER) and receivers SHOULD be - /// prepared to handle Basic Encoding Rules (BER) and DER. - /// - /// The . - private static EcdsaKey ParseECPrivateKey_SEC1(byte[] keyData) - { - var keyReader = new AsnReader(keyData, AsnEncodingRules.DER); - var sequenceReader = keyReader.ReadSequence(); - keyReader.ThrowIfNotEmpty(); + sequenceReader.ThrowIfNotEmpty(); - var version = sequenceReader.ReadInteger(); - if (version != BigInteger.One) - { - throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "EC version '{0}' is not supported.", version)); + return new EcdsaKey(curve, publickey, privatekey); } - var privatekey = sequenceReader.ReadOctetString(); - - // Though the ASN.1 indicates that the parameters field is OPTIONAL, - // implementations that conform to this document MUST always include the parameters field. - var parametersReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0, isConstructed: true)); - var curve = parametersReader.ReadObjectIdentifier(); - parametersReader.ThrowIfNotEmpty(); - - // Though the ASN.1 indicates publicKey is OPTIONAL, - // implementations that conform to this document SHOULD always include the publicKey field. - var publicKeyReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1, isConstructed: true)); - var publickey = publicKeyReader.ReadBitString(out _); - publicKeyReader.ThrowIfNotEmpty(); - - sequenceReader.ThrowIfNotEmpty(); - - return new EcdsaKey(curve, publickey, privatekey); - } - - /// - /// Parses OpenSSL EC private key in Pkcs#8 format. - /// - /// The parameters data. - /// The key data. - /// - /// The format of PKCS#8 EC private keys is not well documented. - /// - /// The . - private static EcdsaKey ParseECPrivateKey_Pkcs8_OpenSSL(byte[] parametersData, byte[] keyData) - { - var parametersReader = new AsnReader(parametersData, AsnEncodingRules.DER); - var curve = parametersReader.ReadObjectIdentifier(); - parametersReader.ThrowIfNotEmpty(); - - var privateKeyReader = new AsnReader(keyData, AsnEncodingRules.DER); - var sequenceReader = privateKeyReader.ReadSequence(); - privateKeyReader.ThrowIfNotEmpty(); - - var version = sequenceReader.ReadInteger(); - if (version != BigInteger.One) + if (algorithmOid.Equals(EdECObjectIdentifiers.id_Ed25519)) { - throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "EC version '{0}' is not supported.", version)); + return new ED25519Key(key); } - var privatekey = sequenceReader.ReadOctetString(); - - var publicKeyReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1, isConstructed: true)); - var publickey = publicKeyReader.ReadBitString(out _); - publicKeyReader.ThrowIfNotEmpty(); - - sequenceReader.ThrowIfNotEmpty(); - - return new EcdsaKey(curve, publickey, privatekey); + throw new SshException(string.Format(CultureInfo.InvariantCulture, "Private key algorithm \"{0}\" is not supported.", algorithmOid)); } /// diff --git a/src/Renci.SshNet/Security/Cryptography/DsaKey.cs b/src/Renci.SshNet/Security/Cryptography/DsaKey.cs index 0973c5e98..2a394b25b 100644 --- a/src/Renci.SshNet/Security/Cryptography/DsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/DsaKey.cs @@ -1,5 +1,6 @@ #nullable enable using System; +using System.Formats.Asn1; using System.Numerics; using System.Security.Cryptography; @@ -115,6 +116,31 @@ public DsaKey(SshKeyData publicKeyData) DSA = LoadDSA(); } + /// + /// Initializes a new instance of the class. + /// + /// DER encoded private key data. + public DsaKey(byte[] privateKeyData) + { + if (privateKeyData is null) + { + throw new ArgumentNullException(nameof(privateKeyData)); + } + + var der = new AsnReader(privateKeyData, AsnEncodingRules.DER).ReadSequence(); + _ = der.ReadInteger(); // skip version + + P = der.ReadInteger(); + Q = der.ReadInteger(); + G = der.ReadInteger(); + Y = der.ReadInteger(); + X = der.ReadInteger(); + + der.ThrowIfNotEmpty(); + + DSA = LoadDSA(); + } + /// /// Initializes a new instance of the class. /// diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs index 47e9e2052..31957c10e 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs @@ -1,6 +1,7 @@ #nullable enable using System; using System.Diagnostics; +using System.Formats.Asn1; using System.Numerics; using System.Security.Cryptography; using System.Text; @@ -203,12 +204,34 @@ public EcdsaKey(SshKeyData publicKeyData) /// /// Initializes a new instance of the class. /// - /// The curve oid. + /// The curve name or oid. /// Value of publickey. /// Value of privatekey. public EcdsaKey(string curve, byte[] publickey, byte[] privatekey) { - _impl = Import(curve, publickey, privatekey.TrimLeadingZeros()); + _impl = Import(GetCurveOid(curve), publickey, privatekey.TrimLeadingZeros()); + } + + /// + /// Initializes a new instance of the class. + /// + /// DER encoded private key data. + public EcdsaKey(byte[] data) + { + var der = new AsnReader(data, AsnEncodingRules.DER).ReadSequence(); + _ = der.ReadInteger(); // skip version + + var privatekey = der.ReadOctetString().TrimLeadingZeros(); + + var s0 = der.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0, isConstructed: true)); + var curve = s0.ReadObjectIdentifier(); + + var s1 = der.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1, isConstructed: true)); + var pubkey = s1.ReadBitString(out _); + + der.ThrowIfNotEmpty(); + + _impl = Import(curve, pubkey, privatekey); } #pragma warning disable CA1859 // Use concrete types when possible for improved performance @@ -243,24 +266,27 @@ private static Impl Import(string curve_oid, byte[] publickey, byte[]? privateke #endif } - private static string GetCurveOid(string curve_s) + private static string GetCurveOid(string curve) { - if (string.Equals(curve_s, "nistp256", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(curve, "nistp256", StringComparison.OrdinalIgnoreCase) || + string.Equals(curve, ECDSA_P256_OID_VALUE)) { return ECDSA_P256_OID_VALUE; } - if (string.Equals(curve_s, "nistp384", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(curve, "nistp384", StringComparison.OrdinalIgnoreCase) || + string.Equals(curve, ECDSA_P384_OID_VALUE)) { return ECDSA_P384_OID_VALUE; } - if (string.Equals(curve_s, "nistp521", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(curve, "nistp521", StringComparison.OrdinalIgnoreCase) || + string.Equals(curve, ECDSA_P521_OID_VALUE)) { return ECDSA_P521_OID_VALUE; } - throw new SshException("Unexpected Curve Name: " + curve_s); + throw new SshException("Unexpected Curve: " + curve); } /// diff --git a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs index e74f4db32..e30502941 100644 --- a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs @@ -1,5 +1,6 @@ #nullable enable using System; +using System.Formats.Asn1; using System.Numerics; using System.Security.Cryptography; @@ -155,25 +156,24 @@ public RsaKey(SshKeyData publicKeyData) /// /// Initializes a new instance of the class. /// - /// The modulus. - /// The exponent. - /// The d. - /// The p. - /// The q. - /// The dp. - /// The dq. - /// The inverse Q. - public RsaKey(BigInteger modulus, BigInteger exponent, BigInteger d, BigInteger p, BigInteger q, BigInteger dp, BigInteger dq, BigInteger inverseQ) + /// DER encoded private key data. + public RsaKey(byte[] privateKeyData) { - Modulus = modulus; - Exponent = exponent; - D = d; - P = p; - Q = q; - DP = dp; - DQ = dq; - InverseQ = inverseQ; + ThrowHelper.ThrowIfNull(privateKeyData); + + var der = new AsnReader(privateKeyData, AsnEncodingRules.DER).ReadSequence(); + _ = der.ReadInteger(); // skip version + + Modulus = der.ReadInteger(); + Exponent = der.ReadInteger(); + D = der.ReadInteger(); + P = der.ReadInteger(); + Q = der.ReadInteger(); + DP = der.ReadInteger(); + DQ = der.ReadInteger(); + InverseQ = der.ReadInteger(); + der.ThrowIfNotEmpty(); RSA = RSA.Create(); RSA.ImportParameters(GetRSAParameters()); } From 0c3bcae5e301131a28ce2075556b2d671c3c87fe Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Fri, 20 Sep 2024 23:11:17 +0800 Subject: [PATCH 6/7] Minimize the change --- src/Renci.SshNet/PrivateKeyFile.cs | 86 +++++++++++++++---- .../Security/Cryptography/DsaKey.cs | 16 +--- .../Security/Cryptography/EcdsaKey.cs | 2 +- .../Security/Cryptography/RsaKey.cs | 1 + 4 files changed, 70 insertions(+), 35 deletions(-) diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index 2b00d30b5..d50902b92 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -314,25 +314,80 @@ private void Open(Stream privateKey, string? passPhrase) switch (keyName) { case "RSA PRIVATE KEY": - _key = new RsaKey(decryptedData); + var rsaKey = new RsaKey(decryptedData); + _key = rsaKey; + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); +#pragma warning disable CA2000 // Dispose objects before losing scope + _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(rsaKey, HashAlgorithmName.SHA512))); + _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(rsaKey, HashAlgorithmName.SHA256))); +#pragma warning restore CA2000 // Dispose objects before losing scope break; case "DSA PRIVATE KEY": _key = new DsaKey(decryptedData); + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-dss", _key)); break; case "EC PRIVATE KEY": _key = new EcdsaKey(decryptedData); + _hostAlgorithms.Add(new KeyHostAlgorithm(_key.ToString(), _key)); break; case "PRIVATE KEY": var privateKeyInfo = PrivateKeyInfo.GetInstance(binaryData); _key = ParseOpenSslPkcs8PrivateKey(privateKeyInfo); + if (_key is RsaKey parsedRsaKey) + { + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); +#pragma warning disable CA2000 // Dispose objects before losing scope + _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(parsedRsaKey, HashAlgorithmName.SHA512))); + _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(parsedRsaKey, HashAlgorithmName.SHA256))); +#pragma warning restore CA2000 // Dispose objects before losing scope + } + else if (_key is DsaKey parsedDsaKey) + { + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-dss", _key)); + } + else + { + _hostAlgorithms.Add(new KeyHostAlgorithm(_key.ToString(), _key)); + } + break; case "ENCRYPTED PRIVATE KEY": var encryptedPrivateKeyInfo = EncryptedPrivateKeyInfo.GetInstance(binaryData); privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(passPhrase?.ToCharArray(), encryptedPrivateKeyInfo); _key = ParseOpenSslPkcs8PrivateKey(privateKeyInfo); + if (_key is RsaKey parsedRsaKey2) + { + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); +#pragma warning disable CA2000 // Dispose objects before losing scope + _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(parsedRsaKey2, HashAlgorithmName.SHA512))); + _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(parsedRsaKey2, HashAlgorithmName.SHA256))); +#pragma warning restore CA2000 // Dispose objects before losing scope + } + else if (_key is DsaKey parsedDsaKey) + { + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-dss", _key)); + } + else + { + _hostAlgorithms.Add(new KeyHostAlgorithm(_key.ToString(), _key)); + } + break; case "OPENSSH PRIVATE KEY": _key = ParseOpenSshV1Key(decryptedData, passPhrase); + if (_key is RsaKey parsedRsaKey3) + { + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); +#pragma warning disable CA2000 // Dispose objects before losing scope + _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(parsedRsaKey3, HashAlgorithmName.SHA512))); + _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(parsedRsaKey3, HashAlgorithmName.SHA256))); +#pragma warning restore CA2000 // Dispose objects before losing scope + } + else + { + _hostAlgorithms.Add(new KeyHostAlgorithm(_key.ToString(), _key)); + } + break; case "SSH2 ENCRYPTED PRIVATE KEY": var reader = new SshDataReader(decryptedData); @@ -389,7 +444,13 @@ private void Open(Stream privateKey, string? passPhrase) var inverseQ = reader.ReadBigIntWithBits(); // u var q = reader.ReadBigIntWithBits(); // p var p = reader.ReadBigIntWithBits(); // q - _key = new RsaKey(modulus, exponent, d, p, q, inverseQ); + var decryptedRsaKey = new RsaKey(modulus, exponent, d, p, q, inverseQ); + _key = decryptedRsaKey; + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); +#pragma warning disable CA2000 // Dispose objects before losing scope + _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(decryptedRsaKey, HashAlgorithmName.SHA512))); + _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(decryptedRsaKey, HashAlgorithmName.SHA256))); +#pragma warning restore CA2000 // Dispose objects before losing scope } else if (keyType.Contains("dsa")) { @@ -405,6 +466,7 @@ private void Open(Stream privateKey, string? passPhrase) var y = reader.ReadBigIntWithBits(); var x = reader.ReadBigIntWithBits(); _key = new DsaKey(p, q, g, y, x); + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-dss", _key)); } else { @@ -415,19 +477,6 @@ private void Open(Stream privateKey, string? passPhrase) default: throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Key '{0}' is not supported.", keyName)); } - - if (_key is RsaKey parsedRsaKey) - { - _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); -#pragma warning disable CA2000 // Dispose objects before losing scope - _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(parsedRsaKey, HashAlgorithmName.SHA512))); - _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(parsedRsaKey, HashAlgorithmName.SHA256))); -#pragma warning restore CA2000 // Dispose objects before losing scope - } - else - { - _hostAlgorithms.Add(new KeyHostAlgorithm(_key.ToString(), _key)); - } } private static byte[] GetCipherKey(string passphrase, int length) @@ -692,15 +741,14 @@ private static Key ParseOpenSshV1Key(byte[] keyFileData, string? passPhrase) case "ecdsa-sha2-nistp521": // curve var len = (int)privateKeyReader.ReadUInt32(); - var curveName = Encoding.ASCII.GetString(privateKeyReader.ReadBytes(len)); - var curveOid = SshNamedCurves.GetOid(curveName).GetID(); + var curve = Encoding.ASCII.GetString(privateKeyReader.ReadBytes(len)); // public key publicKey = privateKeyReader.ReadBignum2(); // private key unencryptedPrivateKey = privateKeyReader.ReadBignum2(); - parsedKey = new EcdsaKey(curveOid, publicKey, unencryptedPrivateKey); + parsedKey = new EcdsaKey(curve, publicKey, unencryptedPrivateKey.TrimLeadingZeros()); break; case "ssh-rsa": var modulus = privateKeyReader.ReadBignum(); // n @@ -796,7 +844,7 @@ private static Key ParseOpenSslPkcs8PrivateKey(PrivateKeyInfo privateKeyInfo) sequenceReader.ThrowIfNotEmpty(); - return new EcdsaKey(curve, publickey, privatekey); + return new EcdsaKey(curve, publickey, privatekey.TrimLeadingZeros()); } if (algorithmOid.Equals(EdECObjectIdentifiers.id_Ed25519)) diff --git a/src/Renci.SshNet/Security/Cryptography/DsaKey.cs b/src/Renci.SshNet/Security/Cryptography/DsaKey.cs index 2a394b25b..a1102b572 100644 --- a/src/Renci.SshNet/Security/Cryptography/DsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/DsaKey.cs @@ -16,17 +16,6 @@ public class DsaKey : Key, IDisposable { private DsaDigitalSignature? _digitalSignature; - /// - /// Gets the SSH name of the DSA Key. - /// - /// - /// The SSH name of the DSA Key. - /// - public override string ToString() - { - return "ssh-dss"; - } - internal DSA DSA { get; } /// @@ -122,10 +111,7 @@ public DsaKey(SshKeyData publicKeyData) /// DER encoded private key data. public DsaKey(byte[] privateKeyData) { - if (privateKeyData is null) - { - throw new ArgumentNullException(nameof(privateKeyData)); - } + ThrowHelper.ThrowIfNull(privateKeyData); var der = new AsnReader(privateKeyData, AsnEncodingRules.DER).ReadSequence(); _ = der.ReadInteger(); // skip version diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs index 31957c10e..c970a323e 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs @@ -209,7 +209,7 @@ public EcdsaKey(SshKeyData publicKeyData) /// Value of privatekey. public EcdsaKey(string curve, byte[] publickey, byte[] privatekey) { - _impl = Import(GetCurveOid(curve), publickey, privatekey.TrimLeadingZeros()); + _impl = Import(GetCurveOid(curve), publickey, privatekey); } /// diff --git a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs index e30502941..e1456ea61 100644 --- a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs @@ -174,6 +174,7 @@ public RsaKey(byte[] privateKeyData) InverseQ = der.ReadInteger(); der.ThrowIfNotEmpty(); + RSA = RSA.Create(); RSA.ImportParameters(GetRSAParameters()); } From 5f0869e8c57363ea6b0fd641fb37ea780fcfe0e9 Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Sat, 21 Sep 2024 07:45:15 +0800 Subject: [PATCH 7/7] Fix build --- src/Renci.SshNet/PrivateKeyFile.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index d50902b92..341a429d5 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using System; using System.Collections.Generic; using System.Diagnostics; @@ -14,7 +14,6 @@ using Org.BouncyCastle.Asn1.EdEC; using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Asn1.X9; -using Org.BouncyCastle.Crypto.Utilities; using Org.BouncyCastle.Pkcs; using Renci.SshNet.Common;