From c735f9431cd2399465f5328aafc51f5c5ed44676 Mon Sep 17 00:00:00 2001 From: Stefan Rinkes Date: Mon, 26 Nov 2018 20:15:25 +0100 Subject: [PATCH] Add Support for ECDSA Host- and Private-Keys Also known as: - ecdsa-sha2-nistp256 - ecdsa-sha2-nistp384 - ecdsa-sha2-nistp521 Basically it translate between SSH-Data and Microsoft Crypto API. --- .../Renci.SshNet.NET35.csproj | 10 +- .../Renci.SshNet.Tests.NET35.csproj | 20 + .../Classes/PrivateKeyFileTest.cs | 66 ++++ .../Data/Key.ECDSA.Encrypted.txt | 8 + src/Renci.SshNet.Tests/Data/Key.ECDSA.txt | 5 + .../Data/Key.ECDSA384.Encrypted.txt | 9 + src/Renci.SshNet.Tests/Data/Key.ECDSA384.txt | 6 + .../Data/Key.ECDSA521.Encrypted.txt | 10 + src/Renci.SshNet.Tests/Data/Key.ECDSA521.txt | 7 + .../Renci.SshNet.Tests.csproj | 8 + src/Renci.SshNet/Common/DerData.cs | 85 ++++- src/Renci.SshNet/Common/Extensions.cs | 9 + src/Renci.SshNet/ConnectionInfo.cs | 6 +- src/Renci.SshNet/PrivateKeyFile.cs | 10 +- src/Renci.SshNet/Renci.SshNet.csproj | 6 +- .../Cryptography/EcdsaDigitalSignature.cs | 176 +++++++++ .../Security/Cryptography/EcdsaKey.cs | 360 ++++++++++++++++++ 17 files changed, 786 insertions(+), 15 deletions(-) create mode 100644 src/Renci.SshNet.Tests/Data/Key.ECDSA.Encrypted.txt create mode 100644 src/Renci.SshNet.Tests/Data/Key.ECDSA.txt create mode 100644 src/Renci.SshNet.Tests/Data/Key.ECDSA384.Encrypted.txt create mode 100644 src/Renci.SshNet.Tests/Data/Key.ECDSA384.txt create mode 100644 src/Renci.SshNet.Tests/Data/Key.ECDSA521.Encrypted.txt create mode 100644 src/Renci.SshNet.Tests/Data/Key.ECDSA521.txt create mode 100644 src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs create mode 100644 src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs diff --git a/src/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj b/src/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj index a6878d187..64ee419f3 100644 --- a/src/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj +++ b/src/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj @@ -18,7 +18,7 @@ full false bin\Debug\ - TRACE;DEBUG;FEATURE_REGEX_COMPILE;FEATURE_BINARY_SERIALIZATION;FEATURE_RNG_CREATE;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_POLL;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_ENCODING_ASCII + TRACE;DEBUG;FEATURE_REGEX_COMPILE;FEATURE_BINARY_SERIALIZATION;FEATURE_RNG_CREATE;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_POLL;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_ENCODING_ASCII;FEATURE_ECDSA prompt 4 true @@ -29,7 +29,7 @@ none true bin\Release\ - TRACE;FEATURE_REGEX_COMPILE;FEATURE_BINARY_SERIALIZATION;FEATURE_RNG_CREATE;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_POLL;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_ENCODING_ASCII + TRACE;FEATURE_REGEX_COMPILE;FEATURE_BINARY_SERIALIZATION;FEATURE_RNG_CREATE;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_POLL;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_ENCODING_ASCII;FEATURE_ECDSA prompt 4 bin\Release\Renci.SshNet.xml @@ -695,6 +695,12 @@ Security\Cryptography\Key.cs + + Security\Cryptography\EcdsaDigitalSignature.cs + + + Security\Cryptography\EcdsaKey.cs + Security\Cryptography\RsaDigitalSignature.cs diff --git a/src/Renci.SshNet.Tests.NET35/Renci.SshNet.Tests.NET35.csproj b/src/Renci.SshNet.Tests.NET35/Renci.SshNet.Tests.NET35.csproj index a42cf8ec1..893a6fe0c 100644 --- a/src/Renci.SshNet.Tests.NET35/Renci.SshNet.Tests.NET35.csproj +++ b/src/Renci.SshNet.Tests.NET35/Renci.SshNet.Tests.NET35.csproj @@ -1737,6 +1737,26 @@ Data\Key.SSH2.RSA.txt + + + Data\Key.ECDSA.txt + + + Data\Key.ECDSA384.txt + + + Data\Key.ECDSA521.txt + + + Data\Key.ECDSA.Encrypted.txt + + + Data\Key.ECDSA384.Encrypted.txt + + + Data\Key.ECDSA521.Encrypted.txt + + diff --git a/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs b/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs index 21bd97853..3c944c8d4 100644 --- a/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs +++ b/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs @@ -319,6 +319,72 @@ public void Test_PrivateKey_RSA_DES_EDE3_CFB() } } + [TestMethod] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_ECDSA() + { + using (var stream = GetData("Key.ECDSA.txt")) + { + new PrivateKeyFile(stream); + } + } + + [TestMethod] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_ECDSA384() + { + using (var stream = GetData("Key.ECDSA384.txt")) + { + new PrivateKeyFile(stream); + } + } + + [TestMethod] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_ECDSA521() + { + using (var stream = GetData("Key.ECDSA521.txt")) + { + new PrivateKeyFile(stream); + } + } + + [TestMethod] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_ECDSA_Encrypted() + { + using (var stream = GetData("Key.ECDSA.Encrypted.txt")) + { + new PrivateKeyFile(stream, "12345"); + } + } + + [TestMethod] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_ECDSA384_Encrypted() + { + using (var stream = GetData("Key.ECDSA384.Encrypted.txt")) + { + new PrivateKeyFile(stream, "12345"); + } + } + + [TestMethod] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_ECDSA521_Encrypted() + { + using (var stream = GetData("Key.ECDSA521.Encrypted.txt")) + { + new PrivateKeyFile(stream, "12345"); + } + } + /// ///A test for Dispose /// diff --git a/src/Renci.SshNet.Tests/Data/Key.ECDSA.Encrypted.txt b/src/Renci.SshNet.Tests/Data/Key.ECDSA.Encrypted.txt new file mode 100644 index 000000000..f0af5ba7d --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.ECDSA.Encrypted.txt @@ -0,0 +1,8 @@ +-----BEGIN EC PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,54D46F498C989115AAE14FEA21E3AF11 + +IQdFnndcbzz10d7YQIgEE1TzuzJrm7uYJr4Hvdfz/FshVxMRqxqaqtEgo2vAHHik +BOcPkm+84ERlTNPslcJqLSkKzCdxb7Rz5hfwHuN3Y6Lf01qGakDlzAUEjEyDor+4 +zQtAne+f+gRUJnBvLLoVhH4xdeQFC55GECNUFQpEmos= +-----END EC PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Data/Key.ECDSA.txt b/src/Renci.SshNet.Tests/Data/Key.ECDSA.txt new file mode 100644 index 000000000..13ac9fb49 --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.ECDSA.txt @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIEdqaFKgJBIibVjyUh1v7Y35LwIQJrocdTaYFLwl7iB0oAoGCCqGSM49 +AwEHoUQDQgAEQD5MO/n9yqSDTszwzVpApLx5SQFecE5ZfDkgxqVdHQecm1BAPozZ +4eKGNhKn72hT79mLlp9HXX+oNEcuVT83Hw== +-----END EC PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Data/Key.ECDSA384.Encrypted.txt b/src/Renci.SshNet.Tests/Data/Key.ECDSA384.Encrypted.txt new file mode 100644 index 000000000..00072ce24 --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.ECDSA384.Encrypted.txt @@ -0,0 +1,9 @@ +-----BEGIN EC PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,1D64653C5E18C2AACB0B17E3FE43C219 + +lCtRmcvKSeIACwqTtsf/ei1brtCZ386rsk/j7bSXdkZBpvzcmzbeo6w6CYm206Km +hV9TMl2dIO/I1/ov5/2VIR3ZkaElyDOJD/+Be0e3aus4EZj1H1YM/Dv+4QJId+is +Cw4ycWjfudYPPejGdiyjzt5qjaIJwrrEvGtMg7sWVAqDpjcAjS9KuaCu5nOgdItL +s7oHuz+DTGdJQNfUHAlUnz1JaMRWzpP0MwtxdcaRY+w= +-----END EC PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Data/Key.ECDSA384.txt b/src/Renci.SshNet.Tests/Data/Key.ECDSA384.txt new file mode 100644 index 000000000..f2d658ea4 --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.ECDSA384.txt @@ -0,0 +1,6 @@ +-----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDCQawHdHLR7NvKa2vPV0sVkbzOE8c0enp95iEysGcGV66RXE1EH//nh +gu5UzeTR4KigBwYFK4EEACKhZANiAAQUk4rVvoOPI1hQzWpNx09Uo6qG+srGcbvB +q15eFK0GnK/T0UBKxdbZ2+//KAYI6SeDHM9t3ORF1aX5EpjTEBI4d7ZY/lV9jX6M +nJ4XuGteJselM2iMmy+p9ZYw83BYB1Y= +-----END EC PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Data/Key.ECDSA521.Encrypted.txt b/src/Renci.SshNet.Tests/Data/Key.ECDSA521.Encrypted.txt new file mode 100644 index 000000000..381b30be8 --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.ECDSA521.Encrypted.txt @@ -0,0 +1,10 @@ +-----BEGIN EC PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,F995028237EBD79C928530CC6C3E957F + +wT+iajbte4MnpCipVy/7W9t2I8OgwbMjNBw9PB5xmXR1NQX+yWa81DXMTgjHi8++ +6tp+Vlftkr7mY1yvZCVo1Sy4VgcvZeMhtpVKtvYdMCmHJC6gaDOTYX3yee8DJ4FL +fG+IQz0wFyZZ26NFrHiwbufW9z6pXhGNCQZK0KLbFxI9iKwVA0llc7uzTEcmBBpn +0/Snp0CVvX+i6AP9Xj0bBdrFCsvcoT+ZHzS8YWJUfu3m6cpAJksCAy0PXR3ifvus +edTfDpkMxd4/b+DtPB6SMekIAjnQyzbyaTwJCujm8iU= +-----END EC PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Data/Key.ECDSA521.txt b/src/Renci.SshNet.Tests/Data/Key.ECDSA521.txt new file mode 100644 index 000000000..31abe917a --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.ECDSA521.txt @@ -0,0 +1,7 @@ +-----BEGIN EC PRIVATE KEY----- +MIHcAgEBBEIBn2DAme7AU8sCA+/sd6s3c2FNW26IiPvulGd3FC8k5q+fjBZ5LUWR +iJMGrsf2rJLO8hXMGJYoF9tjZEGaabQ8KVagBwYFK4EEACOhgYkDgYYABABrpVjs +ANqcvqMUo1wo0I1uVCXQ6xrauy4iU86FiOwFmkYRrle4w3oYdRJwniC3TwGMuBuM +PMIoCTXr0UtUzn1vkQESNR/J/jAxVseLlVe+KDfZHKvsvk2+O4XaSa1qMfLwN3sp +wlj08+ylKjlO6V3g0hbz4ZaSVwuiRS7Xsv8W2MV6rg== +-----END EC PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj index d968dd27b..6f64c0048 100644 --- a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj +++ b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj @@ -709,6 +709,14 @@ Renci.SshNet + + + + + + + +