mirror of
https://github.com/sshnet/SSH.NET.git
synced 2026-09-10 09:15:47 +00:00
Repalce PrivateKey and Signature classes with CryptoKey classes
This commit is contained in:
@@ -14,13 +14,15 @@ namespace Renci.SshClient
|
||||
private Regex _headerLineContinue = new Regex(@"(?<headerValue>[^:]+(?<continue>\\)?)");
|
||||
private Regex _endKeyLine = new Regex(@"----[ ]*END (?<keyName>.+) PRIVATE KEY[ ]*----");
|
||||
|
||||
private PrivateKey _key;
|
||||
//private PrivateKey _key;
|
||||
private CryptoPrivateKey _key;
|
||||
|
||||
public string AlgorithmName
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._key.AlgorithmName;
|
||||
return this._key.Name;
|
||||
//return this._key.AlgorithmName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +30,8 @@ namespace Renci.SshClient
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._key.PublicKey;
|
||||
return this._key.GetPublicKey().GetBytes();
|
||||
//return this._key.PublicKey;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,15 +122,19 @@ namespace Renci.SshClient
|
||||
switch (keyName)
|
||||
{
|
||||
case "RSA":
|
||||
this._key = new PrivateKeyRsa(System.Convert.FromBase64String(data.ToString()));
|
||||
//this._key = new PrivateKeyRsa(System.Convert.FromBase64String(data.ToString()));
|
||||
this._key = new CryptoPrivateKeyRsa();
|
||||
|
||||
break;
|
||||
case "DSA":
|
||||
this._key = new PrivateKeyDsa(System.Convert.FromBase64String(data.ToString()));
|
||||
//this._key = new PrivateKeyDsa(System.Convert.FromBase64String(data.ToString()));
|
||||
this._key = new CryptoPrivateKeyDss();
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(string.Format("Key '{0}' is not supported.", keyName));
|
||||
}
|
||||
|
||||
this._key.Load(System.Convert.FromBase64String(data.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -106,17 +106,18 @@
|
||||
<Compile Include="Messages\Sftp\StatusMessage.cs" />
|
||||
<Compile Include="Messages\Sftp\VersionMessage.cs" />
|
||||
<Compile Include="Messages\Sftp\WriteMessage.cs" />
|
||||
<Compile Include="Security\PrivateKey.cs" />
|
||||
<Compile Include="Security\CryptoKey.cs" />
|
||||
<Compile Include="Security\CryptoPrivateKey.cs" />
|
||||
<Compile Include="Security\CryptoPrivateKeyDss.cs" />
|
||||
<Compile Include="Security\CryptoPrivateKeyRsa.cs" />
|
||||
<Compile Include="Security\CryptoPublicKey.cs" />
|
||||
<Compile Include="Security\CryptoPublicKeyDss.cs" />
|
||||
<Compile Include="Security\CryptoPublicKeyRsa.cs" />
|
||||
<Compile Include="Security\KeyExchange.cs" />
|
||||
<Compile Include="Security\KeyExchangeCompletedEventArgs.cs" />
|
||||
<Compile Include="Security\KeyExchangeDiffieHellman.cs" />
|
||||
<Compile Include="Security\KeyExchangeFailedEventArgs.cs" />
|
||||
<Compile Include="Security\KeyExchangeSendMessageEventArgs.cs" />
|
||||
<Compile Include="Security\PrivateKeyDsa.cs" />
|
||||
<Compile Include="Security\PrivateKeyRsa.cs" />
|
||||
<Compile Include="Security\Signature.cs" />
|
||||
<Compile Include="Security\SignatureDss.cs" />
|
||||
<Compile Include="Security\SignatureRsa.cs" />
|
||||
<Compile Include="KeyFile.cs" />
|
||||
<Compile Include="Messages\Connection\ChannelMessage.cs" />
|
||||
<Compile Include="Messages\Connection\RequestNames.cs" />
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Renci.SshClient.Security
|
||||
{
|
||||
public abstract class CryptoKey
|
||||
{
|
||||
public abstract string Name { get; }
|
||||
|
||||
public abstract void Load(IEnumerable<byte> data);
|
||||
|
||||
public abstract bool VerifySignature(IEnumerable<byte> hash, IEnumerable<byte> signature);
|
||||
|
||||
public abstract IEnumerable<byte> GetBytes();
|
||||
}
|
||||
}
|
||||
+3
-13
@@ -3,20 +3,11 @@ using Renci.SshClient.Common;
|
||||
|
||||
namespace Renci.SshClient.Security
|
||||
{
|
||||
internal abstract class PrivateKey
|
||||
public abstract class CryptoPrivateKey : CryptoKey
|
||||
{
|
||||
public abstract string AlgorithmName { get; }
|
||||
public abstract CryptoPublicKey GetPublicKey();
|
||||
|
||||
protected IEnumerable<byte> Data { get; private set; }
|
||||
|
||||
public abstract IEnumerable<byte> PublicKey { get; }
|
||||
|
||||
public PrivateKey(IEnumerable<byte> data)
|
||||
{
|
||||
this.Data = data;
|
||||
}
|
||||
|
||||
public abstract IEnumerable<byte> GetSignature(IEnumerable<byte> sessionId);
|
||||
public abstract IEnumerable<byte> GetSignature(IEnumerable<byte> key);
|
||||
|
||||
protected class SignatureKeyData : SshData
|
||||
{
|
||||
@@ -34,6 +25,5 @@ namespace Renci.SshClient.Security
|
||||
this.Write(this.Signature.GetSshString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Renci.SshClient.Security
|
||||
{
|
||||
public class CryptoPrivateKeyDss : CryptoPrivateKey
|
||||
{
|
||||
private byte[] _p;
|
||||
private byte[] _q;
|
||||
private byte[] _g;
|
||||
private byte[] _x;
|
||||
private byte[] _publicKey;
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return "ssh-dss"; }
|
||||
}
|
||||
|
||||
public override void Load(IEnumerable<byte> data)
|
||||
{
|
||||
using (var ms = new MemoryStream(data.ToArray()))
|
||||
using (var binr = new BinaryReader(ms)) //wrap Memory Stream with BinaryReader for easy reading
|
||||
{
|
||||
byte bt = 0;
|
||||
ushort twobytes = 0;
|
||||
int elems = 0;
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
|
||||
binr.ReadByte(); //advance 1 byte
|
||||
else if (twobytes == 0x8230)
|
||||
binr.ReadInt16(); //advance 2 bytes
|
||||
else
|
||||
throw new InvalidOperationException("Not valid DSS Key.");
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes != 0x0102) //version number
|
||||
throw new NotSupportedException("Not supported DSS Key version.");
|
||||
bt = binr.ReadByte();
|
||||
if (bt != 0x00)
|
||||
throw new InvalidOperationException("Not valid DSS Key.");
|
||||
|
||||
//------ all private key components are Integer sequences ----
|
||||
elems = CryptoPrivateKeyDss.GetIntegerSize(binr);
|
||||
this._p = binr.ReadBytes(elems);
|
||||
|
||||
elems = CryptoPrivateKeyDss.GetIntegerSize(binr);
|
||||
this._q = binr.ReadBytes(elems);
|
||||
|
||||
elems = CryptoPrivateKeyDss.GetIntegerSize(binr);
|
||||
this._g = binr.ReadBytes(elems);
|
||||
|
||||
elems = CryptoPrivateKeyDss.GetIntegerSize(binr);
|
||||
this._publicKey = binr.ReadBytes(elems);
|
||||
|
||||
elems = CryptoPrivateKeyDss.GetIntegerSize(binr);
|
||||
this._x = binr.ReadBytes(elems);
|
||||
}
|
||||
}
|
||||
|
||||
public override CryptoPublicKey GetPublicKey()
|
||||
{
|
||||
return new CryptoPublicKeyDss();
|
||||
}
|
||||
|
||||
public override IEnumerable<byte> GetSignature(IEnumerable<byte> key)
|
||||
{
|
||||
var data = key.ToArray();
|
||||
using (var sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider())
|
||||
using (var cs = new System.Security.Cryptography.CryptoStream(System.IO.Stream.Null, sha1, System.Security.Cryptography.CryptoStreamMode.Write))
|
||||
{
|
||||
DSAParameters DSAKeyInfo = new DSAParameters();
|
||||
|
||||
DSAKeyInfo.X = this._x.TrimLeadinZero().ToArray();
|
||||
DSAKeyInfo.P = this._p.TrimLeadinZero().ToArray();
|
||||
DSAKeyInfo.Q = this._q.TrimLeadinZero().ToArray();
|
||||
DSAKeyInfo.G = this._g.TrimLeadinZero().ToArray();
|
||||
|
||||
cs.Write(data, 0, data.Length);
|
||||
|
||||
cs.Close();
|
||||
|
||||
var DSA = new System.Security.Cryptography.DSACryptoServiceProvider();
|
||||
DSA.ImportParameters(DSAKeyInfo);
|
||||
var DSAFormatter = new RSAPKCS1SignatureFormatter(DSA);
|
||||
DSAFormatter.SetHashAlgorithm("SHA1");
|
||||
|
||||
var signature = DSAFormatter.CreateSignature(sha1);
|
||||
|
||||
return new SignatureKeyData
|
||||
{
|
||||
AlgorithmName = this.Name,
|
||||
Signature = signature,
|
||||
}.GetBytes();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool VerifySignature(IEnumerable<byte> hash, IEnumerable<byte> signature)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override IEnumerable<byte> GetBytes()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private static int GetIntegerSize(BinaryReader binr)
|
||||
{
|
||||
byte bt = 0;
|
||||
byte lowbyte = 0x00;
|
||||
byte highbyte = 0x00;
|
||||
int count = 0;
|
||||
bt = binr.ReadByte();
|
||||
if (bt != 0x02) //expect integer
|
||||
return 0;
|
||||
bt = binr.ReadByte();
|
||||
|
||||
if (bt == 0x81)
|
||||
count = binr.ReadByte(); // data size in next byte
|
||||
else
|
||||
if (bt == 0x82)
|
||||
{
|
||||
highbyte = binr.ReadByte(); // data size in next 2 bytes
|
||||
lowbyte = binr.ReadByte();
|
||||
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
|
||||
count = BitConverter.ToInt32(modint, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
count = bt; // we already have the data size
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+68
-107
@@ -3,74 +3,99 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using Renci.SshClient.Common;
|
||||
|
||||
namespace Renci.SshClient.Security
|
||||
{
|
||||
internal class PrivateKeyRsa : PrivateKey
|
||||
public class CryptoPrivateKeyRsa : CryptoPrivateKey
|
||||
{
|
||||
private byte[] _modulus;
|
||||
private byte[] _eValue;
|
||||
private byte[] _exponent;
|
||||
private byte[] _dValue;
|
||||
private byte[] _pValue;
|
||||
private byte[] _qValue;
|
||||
private byte[] _dpValue;
|
||||
private byte[] _dqValue;
|
||||
private byte[] _iqValue;
|
||||
private byte[] _inverseQ;
|
||||
|
||||
private IEnumerable<byte> _publicKey;
|
||||
/// <summary>
|
||||
/// Gets the public key.
|
||||
/// </summary>
|
||||
/// <value>The public key.</value>
|
||||
public override IEnumerable<byte> PublicKey
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._publicKey == null)
|
||||
{
|
||||
this._publicKey = new RsaPublicKeyData
|
||||
{
|
||||
E = this._eValue,
|
||||
Modulus = this._modulus,
|
||||
}.GetBytes();
|
||||
|
||||
}
|
||||
return this._publicKey;
|
||||
}
|
||||
}
|
||||
|
||||
public override string AlgorithmName
|
||||
public override string Name
|
||||
{
|
||||
get { return "ssh-rsa"; }
|
||||
}
|
||||
|
||||
|
||||
public PrivateKeyRsa(IEnumerable<byte> data)
|
||||
: base(data)
|
||||
public override void Load(IEnumerable<byte> data)
|
||||
{
|
||||
if (!this.ParseRSAPrivateKey())
|
||||
// --------- Set up stream to decode the asn.1 encoded RSA private key ------
|
||||
using (var ms = new MemoryStream(data.ToArray()))
|
||||
using (var binr = new BinaryReader(ms)) //wrap Memory Stream with BinaryReader for easy reading
|
||||
{
|
||||
throw new InvalidDataException("RSA Key is not valid");
|
||||
byte bt = 0;
|
||||
ushort twobytes = 0;
|
||||
int elems = 0;
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
|
||||
binr.ReadByte(); //advance 1 byte
|
||||
else if (twobytes == 0x8230)
|
||||
binr.ReadInt16(); //advance 2 bytes
|
||||
else
|
||||
throw new InvalidOperationException("Not valid RSA Key.");
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes != 0x0102) //version number
|
||||
throw new NotSupportedException("Not supported RSA Key version.");
|
||||
bt = binr.ReadByte();
|
||||
if (bt != 0x00)
|
||||
throw new InvalidOperationException("Not valid RSA Key.");
|
||||
|
||||
|
||||
//------ all private key components are Integer sequences ----
|
||||
elems = CryptoPrivateKeyRsa.GetIntegerSize(binr);
|
||||
this._modulus = binr.ReadBytes(elems);
|
||||
|
||||
elems = CryptoPrivateKeyRsa.GetIntegerSize(binr);
|
||||
this._exponent = binr.ReadBytes(elems);
|
||||
|
||||
elems = CryptoPrivateKeyRsa.GetIntegerSize(binr);
|
||||
this._dValue = binr.ReadBytes(elems);
|
||||
|
||||
elems = CryptoPrivateKeyRsa.GetIntegerSize(binr);
|
||||
this._pValue = binr.ReadBytes(elems);
|
||||
|
||||
elems = CryptoPrivateKeyRsa.GetIntegerSize(binr);
|
||||
this._qValue = binr.ReadBytes(elems);
|
||||
|
||||
elems = CryptoPrivateKeyRsa.GetIntegerSize(binr);
|
||||
this._dpValue = binr.ReadBytes(elems);
|
||||
|
||||
elems = CryptoPrivateKeyRsa.GetIntegerSize(binr);
|
||||
this._dqValue = binr.ReadBytes(elems);
|
||||
|
||||
elems = CryptoPrivateKeyRsa.GetIntegerSize(binr);
|
||||
this._inverseQ = binr.ReadBytes(elems);
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<byte> GetSignature(IEnumerable<byte> sessionId)
|
||||
public override CryptoPublicKey GetPublicKey()
|
||||
{
|
||||
var data = sessionId.ToArray();
|
||||
return new CryptoPublicKeyRsa(this._modulus, this._exponent);
|
||||
}
|
||||
|
||||
public override IEnumerable<byte> GetSignature(IEnumerable<byte> key)
|
||||
{
|
||||
var data = key.ToArray();
|
||||
using (var sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider())
|
||||
using (var cs = new System.Security.Cryptography.CryptoStream(System.IO.Stream.Null, sha1, System.Security.Cryptography.CryptoStreamMode.Write))
|
||||
{
|
||||
RSAParameters RSAKeyInfo = new RSAParameters();
|
||||
|
||||
RSAKeyInfo.Exponent = _eValue.TrimLeadinZero().ToArray();
|
||||
RSAKeyInfo.Exponent = _exponent.TrimLeadinZero().ToArray();
|
||||
RSAKeyInfo.D = _dValue.TrimLeadinZero().ToArray();
|
||||
RSAKeyInfo.Modulus = _modulus.TrimLeadinZero().ToArray();
|
||||
RSAKeyInfo.P = _pValue.TrimLeadinZero().ToArray();
|
||||
RSAKeyInfo.Q = _qValue.TrimLeadinZero().ToArray();
|
||||
RSAKeyInfo.DP = _dpValue.TrimLeadinZero().ToArray();
|
||||
RSAKeyInfo.DQ = _dqValue.TrimLeadinZero().ToArray();
|
||||
RSAKeyInfo.InverseQ = _iqValue.TrimLeadinZero().ToArray();
|
||||
RSAKeyInfo.InverseQ = _inverseQ.TrimLeadinZero().ToArray();
|
||||
|
||||
cs.Write(data, 0, data.Length);
|
||||
|
||||
@@ -85,66 +110,20 @@ namespace Renci.SshClient.Security
|
||||
|
||||
return new SignatureKeyData
|
||||
{
|
||||
AlgorithmName = this.AlgorithmName,
|
||||
AlgorithmName = this.Name,
|
||||
Signature = signature,
|
||||
}.GetBytes();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private bool ParseRSAPrivateKey()
|
||||
public override bool VerifySignature(IEnumerable<byte> hash, IEnumerable<byte> signature)
|
||||
{
|
||||
// --------- Set up stream to decode the asn.1 encoded RSA private key ------
|
||||
using (var ms = new MemoryStream(this.Data.ToArray()))
|
||||
using (var binr = new BinaryReader(ms)) //wrap Memory Stream with BinaryReader for easy reading
|
||||
{
|
||||
byte bt = 0;
|
||||
ushort twobytes = 0;
|
||||
int elems = 0;
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
|
||||
binr.ReadByte(); //advance 1 byte
|
||||
else if (twobytes == 0x8230)
|
||||
binr.ReadInt16(); //advance 2 bytes
|
||||
else
|
||||
return false;
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes != 0x0102) //version number
|
||||
return false;
|
||||
bt = binr.ReadByte();
|
||||
if (bt != 0x00)
|
||||
return false;
|
||||
|
||||
|
||||
//------ all private key components are Integer sequences ----
|
||||
elems = GetIntegerSize(binr);
|
||||
this._modulus = binr.ReadBytes(elems);
|
||||
|
||||
elems = GetIntegerSize(binr);
|
||||
this._eValue = binr.ReadBytes(elems);
|
||||
|
||||
elems = GetIntegerSize(binr);
|
||||
this._dValue = binr.ReadBytes(elems);
|
||||
|
||||
elems = GetIntegerSize(binr);
|
||||
this._pValue = binr.ReadBytes(elems);
|
||||
|
||||
elems = GetIntegerSize(binr);
|
||||
this._qValue = binr.ReadBytes(elems);
|
||||
|
||||
elems = GetIntegerSize(binr);
|
||||
this._dpValue = binr.ReadBytes(elems);
|
||||
|
||||
elems = GetIntegerSize(binr);
|
||||
this._dqValue = binr.ReadBytes(elems);
|
||||
|
||||
elems = GetIntegerSize(binr);
|
||||
this._iqValue = binr.ReadBytes(elems);
|
||||
|
||||
return true;
|
||||
}
|
||||
public override IEnumerable<byte> GetBytes()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private static int GetIntegerSize(BinaryReader binr)
|
||||
@@ -175,23 +154,5 @@ namespace Renci.SshClient.Security
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private class RsaPublicKeyData : SshData
|
||||
{
|
||||
public IEnumerable<byte> Modulus { get; set; }
|
||||
|
||||
public IEnumerable<byte> E { get; set; }
|
||||
|
||||
protected override void LoadData()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SaveData()
|
||||
{
|
||||
this.Write("ssh-rsa");
|
||||
this.Write(this.E.GetSshString());
|
||||
this.Write(this.Modulus.GetSshString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Renci.SshClient.Security
|
||||
{
|
||||
public abstract class CryptoPublicKey : CryptoKey
|
||||
{
|
||||
}
|
||||
}
|
||||
+43
-17
@@ -1,41 +1,62 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Renci.SshClient.Security
|
||||
{
|
||||
internal class SignatureDss : Signature
|
||||
public class CryptoPublicKeyDss : CryptoPublicKey
|
||||
{
|
||||
private IEnumerable<byte> _p;
|
||||
private IEnumerable<byte> _q;
|
||||
private IEnumerable<byte> _g;
|
||||
private IEnumerable<byte> _x;
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return "ssh-dss"; }
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public SignatureDss(IEnumerable<byte> data)
|
||||
: base(data)
|
||||
public CryptoPublicKeyDss()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override bool ValidateSignature(IEnumerable<byte> hash, IEnumerable<byte> signature)
|
||||
public CryptoPublicKeyDss(IEnumerable<byte> p, IEnumerable<byte> q, IEnumerable<byte> g, IEnumerable<byte> x)
|
||||
{
|
||||
var pLength = BitConverter.ToUInt32(this.Data.Take(4).Reverse().ToArray(), 0);
|
||||
this._p = p;
|
||||
this._q = q;
|
||||
this._g = g;
|
||||
this._x = x;
|
||||
}
|
||||
|
||||
var pData = this.Data.Skip(4).Take((int)pLength).ToArray();
|
||||
public override void Load(IEnumerable<byte> data)
|
||||
{
|
||||
using (var ms = new MemoryStream(data.ToArray()))
|
||||
using (var br = new BinaryReader(ms))
|
||||
{
|
||||
|
||||
var qLength = BitConverter.ToUInt32(this.Data.Skip(4 + (int)pLength).Take(4).Reverse().ToArray(), 0);
|
||||
var pl = BitConverter.ToUInt32(br.ReadBytes(4).Reverse().ToArray(), 0);
|
||||
|
||||
var qData = this.Data.Skip(4 + (int)pLength + 4).Take((int)qLength).ToArray();
|
||||
_p = br.ReadBytes((int)pl);
|
||||
|
||||
var gLength = BitConverter.ToUInt32(this.Data.Skip(4 + (int)pLength + 4 + (int)qLength).Take(4).Reverse().ToArray(), 0);
|
||||
var ql = BitConverter.ToUInt32(br.ReadBytes(4).Reverse().ToArray(), 0);
|
||||
|
||||
var gData = this.Data.Skip(4 + (int)pLength + 4 + (int)qLength + 4).Take((int)gLength).ToArray();
|
||||
_q = br.ReadBytes((int)ql);
|
||||
|
||||
var xLength = BitConverter.ToUInt32(this.Data.Skip(4 + (int)pLength + 4 + (int)qLength + 4 + (int)gLength).Take(4).Reverse().ToArray(), 0);
|
||||
var gl = BitConverter.ToUInt32(br.ReadBytes(4).Reverse().ToArray(), 0);
|
||||
|
||||
var xData = this.Data.Skip(4 + (int)pLength + 4 + (int)qLength + 4 + (int)xLength + 4).Take((int)xLength).ToArray();
|
||||
_g = br.ReadBytes((int)gl);
|
||||
|
||||
var xl = BitConverter.ToUInt32(br.ReadBytes(4).Reverse().ToArray(), 0);
|
||||
|
||||
_x = br.ReadBytes((int)xl);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool VerifySignature(IEnumerable<byte> hash, IEnumerable<byte> signature)
|
||||
{
|
||||
using (var sha1 = new SHA1CryptoServiceProvider())
|
||||
{
|
||||
using (var cs = new CryptoStream(System.IO.Stream.Null, sha1, CryptoStreamMode.Write))
|
||||
@@ -49,10 +70,10 @@ namespace Renci.SshClient.Security
|
||||
{
|
||||
dsa.ImportParameters(new DSAParameters
|
||||
{
|
||||
X = xData.TrimLeadinZero().ToArray(),
|
||||
P = pData.TrimLeadinZero().ToArray(),
|
||||
Q = qData.TrimLeadinZero().ToArray(),
|
||||
G = gData.TrimLeadinZero().ToArray(),
|
||||
X = _x.TrimLeadinZero().ToArray(),
|
||||
P = _p.TrimLeadinZero().ToArray(),
|
||||
Q = _q.TrimLeadinZero().ToArray(),
|
||||
G = _g.TrimLeadinZero().ToArray(),
|
||||
});
|
||||
var dsaDeformatter = new DSASignatureDeformatter(dsa);
|
||||
dsaDeformatter.SetHashAlgorithm("SHA1");
|
||||
@@ -87,5 +108,10 @@ namespace Renci.SshClient.Security
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<byte> GetBytes()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
-10
@@ -1,33 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using Renci.SshClient.Common;
|
||||
|
||||
namespace Renci.SshClient.Security
|
||||
{
|
||||
internal class SignatureRsa : Signature
|
||||
public class CryptoPublicKeyRsa : CryptoPublicKey
|
||||
{
|
||||
private IEnumerable<byte> _modulus;
|
||||
private IEnumerable<byte> _exponent;
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return "ssh-rsa"; }
|
||||
}
|
||||
|
||||
public SignatureRsa(IEnumerable<byte> data)
|
||||
: base(data)
|
||||
public CryptoPublicKeyRsa()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override bool ValidateSignature(IEnumerable<byte> hash, IEnumerable<byte> signature)
|
||||
internal CryptoPublicKeyRsa(IEnumerable<byte> modulus, IEnumerable<byte> exponent)
|
||||
{
|
||||
var exponentLength = BitConverter.ToUInt32(this.Data.Take(4).Reverse().ToArray(), 0);
|
||||
this._modulus = modulus;
|
||||
this._exponent = exponent;
|
||||
}
|
||||
|
||||
var exponentData = this.Data.Skip(4).Take((int)exponentLength).ToArray();
|
||||
public override void Load(IEnumerable<byte> data)
|
||||
{
|
||||
using (var ms = new MemoryStream(data.ToArray()))
|
||||
using (var br = new BinaryReader(ms))
|
||||
{
|
||||
|
||||
var modulusLength = BitConverter.ToUInt32(this.Data.Skip(4 + (int)exponentLength).Take(4).Reverse().ToArray(), 0);
|
||||
var el = BitConverter.ToUInt32(br.ReadBytes(4).Reverse().ToArray(), 0);
|
||||
|
||||
var modulusData = this.Data.Skip(4 + (int)exponentLength + 4).Take((int)modulusLength).ToArray();
|
||||
this._exponent = br.ReadBytes((int)el);
|
||||
|
||||
var ml = BitConverter.ToUInt32(br.ReadBytes(4).Reverse().ToArray(), 0);
|
||||
|
||||
this._modulus = br.ReadBytes((int)ml);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool VerifySignature(IEnumerable<byte> hash, IEnumerable<byte> signature)
|
||||
{
|
||||
using (var sha1 = new SHA1CryptoServiceProvider())
|
||||
{
|
||||
using (var cs = new CryptoStream(System.IO.Stream.Null, sha1, CryptoStreamMode.Write))
|
||||
@@ -41,9 +59,10 @@ namespace Renci.SshClient.Security
|
||||
{
|
||||
rsa.ImportParameters(new RSAParameters
|
||||
{
|
||||
Exponent = exponentData,
|
||||
Modulus = modulusData.TrimLeadinZero().ToArray(),
|
||||
Exponent = this._exponent.TrimLeadinZero().ToArray(),
|
||||
Modulus = this._modulus.TrimLeadinZero().ToArray(),
|
||||
});
|
||||
|
||||
var rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
|
||||
rsaDeformatter.SetHashAlgorithm("SHA1");
|
||||
|
||||
@@ -77,5 +96,33 @@ namespace Renci.SshClient.Security
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<byte> GetBytes()
|
||||
{
|
||||
return new RsaPublicKeyData
|
||||
{
|
||||
E = this._exponent,
|
||||
Modulus = this._modulus,
|
||||
}.GetBytes();
|
||||
}
|
||||
|
||||
private class RsaPublicKeyData : SshData
|
||||
{
|
||||
public IEnumerable<byte> Modulus { get; set; }
|
||||
|
||||
public IEnumerable<byte> E { get; set; }
|
||||
|
||||
protected override void LoadData()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SaveData()
|
||||
{
|
||||
this.Write("ssh-rsa");
|
||||
this.Write(this.E.GetSshString());
|
||||
this.Write(this.Modulus.GetSshString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -296,9 +296,11 @@ namespace Renci.SshClient.Security
|
||||
|
||||
var data = bytes.Skip(4 + algorithmName.Length);
|
||||
|
||||
var signature = Settings.HostKeyAlgorithms[algorithmName](data);
|
||||
CryptoPublicKey key = Settings.HostKeyAlgorithms[algorithmName]();
|
||||
|
||||
return signature.ValidateSignature(this.ExchangeHash, this.Signature.GetSshBytes());
|
||||
key.Load(data);
|
||||
|
||||
return key.VerifySignature(this.ExchangeHash, this.Signature.GetSshBytes());
|
||||
}
|
||||
|
||||
protected void SendMessage(Message message)
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using Renci.SshClient.Common;
|
||||
|
||||
namespace Renci.SshClient.Security
|
||||
{
|
||||
internal class PrivateKeyDsa : PrivateKey
|
||||
{
|
||||
private byte[] _pValue;
|
||||
|
||||
private byte[] _qValue;
|
||||
|
||||
private byte[] _gValue;
|
||||
|
||||
private byte[] _publicKeyValue;
|
||||
|
||||
private byte[] _privateKeyValue;
|
||||
|
||||
private IEnumerable<byte> _publicKey;
|
||||
/// <summary>
|
||||
/// Gets the public key.
|
||||
/// </summary>
|
||||
/// <value>The public key.</value>
|
||||
public override IEnumerable<byte> PublicKey
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._publicKey == null)
|
||||
{
|
||||
this._publicKey = new DsaPublicKeyData
|
||||
{
|
||||
P = this._pValue,
|
||||
Q = this._qValue,
|
||||
G = this._gValue,
|
||||
Public = this._publicKeyValue,
|
||||
}.GetBytes();
|
||||
|
||||
}
|
||||
return this._publicKey;
|
||||
}
|
||||
}
|
||||
|
||||
public override string AlgorithmName
|
||||
{
|
||||
get { return "ssh-dss"; }
|
||||
}
|
||||
|
||||
|
||||
public PrivateKeyDsa(IEnumerable<byte> data)
|
||||
: base(data)
|
||||
{
|
||||
if (!this.ParseDSAPrivateKey())
|
||||
{
|
||||
throw new InvalidDataException("DSA Key is not valid");
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<byte> GetSignature(IEnumerable<byte> sessionId)
|
||||
{
|
||||
var data = sessionId.ToArray();
|
||||
using (var sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider())
|
||||
using (var cs = new System.Security.Cryptography.CryptoStream(System.IO.Stream.Null, sha1, System.Security.Cryptography.CryptoStreamMode.Write))
|
||||
{
|
||||
DSAParameters DSAKeyInfo = new DSAParameters();
|
||||
|
||||
DSAKeyInfo.X = this._privateKeyValue.TrimLeadinZero().ToArray();
|
||||
DSAKeyInfo.P = this._pValue.TrimLeadinZero().ToArray();
|
||||
DSAKeyInfo.Q = this._qValue.TrimLeadinZero().ToArray();
|
||||
DSAKeyInfo.G = this._gValue.TrimLeadinZero().ToArray();
|
||||
|
||||
cs.Write(data, 0, data.Length);
|
||||
|
||||
cs.Close();
|
||||
|
||||
var DSA = new System.Security.Cryptography.DSACryptoServiceProvider();
|
||||
DSA.ImportParameters(DSAKeyInfo);
|
||||
var DSAFormatter = new RSAPKCS1SignatureFormatter(DSA);
|
||||
DSAFormatter.SetHashAlgorithm("SHA1");
|
||||
|
||||
var signature = DSAFormatter.CreateSignature(sha1);
|
||||
|
||||
return new SignatureKeyData
|
||||
{
|
||||
AlgorithmName = this.AlgorithmName,
|
||||
Signature = signature,
|
||||
}.GetBytes();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private bool ParseDSAPrivateKey()
|
||||
{
|
||||
// --------- Set up stream to decode the asn.1 encoded RSA private key ------
|
||||
using (var ms = new MemoryStream(this.Data.ToArray()))
|
||||
using (var binr = new BinaryReader(ms)) //wrap Memory Stream with BinaryReader for easy reading
|
||||
{
|
||||
byte bt = 0;
|
||||
ushort twobytes = 0;
|
||||
int elems = 0;
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
|
||||
binr.ReadByte(); //advance 1 byte
|
||||
else if (twobytes == 0x8230)
|
||||
binr.ReadInt16(); //advance 2 bytes
|
||||
else
|
||||
return false;
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes != 0x0102) //version number
|
||||
return false;
|
||||
bt = binr.ReadByte();
|
||||
if (bt != 0x00)
|
||||
return false;
|
||||
|
||||
//------ all private key components are Integer sequences ----
|
||||
elems = GetIntegerSize(binr);
|
||||
this._pValue = binr.ReadBytes(elems);
|
||||
|
||||
elems = GetIntegerSize(binr);
|
||||
this._qValue = binr.ReadBytes(elems);
|
||||
|
||||
elems = GetIntegerSize(binr);
|
||||
this._gValue = binr.ReadBytes(elems);
|
||||
|
||||
elems = GetIntegerSize(binr);
|
||||
this._publicKeyValue = binr.ReadBytes(elems);
|
||||
|
||||
elems = GetIntegerSize(binr);
|
||||
this._privateKeyValue = binr.ReadBytes(elems);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int GetIntegerSize(BinaryReader binr)
|
||||
{
|
||||
byte bt = 0;
|
||||
byte lowbyte = 0x00;
|
||||
byte highbyte = 0x00;
|
||||
int count = 0;
|
||||
bt = binr.ReadByte();
|
||||
if (bt != 0x02) //expect integer
|
||||
return 0;
|
||||
bt = binr.ReadByte();
|
||||
|
||||
if (bt == 0x81)
|
||||
count = binr.ReadByte(); // data size in next byte
|
||||
else
|
||||
if (bt == 0x82)
|
||||
{
|
||||
highbyte = binr.ReadByte(); // data size in next 2 bytes
|
||||
lowbyte = binr.ReadByte();
|
||||
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
|
||||
count = BitConverter.ToInt32(modint, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
count = bt; // we already have the data size
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private class DsaPublicKeyData : SshData
|
||||
{
|
||||
public IEnumerable<byte> P { get; set; }
|
||||
|
||||
public IEnumerable<byte> Q { get; set; }
|
||||
|
||||
public IEnumerable<byte> G { get; set; }
|
||||
|
||||
public IEnumerable<byte> Public { get; set; }
|
||||
|
||||
protected override void LoadData()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SaveData()
|
||||
{
|
||||
this.Write("ssh-dss");
|
||||
this.Write(this.P.GetSshString());
|
||||
this.Write(this.Q.GetSshString());
|
||||
this.Write(this.G.GetSshString());
|
||||
this.Write(this.Public.GetSshString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Renci.SshClient.Security
|
||||
{
|
||||
internal abstract class Signature : Algorithm
|
||||
{
|
||||
protected IEnumerable<byte> Data { get; private set; }
|
||||
|
||||
public Signature(IEnumerable<byte> data)
|
||||
{
|
||||
this.Data = data;
|
||||
}
|
||||
|
||||
public abstract bool ValidateSignature(IEnumerable<byte> hash, IEnumerable<byte> signature);
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,7 @@ namespace Renci.SshClient
|
||||
|
||||
public static IDictionary<string, Func<IEnumerable<byte>, HMAC>> HmacAlgorithms { get; private set; }
|
||||
|
||||
public static IDictionary<string, Func<IEnumerable<byte>, Signature>> HostKeyAlgorithms { get; private set; }
|
||||
|
||||
public static IDictionary<string, Func<CryptoPublicKey>> HostKeyAlgorithms { get; private set; }
|
||||
|
||||
static Settings()
|
||||
{
|
||||
@@ -39,10 +38,10 @@ namespace Renci.SshClient
|
||||
{"hmac-sha1", (key) => { return new System.Security.Cryptography.HMACSHA1(key.Take(20).ToArray());}},
|
||||
};
|
||||
|
||||
Settings.HostKeyAlgorithms = new Dictionary<string, Func<IEnumerable<byte>, Signature>>()
|
||||
Settings.HostKeyAlgorithms = new Dictionary<string, Func<CryptoPublicKey>>()
|
||||
{
|
||||
{"ssh-rsa", (hostKeyData) => { return new SignatureRsa(hostKeyData);}},
|
||||
{"ssh-dsa", (hostKeyData) => { return new SignatureDss(hostKeyData);;}}, // TODO: Need to be tested
|
||||
{"ssh-rsa", () => { return new CryptoPublicKeyRsa();}},
|
||||
{"ssh-dsa", () => { return new CryptoPublicKeyDss();}}, // TODO: Need to be tested
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user