Skip to content

Commit b5e1f43

Browse files
committed
WIP: ED25519 Keys
Exploring what needs to be done to make it Work. 1st Step Parse OPENSSH Key Format
1 parent 0a084a8 commit b5e1f43

File tree

8 files changed

+186
-0
lines changed

8 files changed

+186
-0
lines changed

src/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,9 @@
701701
<Compile Include="..\Renci.SshNet\Security\Cryptography\EcdsaKey.cs">
702702
<Link>Security\Cryptography\EcdsaKey.cs</Link>
703703
</Compile>
704+
<Compile Include="..\Renci.SshNet\Security\Cryptography\OpenSSHKey.cs">
705+
<Link>Security\Cryptography\OpenSSHKey.cs</Link>
706+
</Compile>
704707
<Compile Include="..\Renci.SshNet\Security\Cryptography\RsaDigitalSignature.cs">
705708
<Link>Security\Cryptography\RsaDigitalSignature.cs</Link>
706709
</Compile>

src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,28 @@ public void Test_PrivateKey_ECDSA521_Encrypted()
385385
}
386386
}
387387

388+
[TestMethod]
389+
[Owner("darinkes")]
390+
[TestCategory("PrivateKey")]
391+
public void Test_PrivateKey_ED25519()
392+
{
393+
using (var stream = GetData("Key.ED25519.txt"))
394+
{
395+
new PrivateKeyFile(stream, "12345");
396+
}
397+
}
398+
399+
[TestMethod]
400+
[Owner("darinkes")]
401+
[TestCategory("PrivateKey")]
402+
public void Test_PrivateKey_ED25519_Encrypted()
403+
{
404+
using (var stream = GetData("Key.ED25519.Encrypted.txt"))
405+
{
406+
new PrivateKeyFile(stream, "12345");
407+
}
408+
}
409+
388410
/// <summary>
389411
///A test for Dispose
390412
///</summary>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-----BEGIN OPENSSH PRIVATE KEY-----
2+
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCziVlGog
3+
eUxEUKJcduOqCCAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIBZfAisK02MKZeSy
4+
MGo9lxq7Otgg1ll2Qhp+ySacRk2CAAAAoDc5MjTED1jcIotaaqc6DcnADwVnPf/4iC9BM2
5+
+2C+6uKXuYGOuqb16kFHn8yYAkABX2mtQo1GmJt5lPriMkJ1qNfZ6gg1jgXVrFru8zHSfY
6+
Gr9tniFSkdnrP/XHaEkQwEPptUlRF1eG+3hOO1D1vW0SliXBfg1DWd/Yew55kljzmtgxsg
7+
J2dfTYZF5L6xblNjM6mr5NItdhUsVB4XsYWo4=
8+
-----END OPENSSH PRIVATE KEY-----
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-----BEGIN OPENSSH PRIVATE KEY-----
2+
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
3+
QyNTUxOQAAACCCsGI6AEHghOMbGIhtsRX59CjoqwkCgDMLgOqGByvrPAAAAKDryTjh68k4
4+
4QAAAAtzc2gtZWQyNTUxOQAAACCCsGI6AEHghOMbGIhtsRX59CjoqwkCgDMLgOqGByvrPA
5+
AAAECcZJX7mXgmBR60wXj51bhpkw21jDt95z4VBbXHEjbgMYKwYjoAQeCE4xsYiG2xFfn0
6+
KOirCQKAMwuA6oYHK+s8AAAAFnNyaW5rZXNAV0lOREVWLVNSSU5LRVMBAgMEBQYH
7+
-----END OPENSSH PRIVATE KEY-----

src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,12 @@
717717
<EmbeddedResource Include="Data\Key.ECDSA384.Encrypted.txt" />
718718
<EmbeddedResource Include="Data\Key.ECDSA521.Encrypted.txt" />
719719
</ItemGroup>
720+
<ItemGroup>
721+
<EmbeddedResource Include="Data\Key.ED25519.txt" />
722+
</ItemGroup>
723+
<ItemGroup>
724+
<EmbeddedResource Include="Data\Key.ED25519.Encrypted.txt" />
725+
</ItemGroup>
720726
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
721727
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
722728
Other similar extension points exist, see Microsoft.Common.targets.

src/Renci.SshNet/PrivateKeyFile.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,10 @@ private void Open(Stream privateKey, string passPhrase)
203203
HostKey = new KeyHostAlgorithm(_key.ToString(), _key);
204204
break;
205205
#endif
206+
case "OPENSSH":
207+
_key = new OpenSSHKey(decryptedData);
208+
HostKey = new KeyHostAlgorithm(_key.ToString(), _key);
209+
break;
206210
case "SSH2 ENCRYPTED":
207211
var reader = new SshDataReader(decryptedData);
208212
var magicNumber = reader.ReadUInt32();

