DSA is removed at compile time from OpenSSH 9.8 and higher.
That means we can no longer test it in our integration tests. It seems like a
good time to remove it. From the OpenSSH release notes:

    DSA, as specified in the SSHv2 protocol, is inherently weak - being
    limited to a 160 bit private key and use of the SHA1 digest. Its
    estimated security level is only 80 bits symmetric equivalent.

    OpenSSH has disabled DSA keys by default since 2015 but has retained
    run-time optional support for them. DSA was the only mandatory-to-
    implement algorithm in the SSHv2 RFCs, mostly because alternative
    algorithms were encumbered by patents when the SSHv2 protocol was
    specified.

    This has not been the case for decades at this point and better
    algorithms are well supported by all actively-maintained SSH
    implementations. We do not consider the costs of maintaining DSA
    in OpenSSH to be justified and hope that removing it from OpenSSH
    can accelerate its wider deprecation in supporting cryptography
    libraries.
This commit is contained in:
Rob Hague
2025-01-03 11:12:21 +01:00
committed by GitHub
parent 2e68828f61
commit 60f3cd803e
25 changed files with 6 additions and 749 deletions
-1
View File
@@ -407,7 +407,6 @@ namespace Renci.SshNet
hostAlgs.Add("rsa-sha2-512", data => { var key = new RsaKey(new SshKeyData(data)); return new KeyHostAlgorithm("rsa-sha2-512", key, new RsaDigitalSignature(key, HashAlgorithmName.SHA512)); });
hostAlgs.Add("rsa-sha2-256", data => { var key = new RsaKey(new SshKeyData(data)); return new KeyHostAlgorithm("rsa-sha2-256", key, new RsaDigitalSignature(key, HashAlgorithmName.SHA256)); });
hostAlgs.Add("ssh-rsa", data => new KeyHostAlgorithm("ssh-rsa", new RsaKey(new SshKeyData(data))));
hostAlgs.Add("ssh-dss", data => new KeyHostAlgorithm("ssh-dss", new DsaKey(new SshKeyData(data))));
#pragma warning restore SA1107 // Code should not contain multiple statements on one line
HostKeyAlgorithms = hostAlgs;
-2
View File
@@ -80,8 +80,6 @@ namespace Renci.SshNet
{
case "RSA PRIVATE KEY":
return new RsaKey(decryptedData);
case "DSA PRIVATE KEY":
return new DsaKey(decryptedData);
case "EC PRIVATE KEY":
return new EcdsaKey(decryptedData);
default:
-21
View File
@@ -54,27 +54,6 @@ namespace Renci.SshNet
return new RsaKey(key);
}
if (algorithmOid.Equals(X9ObjectIdentifiers.IdDsa))
{
var parameters = privateKeyInfo.PrivateKeyAlgorithm.Parameters.GetDerEncoded();
var parametersReader = new AsnReader(parameters, 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(key, AsnEncodingRules.BER);
var x = keyReader.ReadInteger();
keyReader.ThrowIfNotEmpty();
var y = BigInteger.ModPow(g, x, p);
return new DsaKey(p, q, g, y, x);
}
if (algorithmOid.Equals(X9ObjectIdentifiers.IdECPublicKey))
{
var parameters = privateKeyInfo.PrivateKeyAlgorithm.Parameters.GetDerEncoded();
+2 -10
View File
@@ -184,20 +184,12 @@ namespace Renci.SshNet
var prv = privateKeyReader.ReadBignum2();
parsedKey = new EcdsaKey(curve, pub, prv);
break;
case "ssh-dss":
var p = publicKeyReader.ReadBignum();
var q = publicKeyReader.ReadBignum();
var g = publicKeyReader.ReadBignum();
var y = publicKeyReader.ReadBignum();
var x = privateKeyReader.ReadBignum();
parsedKey = new DsaKey(p, q, g, y, x);
break;
case "ssh-rsa":
var exponent = publicKeyReader.ReadBignum(); // e
var modulus = publicKeyReader.ReadBignum(); // n
var d = privateKeyReader.ReadBignum(); // d
p = privateKeyReader.ReadBignum(); // p
q = privateKeyReader.ReadBignum(); // q
var p = privateKeyReader.ReadBignum(); // p
var q = privateKeyReader.ReadBignum(); // q
var inverseQ = privateKeyReader.ReadBignum(); // iqmp
parsedKey = new RsaKey(modulus, exponent, d, p, q, inverseQ);
break;
-15
View File
@@ -83,21 +83,6 @@ namespace Renci.SshNet
var p = reader.ReadBigIntWithBits(); // q
return new RsaKey(modulus, exponent, d, p, q, inverseQ);
}
else if (keyType.Contains("dsa"))
{
var zero = reader.ReadUInt32();
if (zero != 0)
{
throw new SshException("Invalid private key");
}
var p = reader.ReadBigIntWithBits();
var g = reader.ReadBigIntWithBits();
var q = reader.ReadBigIntWithBits();
var y = reader.ReadBigIntWithBits();
var x = reader.ReadBigIntWithBits();
return new DsaKey(p, q, g, y, x);
}
throw new NotSupportedException(string.Format("Key type '{0}' is not supported.", keyType));
}
-4
View File
@@ -381,10 +381,6 @@ namespace Renci.SshNet
_hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(rsaKey, HashAlgorithmName.SHA256)));
#pragma warning restore CA2000 // Dispose objects before losing scope
}
else if (_key is DsaKey)
{
_hostAlgorithms.Add(new KeyHostAlgorithm("ssh-dss", _key));
}
else
{
_hostAlgorithms.Add(new KeyHostAlgorithm(_key.ToString(), _key));
-3
View File
@@ -348,9 +348,6 @@ namespace Renci.SshNet.Security
case "ssh-rsa-cert-v01@openssh.com":
keyData = new SshKeyData("ssh-rsa", LoadPublicKeys(2));
return new RsaKey(keyData);
case "ssh-dss-cert-v01@openssh.com":
keyData = new SshKeyData("ssh-dss", LoadPublicKeys(4));
return new DsaKey(keyData);
case "ecdsa-sha2-nistp256-cert-v01@openssh.com":
case "ecdsa-sha2-nistp384-cert-v01@openssh.com":
case "ecdsa-sha2-nistp521-cert-v01@openssh.com":
@@ -1,86 +0,0 @@
#nullable enable
using System;
using System.Security.Cryptography;
using Renci.SshNet.Common;
namespace Renci.SshNet.Security.Cryptography
{
/// <summary>
/// Implements DSA digital signature algorithm.
/// </summary>
public class DsaDigitalSignature : DigitalSignature, IDisposable
{
private readonly DsaKey _key;
/// <summary>
/// Initializes a new instance of the <see cref="DsaDigitalSignature" /> class.
/// </summary>
/// <param name="key">The DSA key.</param>
/// <exception cref="ArgumentNullException"><paramref name="key"/> is <see langword="null"/>.</exception>
public DsaDigitalSignature(DsaKey key)
{
ThrowHelper.ThrowIfNull(key);
_key = key;
}
/// <inheritdoc/>
public override bool Verify(byte[] input, byte[] signature)
{
#if NETSTANDARD2_1_OR_GREATER || NET
return _key.DSA.VerifyData(input, signature, HashAlgorithmName.SHA1);
#else
// VerifyData does not exist on netstandard2.0.
// It does exist on net462, but in order to keep the path tested,
// use it on netfx as well.
using (var sha1 = SHA1.Create())
{
var hash = sha1.ComputeHash(input);
return _key.DSA.VerifySignature(hash, signature);
}
#endif
}
/// <summary>
/// Creates the signature.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>
/// Signed input data.
/// </returns>
/// <exception cref="SshException">Invalid DSA key.</exception>
public override byte[] Sign(byte[] input)
{
#if NETSTANDARD2_1_OR_GREATER || NET
return _key.DSA.SignData(input, HashAlgorithmName.SHA1);
#else
// SignData does not exist on netstandard2.0.
// It does exist on net462, but in order to keep the path tested,
// use it on netfx as well.
using (var sha1 = SHA1.Create())
{
var hash = sha1.ComputeHash(input);
return _key.DSA.CreateSignature(hash);
}
#endif
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="disposing"><see langword="true"/> to release both managed and unmanaged resources; <see langword="false"/> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
}
}
}
@@ -1,220 +0,0 @@
#nullable enable
using System;
using System.Formats.Asn1;
using System.Numerics;
using System.Security.Cryptography;
using Renci.SshNet.Common;
using Renci.SshNet.Security.Cryptography;
namespace Renci.SshNet.Security
{
/// <summary>
/// Contains DSA private and public key.
/// </summary>
public class DsaKey : Key, IDisposable
{
private DsaDigitalSignature? _digitalSignature;
internal DSA DSA { get; }
/// <summary>
/// Gets the P.
/// </summary>
public BigInteger P { get; }
/// <summary>
/// Gets the Q.
/// </summary>
public BigInteger Q { get; }
/// <summary>
/// Gets the G.
/// </summary>
public BigInteger G { get; }
/// <summary>
/// Gets public key Y.
/// </summary>
public BigInteger Y { get; }
/// <summary>
/// Gets private key X.
/// </summary>
public BigInteger X { get; }
/// <inheritdoc/>
public override int KeyLength
{
get
{
return (int)P.GetBitLength();
}
}
/// <summary>
/// Gets the digital signature.
/// </summary>
protected internal override DigitalSignature DigitalSignature
{
get
{
_digitalSignature ??= new DsaDigitalSignature(this);
return _digitalSignature;
}
}
/// <summary>
/// Gets the DSA public key.
/// </summary>
/// <value>
/// An array whose values are:
/// <list>
/// <item><term>0</term><description><see cref="P"/></description></item>
/// <item><term>1</term><description><see cref="Q"/></description></item>
/// <item><term>2</term><description><see cref="G"/></description></item>
/// <item><term>3</term><description><see cref="Y"/></description></item>
/// </list>
/// </value>
public override BigInteger[] Public
{
get
{
return new[] { P, Q, G, Y };
}
}
/// <summary>
/// Initializes a new instance of the <see cref="DsaKey"/> class.
/// </summary>
/// <param name="publicKeyData">The encoded public key data.</param>
public DsaKey(SshKeyData publicKeyData)
{
ThrowHelper.ThrowIfNull(publicKeyData);
if (publicKeyData.Name != "ssh-dss" || publicKeyData.Keys.Length != 4)
{
throw new ArgumentException($"Invalid DSA public key data. ({publicKeyData.Name}, {publicKeyData.Keys.Length}).", nameof(publicKeyData));
}
P = publicKeyData.Keys[0];
Q = publicKeyData.Keys[1];
G = publicKeyData.Keys[2];
Y = publicKeyData.Keys[3];
DSA = LoadDSA();
}
/// <summary>
/// Initializes a new instance of the <see cref="DsaKey"/> class.
/// </summary>
/// <param name="privateKeyData">DER encoded private key data.</param>
public DsaKey(byte[] privateKeyData)
{
ThrowHelper.ThrowIfNull(privateKeyData);
var keyReader = new AsnReader(privateKeyData, AsnEncodingRules.DER);
var sequenceReader = keyReader.ReadSequence();
keyReader.ThrowIfNotEmpty();
_ = sequenceReader.ReadInteger(); // skip version
P = sequenceReader.ReadInteger();
Q = sequenceReader.ReadInteger();
G = sequenceReader.ReadInteger();
Y = sequenceReader.ReadInteger();
X = sequenceReader.ReadInteger();
sequenceReader.ThrowIfNotEmpty();
DSA = LoadDSA();
}
/// <summary>
/// Initializes a new instance of the <see cref="DsaKey" /> class.
/// </summary>
/// <param name="p">The p.</param>
/// <param name="q">The q.</param>
/// <param name="g">The g.</param>
/// <param name="y">The y.</param>
/// <param name="x">The x.</param>
public DsaKey(BigInteger p, BigInteger q, BigInteger g, BigInteger y, BigInteger x)
{
P = p;
Q = q;
G = g;
Y = y;
X = x;
DSA = LoadDSA();
}
#pragma warning disable CA1859 // Use concrete types when possible for improved performance
#pragma warning disable CA5384 // Do Not Use Digital Signature Algorithm (DSA)
private DSA LoadDSA()
{
#if NETFRAMEWORK
// On .NET Framework we use the concrete CNG type which is FIPS-186-3
// compatible. The CryptoServiceProvider type returned by DSA.Create()
// is limited to FIPS-186-1 (max 1024 bit key).
var dsa = new DSACng();
#else
var dsa = DSA.Create();
#endif
dsa.ImportParameters(GetDSAParameters());
return dsa;
}
#pragma warning restore CA5384 // Do Not Use Digital Signature Algorithm (DSA)
#pragma warning restore CA1859 // Use concrete types when possible for improved performance
internal DSAParameters GetDSAParameters()
{
// P, G, Y, Q are required.
// P, G, Y must have the same length.
// If X is present, it must have the same length as Q.
// See https://github.com/dotnet/runtime/blob/fadd8313653f71abd0068c8bf914be88edb2c8d3/src/libraries/Common/src/System/Security/Cryptography/DSACng.ImportExport.cs#L23
// and https://github.com/dotnet/runtime/blob/fadd8313653f71abd0068c8bf914be88edb2c8d3/src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.cs#L18
// (and similar code in RsaKey.cs)
var ret = new DSAParameters
{
P = P.ToByteArray(isUnsigned: true, isBigEndian: true),
Q = Q.ToByteArray(isUnsigned: true, isBigEndian: true),
};
ret.G = G.ExportKeyParameter(ret.P.Length);
ret.Y = Y.ExportKeyParameter(ret.P.Length);
if (!X.IsZero)
{
ret.X = X.ExportKeyParameter(ret.Q.Length);
}
return ret;
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="disposing"><see langword="true"/> to release both managed and unmanaged resources; <see langword="false"/> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_digitalSignature?.Dispose();
DSA.Dispose();
}
}
}
}
@@ -1,12 +0,0 @@
-----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-----
-9
View File
@@ -1,9 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIBSgIBADCCASsGByqGSM44BAEwggEeAoGBALVl3fae2O4qwsAK95SUShX0KMUN
P+yl/uT3lGH9T/ZptnHSlrTxnTWXCl0g91KEeCaEnDDhLxm4aCv1Ag4B/yvcM4u3
4qkmaNLy2LiAxiqdobZcNG61Pqwqd5IDkp38LBsn8tmb12xu9NalpUfOiSEB1cyC
r4zFZMrm0wtdyJQVAhUArvojZKn/2DgGI2Kx0ghxZlgHxGECgYAOVJ434UAR3Hn6
lA5nWNfFOuUVH3W7nJaP0FQJiIPx7GUbdxO9qtDNTbWkWL3c9qx5+B7Ole4xM7cv
yXPrNQUYDHCFlS+Ue2x3IeJrkdfZkH9ePP25y5A0J4/c+8XXvQaj4zA5nfw13oy5
Ptyd7d3Kq5tEDM8KiVdIhwkXjUA3PQQWAhQYRjs5PgIpnqG/euBPPh7EDZcnXg==
-----END PRIVATE KEY-----
-1
View File
@@ -1 +0,0 @@
ssh-dss AAAAB3NzaC1kc3MAAACBALVl3fae2O4qwsAK95SUShX0KMUNP+yl/uT3lGH9T/ZptnHSlrTxnTWXCl0g91KEeCaEnDDhLxm4aCv1Ag4B/yvcM4u34qkmaNLy2LiAxiqdobZcNG61Pqwqd5IDkp38LBsn8tmb12xu9NalpUfOiSEB1cyCr4zFZMrm0wtdyJQVAAAAFQCu+iNkqf/YOAYjYrHSCHFmWAfEYQAAAIAOVJ434UAR3Hn6lA5nWNfFOuUVH3W7nJaP0FQJiIPx7GUbdxO9qtDNTbWkWL3c9qx5+B7Ole4xM7cvyXPrNQUYDHCFlS+Ue2x3IeJrkdfZkH9ePP25y5A0J4/c+8XXvQaj4zA5nfw13oy5Ptyd7d3Kq5tEDM8KiVdIhwkXjUA3PQAAAIEAm8IGZQatS7M6AfNITNWG4TI7Z2aRQjLb9/MWJIID7c/VQ4zdTZdG3kpk0Gj9n4xreopK5NmYAdj8rtFfPBgmXltsLqt+bBcXkpxW//7WC29WOXW3t90ySTh+cWuWfr9fV7mf4Ql/6u/ZIgpQNvnNYezazt3fK8EXjI1dAXEuQxE=
-12
View File
@@ -1,12 +0,0 @@
-----BEGIN DSA PRIVATE KEY-----
MIIBuwIBAAKBgQC1Zd32ntjuKsLACveUlEoV9CjFDT/spf7k95Rh/U/2abZx0pa0
8Z01lwpdIPdShHgmhJww4S8ZuGgr9QIOAf8r3DOLt+KpJmjS8ti4gMYqnaG2XDRu
tT6sKneSA5Kd/CwbJ/LZm9dsbvTWpaVHzokhAdXMgq+MxWTK5tMLXciUFQIVAK76
I2Sp/9g4BiNisdIIcWZYB8RhAoGADlSeN+FAEdx5+pQOZ1jXxTrlFR91u5yWj9BU
CYiD8exlG3cTvarQzU21pFi93PasefgezpXuMTO3L8lz6zUFGAxwhZUvlHtsdyHi
a5HX2ZB/Xjz9ucuQNCeP3PvF170Go+MwOZ38Nd6MuT7cne3dyqubRAzPColXSIcJ
F41ANz0CgYEAm8IGZQatS7M6AfNITNWG4TI7Z2aRQjLb9/MWJIID7c/VQ4zdTZdG
3kpk0Gj9n4xreopK5NmYAdj8rtFfPBgmXltsLqt+bBcXkpxW//7WC29WOXW3t90y
STh+cWuWfr9fV7mf4Ql/6u/ZIgpQNvnNYezazt3fK8EXjI1dAXEuQxECFBhGOzk+
Aimeob964E8+HsQNlyde
-----END DSA PRIVATE KEY-----
@@ -1,22 +0,0 @@
PuTTY-User-Key-File-3: ssh-dss
Encryption: aes256-cbc
Comment: imported-openssh-key
Public-Lines: 10
AAAAB3NzaC1kc3MAAACBALVl3fae2O4qwsAK95SUShX0KMUNP+yl/uT3lGH9T/Zp
tnHSlrTxnTWXCl0g91KEeCaEnDDhLxm4aCv1Ag4B/yvcM4u34qkmaNLy2LiAxiqd
obZcNG61Pqwqd5IDkp38LBsn8tmb12xu9NalpUfOiSEB1cyCr4zFZMrm0wtdyJQV
AAAAFQCu+iNkqf/YOAYjYrHSCHFmWAfEYQAAAIAOVJ434UAR3Hn6lA5nWNfFOuUV
H3W7nJaP0FQJiIPx7GUbdxO9qtDNTbWkWL3c9qx5+B7Ole4xM7cvyXPrNQUYDHCF
lS+Ue2x3IeJrkdfZkH9ePP25y5A0J4/c+8XXvQaj4zA5nfw13oy5Ptyd7d3Kq5tE
DM8KiVdIhwkXjUA3PQAAAIEAm8IGZQatS7M6AfNITNWG4TI7Z2aRQjLb9/MWJIID
7c/VQ4zdTZdG3kpk0Gj9n4xreopK5NmYAdj8rtFfPBgmXltsLqt+bBcXkpxW//7W
C29WOXW3t90ySTh+cWuWfr9fV7mf4Ql/6u/ZIgpQNvnNYezazt3fK8EXjI1dAXEu
QxE=
Key-Derivation: Argon2id
Argon2-Memory: 8192
Argon2-Passes: 8
Argon2-Parallelism: 1
Argon2-Salt: 310d916da49faba22ba8d2745777e5c5
Private-Lines: 1
xMm0Tg+o7Yq6lAs6L33y2fy3fiDPl6p71iKxm8OAgj4=
Private-MAC: fc2aef48bf90b80b97d06c32c37491db614331c2551ab37865d8719ee6cb5f4f
-17
View File
@@ -1,17 +0,0 @@
PuTTY-User-Key-File-3: ssh-dss
Encryption: none
Comment: imported-openssh-key
Public-Lines: 10
AAAAB3NzaC1kc3MAAACBALVl3fae2O4qwsAK95SUShX0KMUNP+yl/uT3lGH9T/Zp
tnHSlrTxnTWXCl0g91KEeCaEnDDhLxm4aCv1Ag4B/yvcM4u34qkmaNLy2LiAxiqd
obZcNG61Pqwqd5IDkp38LBsn8tmb12xu9NalpUfOiSEB1cyCr4zFZMrm0wtdyJQV
AAAAFQCu+iNkqf/YOAYjYrHSCHFmWAfEYQAAAIAOVJ434UAR3Hn6lA5nWNfFOuUV
H3W7nJaP0FQJiIPx7GUbdxO9qtDNTbWkWL3c9qx5+B7Ole4xM7cvyXPrNQUYDHCF
lS+Ue2x3IeJrkdfZkH9ePP25y5A0J4/c+8XXvQaj4zA5nfw13oy5Ptyd7d3Kq5tE
DM8KiVdIhwkXjUA3PQAAAIEAm8IGZQatS7M6AfNITNWG4TI7Z2aRQjLb9/MWJIID
7c/VQ4zdTZdG3kpk0Gj9n4xreopK5NmYAdj8rtFfPBgmXltsLqt+bBcXkpxW//7W
C29WOXW3t90ySTh+cWuWfr9fV7mf4Ql/6u/ZIgpQNvnNYezazt3fK8EXjI1dAXEu
QxE=
Private-Lines: 1
AAAAFBhGOzk+Aimeob964E8+HsQNlyde
Private-MAC: 6c517ac5ede72c006b0115dd9d0830c8e699a1f4d72c708d41f68b6263d974ae
@@ -1 +0,0 @@
ssh-dss AAAAB3NzaC1kc3MAAACBAI8gyHFchkVhkPiwkhkjFDqN6w2nFWTqVy9sLjFs38oEWLMpAw9+c132erUptAhNQ6JZUAVZGllv/3V5hksSDyChe9WY5IfsOlh6X0dcZCwBKysEzQlPyMFqAtbc9uv7oUWNzBfvEbtV6WN/VmcmXf7dyo3EBVXbBFdPl1NKC7W9AAAAFQDY1+bTt7s2iNmYoBE4C9hdWRCyeQAAAIAEtj09ugx/Tdl6bo7X6mX17hcgVgIxcYj5VNONg2k6IHmRFriLviYaS68mIB4SG3jmvvxbXAGqR1bWBUrv90n0wpxxcuuNoCFylJQyuqUkzSsUHb0WMcncZ/tBQt+NJnRB1Zp9sw8n20ocpg3WVPdaXTtc4pk83NYB6ywG6UFPvgAAAIAX+De5dwo33LMl9W8IvA4dY8Q1wshdycAGJzhy+qYF9dCcwD1Pg+4EbPjYPmzJopsVrK97v9QhxyYcXMr/iHhngGwd9nYNzzSKx665vkSjzyeJWpeQ+fvNV3CLItP01ypbUreM+s+Vz1wor5joLKcDS4X0oQ0RIVZNEHnekuLuFg==
@@ -1,12 +0,0 @@
---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----
P2/56wAAAgoAAAAmZGwtbW9kcHtzaWdue2RzYS1uaXN0LXNoYTF9LGRoe3BsYWlufX0AAA
AIM2Rlcy1jYmMAAAHIxrKV3QJkISlRHox4JYLlWJG0ccdEfMmDF3IXW+up6nUQZeWyOS9/
csXyclUtJ/adA0qkpH5hcaIIOr1jQgvPxjMy7o3I5WJ/MvKB7omSDYG82wKZAaZQeSCaqY
Cn1DYHz6Xou5BIle37f0y71tq3d7YFCh33BjbCM8KHsar3TgRf3oegaawZyZuLnnZRy0L+
xdsdqgntc4fyhpmCmfwIYhWwD2R9P56FXTw59VuE0r/LxxLJW8Cq2R8i7bN0lb2ezb3qnU
SykSJ5PYvoW6e7HIZ3GEr9d+wDhqp0SKWHl+shed3e5xi1NF7fRR23bZ1xlAk3FdrBrH1b
aWYW4JFzdVc33Pg5oHLe+q5NQ3vQpMxXlN2IG9cdAigWKNJMdvLuxiYi+6lzNIGAH+yb01
56ksXYgUs65Gqnj0GMYVmf//8NN0gRKXl5dT57LyuU42jRePwANMyO/n9QOi9OKeea8Tku
f6ZMRiHQLDiZx2ShEXEhHRwmv42jt2xjuHNMbY0dZTKZEkFMUGVFVbkl5MEmN8Fj59rHJn
0adWRPLH5smwM8WXbaYt+E0r628UNZbedXCcjZ5c5egpxCBxRrSJqnK1f0l899fulB
---- END SSH2 ENCRYPTED PRIVATE KEY ----
-1
View File
@@ -1 +0,0 @@
ssh-dss AAAAB3NzaC1kc3MAAACBAOCSGuOxxY/DQBowG7fkS30AJmwN4fDPXToyTaAaxwpOWnGJXFhgP4Il+GSKlpaxnUWkajKpMc1b1hhawPWN4sxoT8QRb6SAW30ErnT/pUtsxqoFlkFla4xvWSgNAuHAVkUBrgPsJ4sHehSbNFn3I6q8Rgle2jyHDHTOqPj2KEXhAAAAFQC740YkVJdVpTJRTxd9Myi0Nx3t4wAAAIArvP7AGh5jY+zxeQRb52zxcUamRBkVYL/ferdJNi9hoM8ZaO4++Xgs8wMbpmoEch9DsXdtufjqXWpk7ywlPjcdhhsb3MxJAeEeFtTRsu2/IUTKqKPHIOgoiPzs8q69AxWhV10aDDUdYWLkqPV/tMGl6S/jC7vTJLmhZum4BUv8MQAAAIEAt19oHPIPyv/8mbMaYpu8I6kvj1/97Ejw0neN7Cd9cGZLqIPBwTyUHEQvKSAm4BvNP0Le3JDn3RFayhRmf+8RrAmS4d1MjrCOs6fmeyLnk2kTpRPFZ2x0H1udIRAhzRehyfj6OsAHn7Jclr+mqDhoq7nIfC3tSgWxFH5g948+7ks= imported-openssh-key
-13
View File
@@ -1,13 +0,0 @@
---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----
Comment: "imported-openssh-key"
P2/56wAAAgIAAAAmZGwtbW9kcHtzaWdue2RzYS1uaXN0LXNoYTF9LGRoe3BsYWlufX0AAA
AEbm9uZQAAAcQAAAHAAAAAAAAABADgkhrjscWPw0AaMBu35Et9ACZsDeHwz106Mk2gGscK
TlpxiVxYYD+CJfhkipaWsZ1FpGoyqTHNW9YYWsD1jeLMaE/EEW+kgFt9BK50/6VLbMaqBZ
ZBZWuMb1koDQLhwFZFAa4D7CeLB3oUmzRZ9yOqvEYJXto8hwx0zqj49ihF4QAAA/4rvP7A
Gh5jY+zxeQRb52zxcUamRBkVYL/ferdJNi9hoM8ZaO4++Xgs8wMbpmoEch9DsXdtufjqXW
pk7ywlPjcdhhsb3MxJAeEeFtTRsu2/IUTKqKPHIOgoiPzs8q69AxWhV10aDDUdYWLkqPV/
tMGl6S/jC7vTJLmhZum4BUv8MQAAAKC740YkVJdVpTJRTxd9Myi0Nx3t4wAABAC3X2gc8g
/K//yZsxpim7wjqS+PX/3sSPDSd43sJ31wZkuog8HBPJQcRC8pICbgG80/Qt7ckOfdEVrK
FGZ/7xGsCZLh3UyOsI6zp+Z7IueTaROlE8VnbHQfW50hECHNF6HJ+Po6wAefslyWv6aoOG
iruch8Le1KBbEUfmD3jz7uSwAAAJ9mUEtdk3zSMZJ1umUnNSo5zC+UxA==
---- END SSH2 ENCRYPTED PRIVATE KEY ----
@@ -24,12 +24,6 @@ namespace Renci.SshNet.IntegrationTests
_remoteSshdConfig?.Reset();
}
[TestMethod]
public void SshDss()
{
DoTest(HostKeyAlgorithm.SshDss, HostKeyFile.Dsa);
}
[TestMethod]
public void SshRsa()
{
@@ -22,12 +22,6 @@ namespace Renci.SshNet.IntegrationTests
_remoteSshdConfig?.Reset();
}
[TestMethod]
public void SshDss()
{
DoTest(PublicKeyAlgorithm.SshDss, "Data.Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt", "12345");
}
[TestMethod]
public void SshRsa()
{
@@ -311,9 +311,6 @@ namespace Renci.SshNet.Tests.Classes
}
[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))]
@@ -348,8 +345,6 @@ namespace Renci.SshNet.Tests.Classes
[DataRow("Key.PuTTY2.Ed25519.ppk", null, typeof(ED25519Key))]
[DataRow("Key.PuTTY2.RSA.Encrypted.12345.ppk", "12345", typeof(RsaKey))]
[DataRow("Key.PuTTY2.RSA.ppk", null, typeof(RsaKey))]
[DataRow("Key.PuTTY3.DSA.Encrypted.Argon2id.12345.ppk", "12345", typeof(DsaKey))]
[DataRow("Key.PuTTY3.DSA.ppk", null, typeof(DsaKey))]
[DataRow("Key.PuTTY3.ECDSA.Encrypted.Argon2id.12345.ppk", "12345", typeof(EcdsaKey))]
[DataRow("Key.PuTTY3.ECDSA.ppk", null, typeof(EcdsaKey))]
[DataRow("Key.PuTTY3.Ed25519.Encrypted.Argon2i.12345.ppk", "12345", typeof(ED25519Key))]
@@ -366,8 +361,6 @@ namespace Renci.SshNet.Tests.Classes
[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))]
[DataRow("Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt", "12345", typeof(RsaKey))]
[DataRow("Key.SSH2.RSA.txt", null, typeof(RsaKey))]
public void Test_PrivateKey(string name, string passPhrase, Type expectedKeyType)
@@ -121,7 +121,7 @@ namespace Renci.SshNet.Tests.Classes
var host = _random.Next().ToString();
var port = _random.Next(1, 100);
var userName = _random.Next().ToString();
var privateKeys = new[] { GetRsaKey(), GetDsaKey() };
var privateKeys = new[] { GetRsaKey(), GetEcdsaKey() };
var client = new ScpClient(host, port, userName, privateKeys);
Assert.AreEqual(16 * 1024U, client.BufferSize);
@@ -154,7 +154,7 @@ namespace Renci.SshNet.Tests.Classes
{
var host = _random.Next().ToString();
var userName = _random.Next().ToString();
var privateKeys = new[] { GetRsaKey(), GetDsaKey() };
var privateKeys = new[] { GetRsaKey(), GetEcdsaKey() };
var client = new ScpClient(host, userName, privateKeys);
Assert.AreEqual(16 * 1024U, client.BufferSize);
@@ -222,9 +222,9 @@ namespace Renci.SshNet.Tests.Classes
}
}
private PrivateKeyFile GetDsaKey()
private PrivateKeyFile GetEcdsaKey()
{
using (var stream = GetData("Key.SSH2.DSA.txt"))
using (var stream = GetData("Key.ECDSA.txt"))
{
return new PrivateKeyFile(stream);
}
@@ -1,59 +0,0 @@
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Renci.SshNet.Abstractions;
#if !NET6_0_OR_GREATER
using Renci.SshNet.Common;
#endif
using Renci.SshNet.Security;
using Renci.SshNet.Security.Cryptography;
using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes.Security.Cryptography
{
[TestClass]
public class DsaDigitalSignatureTest : TestBase
{
[TestMethod]
public void Verify()
{
byte[] data = Encoding.UTF8.GetBytes("Hello, World!");
DsaKey dsaKey = GetDsaKey("Key.DSA.txt");
Assert.AreEqual(1024, dsaKey.P.GetBitLength());
Assert.AreEqual(160, dsaKey.Q.GetBitLength());
var digitalSignature = new DsaDigitalSignature(dsaKey);
byte[] signedBytes = digitalSignature.Sign(data);
// We can't compare signatures for value equality because they have a source of randomness
Assert.AreEqual(40, signedBytes.Length);
Assert.IsTrue(digitalSignature.Verify(data, signedBytes));
byte[] signatureToVerify = new byte[]
{
// Generated with a previous DsaDigitalSignature implementation in order to confirm consistent
// behaviour. We can't seem to validate against openssl because openssl outputs a DER signature,
// where as we want IEEE P1363 (fixed size) format.
0x07, 0x4c, 0x5e, 0x15, 0x53, 0x36, 0x21, 0xbe, 0x5a, 0x82, 0x35, 0xd5, 0xb6, 0xe6, 0x7d, 0x2f,
0x01, 0x2a, 0x78, 0x9b, 0x16, 0x4a, 0xe5, 0x8d, 0x85, 0xa6, 0x34, 0x56, 0x9d, 0x38, 0xd6, 0x1a,
0xa4, 0xa1, 0x5b, 0x98, 0x7d, 0xd5, 0x35, 0x40
};
Assert.IsTrue(digitalSignature.Verify(data, signatureToVerify));
Assert.IsFalse(digitalSignature.Verify(data, CryptoAbstraction.GenerateRandom(40)));
}
private static DsaKey GetDsaKey(string fileName, string passPhrase = null)
{
using (var stream = GetData(fileName))
{
return (DsaKey)new PrivateKeyFile(stream, passPhrase).Key;
}
}
}
}
@@ -1,205 +0,0 @@
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
#if !NET6_0_OR_GREATER
using Renci.SshNet.Common;
#endif
using Renci.SshNet.Security;
using Renci.SshNet.Tests.Common;
namespace Renci.SshNet.Tests.Classes.Security.Cryptography
{
[TestClass]
public class DsaKeyTest : TestBase
{
private static DsaKey GetDsaKey(string fileName, string passPhrase = null)
{
using (var stream = GetData(fileName))
{
return (DsaKey)new PrivateKeyFile(stream, passPhrase).Key;
}
}
// This is just to line up any differences in the assertion message.
private static void AssertEqual(byte[] actualBytes, string expectedHex)
{
#if NET
string actualHex = Convert.ToHexString(actualBytes);
#else
string actualHex = BitConverter.ToString(actualBytes).Replace("-", "");
#endif
Assert.AreEqual(expectedHex, actualHex,
$"{Environment.NewLine}Expected: {expectedHex}{Environment.NewLine} Actual: {actualHex}");
}
// These tests generated by converting the keys to PKCS8, importing them to BCL DSA,
// and printing out the expected DSAParameter values.
// Some useful commands:
// Generate a new params file with specific parameters:
// openssl genpkey -genparam -algorithm dsa -pkeyopt pbits:1024 -pkeyopt qbits:160 -out dsa.1024.params
// Generate PKCS8 key file from the params:
// openssl genpkey -paramfile dsa.1024.params -out dsa.1024.txt
// Convert to PKCS1:
// openssl pkcs8 -in dsa.1024.txt -nocrypt -traditional -out dsa.1024.pkcs1.txt
// Convert PKCS1 to ssh.com:
// puttygen dsa.1024.pkcs1.txt -O private-sshcom -o dsa.1024.ssh2.txt
// Convert to PKCS8:
// openssl pkcs8 -topk8 -nocrypt -in Key.DSA.txt -out Key.DSA.PKCS8.txt
/*
using IndentedTextWriter tw = new(Console.Out);
foreach (string filePath in Directory.EnumerateFiles(dir, "*.DSA.*txt"))
{
string pkFile = Path.GetFileNameWithoutExtension(filePath);
tw.WriteLine("[TestMethod]");
tw.WriteLine($"public void {pkFile.Replace('.', '_')}()");
tw.WriteLine("{");
tw.Indent++;
tw.WriteLine($"DsaKey dsaKey = GetDsaKey(\"{pkFile}.txt\");");
tw.WriteLine();
tw.WriteLine("DSAParameters p = dsaKey.GetDSAParameters();");
tw.WriteLine();
using DSA dsa = DSA.Create();
dsa.ImportFromPem(File.ReadAllText(filePath));
DSAParameters p = dsa.ExportParameters(true);
WriteParamAssert(p.P);
WriteParamAssert(p.G);
WriteParamAssert(p.Y);
WriteParamAssert(p.Q);
WriteParamAssert(p.X);
tw.Indent--;
tw.WriteLine("}");
tw.WriteLine();
}
void WriteParamAssert(byte[] bytes, [CallerArgumentExpression(nameof(bytes))] string name = null)
{
tw.WriteLine($"AssertEqual({name}, \"{Convert.ToHexString(bytes)}\");");
}
*/
[TestMethod]
public void Key_DSA()
{
DsaKey dsaKey = GetDsaKey("Key.DSA.txt");
Assert.AreEqual(1024, dsaKey.P.GetBitLength());
Assert.AreEqual(160, dsaKey.Q.GetBitLength());
DSAParameters p = dsaKey.GetDSAParameters();
AssertEqual(p.P, "B565DDF69ED8EE2AC2C00AF794944A15F428C50D3FECA5FEE4F79461FD4FF669B671D296B4F19D35970A5D20F752847826849C30E12F19B8682BF5020E01FF2BDC338BB7E2A92668D2F2D8B880C62A9DA1B65C346EB53EAC2A779203929DFC2C1B27F2D99BD76C6EF4D6A5A547CE892101D5CC82AF8CC564CAE6D30B5DC89415");
AssertEqual(p.G, "0E549E37E14011DC79FA940E6758D7C53AE5151F75BB9C968FD054098883F1EC651B7713BDAAD0CD4DB5A458BDDCF6AC79F81ECE95EE3133B72FC973EB3505180C7085952F947B6C7721E26B91D7D9907F5E3CFDB9CB9034278FDCFBC5D7BD06A3E330399DFC35DE8CB93EDC9DEDDDCAAB9B440CCF0A8957488709178D40373D");
AssertEqual(p.Y, "9BC2066506AD4BB33A01F3484CD586E1323B6766914232DBF7F316248203EDCFD5438CDD4D9746DE4A64D068FD9F8C6B7A8A4AE4D99801D8FCAED15F3C18265E5B6C2EAB7E6C1717929C56FFFED60B6F563975B7B7DD3249387E716B967EBF5F57B99FE1097FEAEFD9220A5036F9CD61ECDACEDDDF2BC1178C8D5D01712E4311");
AssertEqual(p.Q, "AEFA2364A9FFD838062362B1D20871665807C461");
AssertEqual(p.X, "18463B393E02299EA1BF7AE04F3E1EC40D97275E");
}
[TestMethod]
public void Key_SSH2_DSA_Encrypted_Des_CBC_12345()
{
DsaKey dsaKey = GetDsaKey("Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt", "12345");
Assert.AreEqual(1024, dsaKey.P.GetBitLength());
Assert.AreEqual(160, dsaKey.Q.GetBitLength());
DSAParameters p = dsaKey.GetDSAParameters();
AssertEqual(p.P, "8F20C8715C86456190F8B0921923143A8DEB0DA71564EA572F6C2E316CDFCA0458B329030F7E735DF67AB529B4084D43A2595005591A596FFF7579864B120F20A17BD598E487EC3A587A5F475C642C012B2B04CD094FC8C16A02D6DCF6EBFBA1458DCC17EF11BB55E9637F5667265DFEDDCA8DC40555DB04574F97534A0BB5BD");
AssertEqual(p.G, "04B63D3DBA0C7F4DD97A6E8ED7EA65F5EE17205602317188F954D38D83693A20799116B88BBE261A4BAF26201E121B78E6BEFC5B5C01AA4756D6054AEFF749F4C29C7172EB8DA02172949432BAA524CD2B141DBD1631C9DC67FB4142DF8D267441D59A7DB30F27DB4A1CA60DD654F75A5D3B5CE2993CDCD601EB2C06E9414FBE");
AssertEqual(p.Y, "17F837B9770A37DCB325F56F08BC0E1D63C435C2C85DC9C006273872FAA605F5D09CC03D4F83EE046CF8D83E6CC9A29B15ACAF7BBFD421C7261C5CCAFF887867806C1DF6760DCF348AC7AEB9BE44A3CF27895A9790F9FBCD57708B22D3F4D72A5B52B78CFACF95CF5C28AF98E82CA7034B85F4A10D1121564D1079DE92E2EE16");
AssertEqual(p.Q, "D8D7E6D3B7BB3688D998A011380BD85D5910B279");
AssertEqual(p.X, "23FA5A574AF1197B185B88008A7A7527899FD092");
}
[TestMethod]
public void Key_SSH2_DSA()
{
DsaKey dsaKey = GetDsaKey("Key.SSH2.DSA.txt");
Assert.AreEqual(1024, dsaKey.P.GetBitLength());
Assert.AreEqual(160, dsaKey.Q.GetBitLength());
DSAParameters p = dsaKey.GetDSAParameters();
AssertEqual(p.P, "E0921AE3B1C58FC3401A301BB7E44B7D00266C0DE1F0CF5D3A324DA01AC70A4E5A71895C58603F8225F8648A9696B19D45A46A32A931CD5BD6185AC0F58DE2CC684FC4116FA4805B7D04AE74FFA54B6CC6AA059641656B8C6F59280D02E1C0564501AE03EC278B077A149B3459F723AABC46095EDA3C870C74CEA8F8F62845E1");
AssertEqual(p.G, "2BBCFEC01A1E6363ECF179045BE76CF17146A644191560BFDF7AB749362F61A0CF1968EE3EF9782CF3031BA66A04721F43B1776DB9F8EA5D6A64EF2C253E371D861B1BDCCC4901E11E16D4D1B2EDBF2144CAA8A3C720E82888FCECF2AEBD0315A1575D1A0C351D6162E4A8F57FB4C1A5E92FE30BBBD324B9A166E9B8054BFC31");
AssertEqual(p.Y, "B75F681CF20FCAFFFC99B31A629BBC23A92F8F5FFDEC48F0D2778DEC277D70664BA883C1C13C941C442F292026E01BCD3F42DEDC90E7DD115ACA14667FEF11AC0992E1DD4C8EB08EB3A7E67B22E7936913A513C5676C741F5B9D211021CD17A1C9F8FA3AC0079FB25C96BFA6A83868ABB9C87C2DED4A05B1147E60F78F3EEE4B");
AssertEqual(p.Q, "BBE34624549755A532514F177D3328B4371DEDE3");
AssertEqual(p.X, "66504B5D937CD2319275BA6527352A39CC2F94C4");
}
[TestMethod]
public void Key_DSA_3072_256()
{
// Not supported by OpenSSH but easy enough to test here.
var keyString = """
-----BEGIN DSA PRIVATE KEY-----
MIIE1gIBAAKCAYEA6Rb9Cogx64CZcrnP35Nr8W9sjcUqoCpSfZrJdvIhTxgyAkEl
d9U868azCTZ1QGvUuPOCGB5Ll8nRQ6QSK9bicSQ3q3C69BcjzTfZcFuZEi533wEl
9m9xZTbMAW8643jgARKszoNWIeTGsk2JcXQ2c6+VfPOml6F7yMv3KDIpqjUQlpK+
RoZn5Eg5R2+2VqcNwwqbP8dyQGnGmgX2hlzbWx9Cld8NTG2b0B6Taaea4zqiMLHC
MeOUh+3WkbGM+aVQ7kthQbkhTEMmZeB/zyJrlEQGmKJl/cuvx69iO8nPSIZJDSEp
sZwg6p+Fqlm0+IyaFaxJMF+SuQirYLR+ee5oor5lcWS3Szaaikz0u1ONO3ndWAmO
eEHq7BL4vuHc/SDxfO5RouhEirCUFtGwtYq/Kf7x53ccd0Jmlj1FalubKHaiyYSg
baHrvN8rFv12XDMI0vPDeOxLVaxaB3zSJTz/ZwDjUcFx7PbuWsvOoSZeagd0sCm9
aVNQoe7dy/5YCrM7AiEA1oznSuokVWnPt9GaBlmggzk9lMjZ/XVr9MFuDzWDycsC
ggGAYVSdm43WuonZQ40M9An5oBZuWsv22ZNXFnMXzcrKkvdslWGP+za/Ipa+tm+j
YE82vuqCdGjDuDJViJbrx2FProe4J/to2Gpd0jc0uV2c1PFO0B1hDk7tkglQyhmV
q9GAQatA4XUM5cIiInseF5JxHMmfgwEKmfIUDotWnpFQImMvehHxZfI29ngrB2ND
Ba4wBIj1Ua4UqsQi2beNfope7+XSsBQm98prswjvdR6n6wg9Xkvtn4ti3lLbEHzO
ZlwnxoRxFlNE/s2RaygGySRRYAe9TPriGWeMpWirYF3/SDAQyt5qDJsPQU0fWAuF
WsuxDlOsaLmJNJNnvySwx5Qmiw4e17U+6/IKptVbOHWowq05PxZKSVYmcP5+Jbt2
eVzozKPNGkEw6aBy18l4t+ehx7fiUha7uCPaZ+VTPodLRZE6sKT1uiKOBtPqhrsp
bxKJ3zzmF1KZpoOG++1JHzqOPL+Npokd+K3ce9vNfU7eWTYP2DuiooyF9EktJt7w
AVilAoIBgBCpFSwJxhdAIQRefnQmweW+eXRbx8KL+8t53YsPS/fQhdzIEVEi5LWz
cJ0iAU2l2Mj43AC/6yehA8KF6vJEy4LWSXNwoGVqEoSA2LxBaomLxLARqlFyfCZN
yBlUVfXDiqFw2ajRaLQKUIxWbfC6ard69brWZuS61YQd8Jrk782VAa+sQO6Ca6Ii
vtyyRjNKxbeYwKLkZydi9JFdYYR6kmVG1ge7spemMHlozza6VvNcDU3hE4T4PwbY
Ns555ihK79EWGO2zCNjhPEIN34IjN2WjbUidCBWPGgXLhw9BYyEEREhfP1QUTe2q
S3gup/j8//v46O+OZFcB6g/MZB2IFpRRSw16qM2+pNZFKVTvXs/dUq5tEXylbMCg
+7jS5eLVAkDYFwSUai4Ht9VOHGASz7VyfPfngL8nx+KLNyegB12OLwr6ho5tc9dE
Rib63kEJnsK6CzIjg1+iFblWy4pQsHnKEgvBWxk4+sLyEZFTtjCe7KjigdH6WRDH
U5ejA3bnFQIhAIkT3ff8AjkByyJg1CRkpwDCvFag1fbPXEdg1Ru1E+l/
-----END DSA PRIVATE KEY-----
""";
using MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(keyString));
DsaKey dsaKey = (DsaKey)new PrivateKeyFile(stream).Key;
Assert.AreEqual(3072, dsaKey.P.GetBitLength());
Assert.AreEqual(256, dsaKey.Q.GetBitLength());
DSAParameters p = dsaKey.GetDSAParameters();
AssertEqual(p.P, "E916FD0A8831EB809972B9CFDF936BF16F6C8DC52AA02A527D9AC976F2214F183202412577D53CEBC6B3093675406BD4B8F382181E4B97C9D143A4122BD6E2712437AB70BAF41723CD37D9705B99122E77DF0125F66F716536CC016F3AE378E00112ACCE835621E4C6B24D8971743673AF957CF3A697A17BC8CBF7283229AA35109692BE468667E44839476FB656A70DC30A9B3FC7724069C69A05F6865CDB5B1F4295DF0D4C6D9BD01E9369A79AE33AA230B1C231E39487EDD691B18CF9A550EE4B6141B9214C432665E07FCF226B94440698A265FDCBAFC7AF623BC9CF4886490D2129B19C20EA9F85AA59B4F88C9A15AC49305F92B908AB60B47E79EE68A2BE657164B74B369A8A4CF4BB538D3B79DD58098E7841EAEC12F8BEE1DCFD20F17CEE51A2E8448AB09416D1B0B58ABF29FEF1E7771C774266963D456A5B9B2876A2C984A06DA1EBBCDF2B16FD765C3308D2F3C378EC4B55AC5A077CD2253CFF6700E351C171ECF6EE5ACBCEA1265E6A0774B029BD695350A1EEDDCBFE580AB33B");
AssertEqual(p.G, "61549D9B8DD6BA89D9438D0CF409F9A0166E5ACBF6D99357167317CDCACA92F76C95618FFB36BF2296BEB66FA3604F36BEEA827468C3B832558896EBC7614FAE87B827FB68D86A5DD23734B95D9CD4F14ED01D610E4EED920950CA1995ABD18041AB40E1750CE5C222227B1E1792711CC99F83010A99F2140E8B569E915022632F7A11F165F236F6782B07634305AE300488F551AE14AAC422D9B78D7E8A5EEFE5D2B01426F7CA6BB308EF751EA7EB083D5E4BED9F8B62DE52DB107CCE665C27C68471165344FECD916B2806C924516007BD4CFAE219678CA568AB605DFF483010CADE6A0C9B0F414D1F580B855ACBB10E53AC68B989349367BF24B0C794268B0E1ED7B53EEBF20AA6D55B3875A8C2AD393F164A49562670FE7E25BB76795CE8CCA3CD1A4130E9A072D7C978B7E7A1C7B7E25216BBB823DA67E5533E874B45913AB0A4F5BA228E06D3EA86BB296F1289DF3CE6175299A68386FBED491F3A8E3CBF8DA6891DF8ADDC7BDBCD7D4EDE59360FD83BA2A28C85F4492D26DEF00158A5");
AssertEqual(p.Y, "10A9152C09C6174021045E7E7426C1E5BE79745BC7C28BFBCB79DD8B0F4BF7D085DCC8115122E4B5B3709D22014DA5D8C8F8DC00BFEB27A103C285EAF244CB82D6497370A0656A128480D8BC416A898BC4B011AA51727C264DC8195455F5C38AA170D9A8D168B40A508C566DF0BA6AB77AF5BAD666E4BAD5841DF09AE4EFCD9501AFAC40EE826BA222BEDCB246334AC5B798C0A2E4672762F4915D61847A926546D607BBB297A6307968CF36BA56F35C0D4DE11384F83F06D836CE79E6284AEFD11618EDB308D8E13C420DDF82233765A36D489D08158F1A05CB870F4163210444485F3F54144DEDAA4B782EA7F8FCFFFBF8E8EF8E645701EA0FCC641D881694514B0D7AA8CDBEA4D6452954EF5ECFDD52AE6D117CA56CC0A0FBB8D2E5E2D50240D81704946A2E07B7D54E1C6012CFB5727CF7E780BF27C7E28B3727A0075D8E2F0AFA868E6D73D7444626FADE41099EC2BA0B3223835FA215B956CB8A50B079CA120BC15B1938FAC2F2119153B6309EECA8E281D1FA5910C75397A30376E715");
AssertEqual(p.Q, "D68CE74AEA245569CFB7D19A0659A083393D94C8D9FD756BF4C16E0F3583C9CB");
AssertEqual(p.X, "8913DDF7FC023901CB2260D42464A700C2BC56A0D5F6CF5C4760D51BB513E97F");
}
}
}