src/Renci.SshNet/Renci.SshNet.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@
170170
<Compile Include="RemotePathTransformation.cs" />
171171
<Compile Include="Security\Cryptography\EcdsaDigitalSignature.cs" />
172172
<Compile Include="Security\Cryptography\EcdsaKey.cs" />
173+
<Compile Include="Security\Cryptography\OpenSSHKey.cs" />
173174
<Compile Include="Security\Cryptography\HMACMD5.cs" />
174175
<Compile Include="Security\Cryptography\HMACSHA1.cs" />
175176
<Compile Include="Security\Cryptography\HMACSHA256.cs" />
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
using System;
2+
using System.IO;
3+
using System.Text;
4+
using Renci.SshNet.Common;
5+
using Renci.SshNet.Security.Cryptography;
6+
7+
namespace Renci.SshNet.Security
8+
{
9+
/// <summary>
10+
/// Contains OpenSSH private and public key
11+
/// </summary>
12+
public class OpenSSHKey : Key, IDisposable
13+
{
14+
/// <summary>
15+
/// Gets the Key String.
16+
/// </summary>
17+
public override string ToString()
18+
{
19+
// ToDo: return extraced Key String
20+
return base.ToString();
21+
}
22+
23+
/// <summary>
24+
/// Gets the length of the key.
25+
/// </summary>
26+
/// <value>
27+
/// The length of the key.
28+
/// </value>
29+
public override int KeyLength
30+
{
31+
get
32+
{
33+
// ToDo: actual KeySize;
34+
return 0;
35+
}
36+
}
37+
38+
/// <summary>
39+
/// Gets the digital signature.
40+
/// </summary>
41+
protected override DigitalSignature DigitalSignature
42+
{
43+
get
44+
{
45+
throw new NotImplementedException();
46+
}
47+
}
48+
49+
/// <summary>
50+
/// Gets or sets the public.
51+
/// </summary>
52+
/// <value>
53+
/// The public.
54+
/// </value>
55+
public override BigInteger[] Public
56+
{
57+
get
58+
{
59+
throw new NotImplementedException();
60+
}
61+
set
62+
{
63+
throw new NotImplementedException();
64+
}
65+
}
66+
67+
const string AUTH_MAGIC = "openssh-key-v1";
68+
69+
/// <summary>
70+
/// Initializes a new instance of the <see cref="OpenSSHKey"/> class.
71+
/// </summary>
72+
public OpenSSHKey()
73+
{
74+
}
75+
76+
/// <summary>
77+
/// Initializes a new instance of the <see cref="OpenSSHKey"/> class.
78+
/// </summary>
79+
/// <param name="data">DER encoded private key data.</param>
80+
public OpenSSHKey(byte[] data)
81+
{
82+
//throw new SshException("Unsupported Format: " + BitConverter.ToString(data));
83+
84+
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key
85+
using (var br = new BinaryReader(new MemoryStream(data), Encoding.ASCII))
86+
{
87+
var magic = Encoding.ASCII.GetString(br.ReadBytes(AUTH_MAGIC.Length));
88+
if (magic != AUTH_MAGIC)
89+
throw new SshException("Unsupported Format: " + magic);
90+
br.ReadByte(); // AUTH_MAGIC is 0 terminated string
91+
Console.WriteLine("Len: " + BitConverter.ToString(br.ReadBytes(4)));
92+
Console.WriteLine("String: " + Encoding.ASCII.GetString(br.ReadBytes(4)));
93+
}
94+
}
95+
96+
#region IDisposable Members
97+
98+
private bool _isDisposed;
99+
100+
/// <summary>
101+
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
102+
/// </summary>
103+
public void Dispose()
104+
{
105+
Dispose(true);
106+
GC.SuppressFinalize(this);
107+
}
108+
109+
/// <summary>
110+
/// Releases unmanaged and - optionally - managed resources
111+
/// </summary>
112+
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
113+
protected virtual void Dispose(bool disposing)
114+
{
115+
if (_isDisposed)
116+
return;
117+
118+
if (disposing)
119+
{
120+
_isDisposed = true;
121+
}
122+
}
123+
124+
/// <summary>
125+
/// Releases unmanaged resources and performs other cleanup operations before the
126+
/// <see cref="DsaKey"/> is reclaimed by garbage collection.
127+
/// </summary>
128+
~OpenSSHKey()
129+
{
130+
Dispose(false);
131+
}
132+
133+
#endregion
134+
}
135+
}

0 commit comments

Comments
 (0)