mirror of
https://github.com/sshnet/SSH.NET.git
synced 2026-09-11 01:36:39 +00:00
Add RsaKey and DsaKey classes
Add HostAlgorithm class for host key authentication and possible for certificate authentication in the future Refactor public/private key logic
This commit is contained in:
@@ -55,7 +55,6 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="ConnectionTest.cs" />
|
||||
<Compile Include="Security\TestCipher.cs" />
|
||||
<Compile Include="Security\TestCryptoKey.cs" />
|
||||
<Compile Include="Security\TestHMac.cs" />
|
||||
<Compile Include="Security\TestHostKey.cs" />
|
||||
<Compile Include="Security\TestKeyExchange.cs" />
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -5,6 +5,7 @@ using System.Text;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Renci.SshNet.Security;
|
||||
using Renci.SshNet.Tests.Properties;
|
||||
using Renci.SshNet.Security.Cryptography;
|
||||
|
||||
namespace Renci.SshNet.Tests.Security
|
||||
{
|
||||
@@ -16,8 +17,8 @@ namespace Renci.SshNet.Tests.Security
|
||||
{
|
||||
var connectionInfo = new PasswordConnectionInfo(Resources.HOST, 22, Resources.USERNAME, Resources.PASSWORD);
|
||||
connectionInfo.HostKeyAlgorithms.Clear();
|
||||
connectionInfo.HostKeyAlgorithms.Add("ssh-rsa", typeof(CryptoPublicKeyRsa));
|
||||
|
||||
connectionInfo.HostKeyAlgorithms.Add("ssh-rsa", (data) => { return new KeyHostAlgorithm("ssh-rsa", new RsaKey(), data); });
|
||||
|
||||
using (var client = new SshClient(connectionInfo))
|
||||
{
|
||||
client.Connect();
|
||||
@@ -30,7 +31,7 @@ namespace Renci.SshNet.Tests.Security
|
||||
{
|
||||
var connectionInfo = new PasswordConnectionInfo(Resources.HOST, 22, Resources.USERNAME, Resources.PASSWORD);
|
||||
connectionInfo.HostKeyAlgorithms.Clear();
|
||||
connectionInfo.HostKeyAlgorithms.Add("ssh-dss", typeof(CryptoPublicKeyDss));
|
||||
connectionInfo.HostKeyAlgorithms.Add("ssh-dss", (data) => { return new KeyHostAlgorithm("ssh-dss", new DsaKey(), data); });
|
||||
|
||||
using (var client = new SshClient(connectionInfo))
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Renci.SshNet.Common
|
||||
/// <summary>
|
||||
/// Base class for DER encoded data.
|
||||
/// </summary>
|
||||
public abstract class DerData
|
||||
public class DerData
|
||||
{
|
||||
private const byte CONSTRUCTED = 0x20;
|
||||
|
||||
@@ -44,13 +44,48 @@ namespace Renci.SshNet.Common
|
||||
private List<byte> _data;
|
||||
|
||||
private int _readerIndex = 0;
|
||||
private int _lastIndex;
|
||||
|
||||
public byte[] Encode()
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether end of data is reached.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if end of data is reached; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsEndOfData
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._readerIndex >= this._lastIndex;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DerData"/> class.
|
||||
/// </summary>
|
||||
public DerData()
|
||||
{
|
||||
this._data = new List<byte>();
|
||||
}
|
||||
|
||||
this.SaveData();
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DerData"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">DER encoded data.</param>
|
||||
public DerData(byte[] data)
|
||||
{
|
||||
this._data = new List<byte>(data);
|
||||
var dataType = this.ReadByte();
|
||||
var length = this.ReadLength();
|
||||
this._lastIndex = this._readerIndex + length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encodes written data as DER byte array.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public byte[] Encode()
|
||||
{
|
||||
var length = this._data.Count();
|
||||
var lengthBytes = this.GetLength(length);
|
||||
|
||||
@@ -60,31 +95,11 @@ namespace Renci.SshNet.Common
|
||||
return this._data.ToArray();
|
||||
}
|
||||
|
||||
public void Decode(byte[] data)
|
||||
{
|
||||
this._data = new List<byte>(data);
|
||||
this._readerIndex = 0;
|
||||
var dataType = this.ReadByte();
|
||||
var length = this.ReadLength();
|
||||
|
||||
this.LoadData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when type specific data need to be loaded.
|
||||
/// </summary>
|
||||
protected abstract void LoadData();
|
||||
|
||||
/// <summary>
|
||||
/// Called when type specific data need to be saved.
|
||||
/// </summary>
|
||||
protected abstract void SaveData();
|
||||
|
||||
/// <summary>
|
||||
/// Reads next mpint data type from internal buffer.
|
||||
/// </summary>
|
||||
/// <returns>mpint read.</returns>
|
||||
protected BigInteger ReadBigInt()
|
||||
public BigInteger ReadBigInteger()
|
||||
{
|
||||
var type = this.ReadByte();
|
||||
if (type != INTEGER)
|
||||
@@ -98,10 +113,40 @@ namespace Renci.SshNet.Common
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes uint32 data into internal buffer.
|
||||
/// Reads next int data type from internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="data">uint32 data to write.</param>
|
||||
protected void Write(UInt32 data)
|
||||
/// <returns>int read.</returns>
|
||||
public int ReadInteger()
|
||||
{
|
||||
var type = this.ReadByte();
|
||||
if (type != INTEGER)
|
||||
throw new InvalidOperationException("Invalid data type, INTEGER(02) is expected.");
|
||||
|
||||
var length = this.ReadLength();
|
||||
|
||||
var data = this.ReadBytes(length);
|
||||
|
||||
if (length > 4)
|
||||
throw new InvalidOperationException("Integer type cannot occupy more then 4 bytes");
|
||||
|
||||
var result = 0;
|
||||
var shift = (length - 1) * 8;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
result |= data[i] << shift;
|
||||
shift -= 8;
|
||||
}
|
||||
|
||||
//return (int)(data[0] << 56 | data[1] << 48 | data[2] << 40 | data[3] << 32 | data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes UInt32 data into internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="data">UInt32 data to write.</param>
|
||||
public void Write(UInt32 data)
|
||||
{
|
||||
var bytes = data.GetBytes();
|
||||
this._data.Add(INTEGER);
|
||||
@@ -110,7 +155,11 @@ namespace Renci.SshNet.Common
|
||||
this.WriteBytes(bytes);
|
||||
}
|
||||
|
||||
protected void Write(BigInteger data)
|
||||
/// <summary>
|
||||
/// Writes BigInteger data into internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="data">BigInteger data to write.</param>
|
||||
public void Write(BigInteger data)
|
||||
{
|
||||
var bytes = data.ToByteArray().Reverse().ToList();
|
||||
this._data.Add(INTEGER);
|
||||
@@ -119,7 +168,11 @@ namespace Renci.SshNet.Common
|
||||
this.WriteBytes(bytes);
|
||||
}
|
||||
|
||||
protected void Write(DerData data)
|
||||
/// <summary>
|
||||
/// Writes DerData data into internal buffer.
|
||||
/// </summary>
|
||||
/// <param name="data">DerData data to write.</param>
|
||||
public void Write(DerData data)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -208,9 +261,5 @@ namespace Renci.SshNet.Common
|
||||
this._readerIndex += length;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Renci.SshNet
|
||||
/// <summary>
|
||||
/// Gets supported host key algorithms for this connection.
|
||||
/// </summary>
|
||||
public IDictionary<string, Type> HostKeyAlgorithms { get; private set; }
|
||||
public IDictionary<string, Func<byte[], HostAlgorithm>> HostKeyAlgorithms { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets supported authentication methods for this connection.
|
||||
@@ -178,10 +178,16 @@ namespace Renci.SshNet
|
||||
//{"none", typeof(...)},
|
||||
};
|
||||
|
||||
this.HostKeyAlgorithms = new Dictionary<string, Type>()
|
||||
this.HostKeyAlgorithms = new Dictionary<string, Func<byte[], HostAlgorithm>>()
|
||||
{
|
||||
{"ssh-rsa", typeof(CryptoPublicKeyRsa)},
|
||||
{"ssh-dss", typeof(CryptoPublicKeyDss)},
|
||||
{"ssh-rsa", (data) => { return new KeyHostAlgorithm("ssh-rsa", new RsaKey(), data); }},
|
||||
{"ssh-dss", (data) => { return new KeyHostAlgorithm("ssh-dss", new DsaKey(), data); }},
|
||||
//{"x509v3-sign-rsa", () => { ... },
|
||||
//{"x509v3-sign-dss", () => { ... },
|
||||
//{"spki-sign-rsa", () => { ... },
|
||||
//{"spki-sign-dss", () => { ... },
|
||||
//{"pgp-sign-rsa", () => { ... },
|
||||
//{"pgp-sign-dss", () => { ... },
|
||||
};
|
||||
|
||||
this.AuthenticationMethods = new Dictionary<string, Type>()
|
||||
|
||||
+3
@@ -5,6 +5,9 @@ using System.Text;
|
||||
|
||||
namespace Renci.SshNet.Messages.Connection
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents "keepalive@openssh.com" type channel request information
|
||||
/// </summary>
|
||||
public class KeepAliveRequestInfo : RequestInfo
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -75,14 +75,14 @@ namespace Renci.SshNet
|
||||
this._publicKeyRequestMessageResponseWaitHandle.Reset();
|
||||
this._isSignatureRequired = false;
|
||||
|
||||
var message = new RequestMessagePublicKey(ServiceName.Connection, this.Username, keyFile.AlgorithmName, keyFile.PublicKey);
|
||||
var message = new RequestMessagePublicKey(ServiceName.Connection, this.Username, keyFile.HostKey.Name, keyFile.HostKey.Data);
|
||||
|
||||
if (this.KeyFiles.Count < 2)
|
||||
{
|
||||
// If only one key file provided then send signature for very first request
|
||||
var signatureData = new SignatureData(message, this.Session.SessionId).GetBytes();
|
||||
|
||||
message.Signature = keyFile.GetSignature(signatureData);
|
||||
message.Signature = keyFile.HostKey.Sign(signatureData);
|
||||
}
|
||||
|
||||
// Send public key authentication request
|
||||
@@ -94,11 +94,11 @@ namespace Renci.SshNet
|
||||
{
|
||||
this._publicKeyRequestMessageResponseWaitHandle.Reset();
|
||||
|
||||
var signatureMessage = new RequestMessagePublicKey(ServiceName.Connection, this.Username, keyFile.AlgorithmName, keyFile.PublicKey);
|
||||
var signatureMessage = new RequestMessagePublicKey(ServiceName.Connection, this.Username, keyFile.HostKey.Name, keyFile.HostKey.Data);
|
||||
|
||||
var signatureData = new SignatureData(message, this.Session.SessionId).GetBytes();
|
||||
|
||||
signatureMessage.Signature = keyFile.GetSignature(signatureData);
|
||||
signatureMessage.Signature = keyFile.HostKey.Sign(signatureData);
|
||||
|
||||
// Send public key authentication request with signature
|
||||
this.SendMessage(signatureMessage);
|
||||
|
||||
@@ -27,42 +27,10 @@ namespace Renci.SshNet
|
||||
private static Regex _privateKeyRegex = new Regex(@"^-----BEGIN (?<keyName>\w+) PRIVATE KEY-----\r?\n(Proc-Type: 4,ENCRYPTED\r?\nDEK-Info: (?<cipherName>[A-Z0-9-]+),(?<salt>[A-F0-9]{16})\r?\n\r?\n)?(?<data>([a-zA-Z0-9/+=]{1,64}\r?\n)+)-----END \k<keyName> PRIVATE KEY-----.*", RegexOptions.Compiled | RegexOptions.Multiline);
|
||||
#endif
|
||||
|
||||
private CryptoPrivateKey _key;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of private key algorithm.
|
||||
/// Gets the host key.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The name of the algorithm.
|
||||
/// </value>
|
||||
public string AlgorithmName
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._key.Name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the public key.
|
||||
/// </summary>
|
||||
public byte[] PublicKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._key.GetPublicKey().GetBytes().ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the signature.
|
||||
/// </summary>
|
||||
/// <param name="sessionId">The session id.</param>
|
||||
/// <returns>Signature data</returns>
|
||||
public byte[] GetSignature(IEnumerable<byte> sessionId)
|
||||
{
|
||||
return this._key.GetSignature(sessionId);
|
||||
}
|
||||
public HostAlgorithm HostKey;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PrivateKeyFile"/> class.
|
||||
@@ -199,16 +167,14 @@ namespace Renci.SshNet
|
||||
switch (keyName)
|
||||
{
|
||||
case "RSA":
|
||||
this._key = new CryptoPrivateKeyRsa();
|
||||
this.HostKey = new KeyHostAlgorithm("ssh-rsa", new RsaKey(decryptedData.ToArray()));
|
||||
break;
|
||||
case "DSA":
|
||||
this._key = new CryptoPrivateKeyDss();
|
||||
this.HostKey = new KeyHostAlgorithm("ssh-dss", new DsaKey(decryptedData.ToArray()));
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Key '{0}' is not supported.", keyName));
|
||||
}
|
||||
|
||||
this._key.Load(decryptedData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -224,10 +190,13 @@ namespace Renci.SshNet
|
||||
{
|
||||
if (cipherInfo == null)
|
||||
throw new ArgumentNullException("cipherInfo");
|
||||
|
||||
|
||||
if (cipherData == null)
|
||||
throw new ArgumentNullException("cipherData");
|
||||
|
||||
if (binarySalt == null)
|
||||
throw new ArgumentNullException("binarySalt");
|
||||
|
||||
List<byte> cipherKey = new List<byte>();
|
||||
|
||||
using (var md5 = new MD5Hash())
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
<Compile Include="Security\Algorithm.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Security\CertificateHostAlgorithm.cs" />
|
||||
<Compile Include="Security\Cryptography\CipherDigitalSignature.cs" />
|
||||
<Compile Include="Security\Cryptography\Ciphers\AesCipher.cs" />
|
||||
<Compile Include="Security\Cryptography\Ciphers\Arc4Cipher.cs" />
|
||||
@@ -129,6 +130,15 @@
|
||||
<Compile Include="Security\Cryptography\Ciphers\RsaCipher.cs" />
|
||||
<Compile Include="Security\Cryptography\Ciphers\SerpentCipher.cs" />
|
||||
<Compile Include="Security\Cryptography\DsaDigitalSignature.cs" />
|
||||
<Compile Include="Security\Cryptography\DsaKey.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Security\Cryptography\Key.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Security\Cryptography\RsaKey.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Security\Cryptography\StreamCipher.cs" />
|
||||
<Compile Include="Security\Cryptography\SymmetricCipher.cs" />
|
||||
<Compile Include="Security\Cryptography\Ciphers\TripleDesCipher.cs" />
|
||||
@@ -151,27 +161,7 @@
|
||||
<Compile Include="Security\Cryptography\Hashes\SHA256Hash.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Security\CryptoKey.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Security\CryptoPrivateKey.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Security\CryptoPrivateKeyDss.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Security\CryptoPrivateKeyRsa.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Security\CryptoPublicKey.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Security\CryptoPublicKeyDss.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Security\CryptoPublicKeyRsa.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Security\HostAlgorithm.cs" />
|
||||
<Compile Include="Security\KeyExchange.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
@@ -190,6 +180,7 @@
|
||||
<Compile Include="Security\KeyExchangeDiffieHellmanGroupExchangeSha256.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Security\KeyHostAlgorithm.cs" />
|
||||
<Compile Include="Shell.NET40.cs" />
|
||||
<Compile Include="SftpClient.NET40.cs" />
|
||||
<Compile Include="PasswordConnectionInfo.NET40.cs" />
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Renci.SshNet.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements certificate support for host algorithm.
|
||||
/// </summary>
|
||||
public class CertificateHostAlgorithm : HostAlgorithm
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the host key data.
|
||||
/// </summary>
|
||||
public override byte[] Data
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CertificateHostAlgorithm"/> class.
|
||||
/// </summary>
|
||||
/// <param name="name">The host key name.</param>
|
||||
public CertificateHostAlgorithm(string name)
|
||||
: base(name)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signs the specified data.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <returns></returns>
|
||||
public override byte[] Sign(byte[] data)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the signature.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <param name="signature">The signature.</param>
|
||||
/// <returns></returns>
|
||||
public override bool VerifySignature(byte[] data, byte[] signature)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Renci.SshNet.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents base class for public and private keys
|
||||
/// </summary>
|
||||
public abstract class CryptoKey
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets key name.
|
||||
/// </summary>
|
||||
public abstract string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Loads key specific data.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
public abstract void Load(IEnumerable<byte> data);
|
||||
|
||||
/// <summary>
|
||||
/// Gets key data byte array.
|
||||
/// </summary>
|
||||
/// <returns>The data byte array.</returns>
|
||||
public abstract IEnumerable<byte> GetBytes();
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using Renci.SshNet.Common;
|
||||
|
||||
namespace Renci.SshNet.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents base class for private keys
|
||||
/// </summary>
|
||||
public abstract class CryptoPrivateKey : CryptoKey
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the public key.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public abstract CryptoPublicKey GetPublicKey();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the signature.
|
||||
/// </summary>
|
||||
/// <param name="key">The key data bytes.</param>
|
||||
/// <returns></returns>
|
||||
public abstract byte[] GetSignature(IEnumerable<byte> key);
|
||||
|
||||
/// <summary>
|
||||
/// Represents signature key data structure
|
||||
/// </summary>
|
||||
protected class SignatureKeyData : SshData
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the algorithm.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The name of the algorithm.
|
||||
/// </value>
|
||||
public string AlgorithmName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the signature.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The signature.
|
||||
/// </value>
|
||||
public byte[] Signature { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Called when type specific data need to be loaded.
|
||||
/// </summary>
|
||||
protected override void LoadData()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when type specific data need to be saved.
|
||||
/// </summary>
|
||||
protected override void SaveData()
|
||||
{
|
||||
this.Write(this.AlgorithmName);
|
||||
this.WriteBinaryString(this.Signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using Renci.SshNet.Common;
|
||||
using Renci.SshNet.Security.Cryptography;
|
||||
|
||||
namespace Renci.SshNet.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents DSS private key
|
||||
/// </summary>
|
||||
internal class CryptoPrivateKeyDss : CryptoPrivateKey
|
||||
{
|
||||
private byte[] _p;
|
||||
private byte[] _q;
|
||||
private byte[] _g;
|
||||
private byte[] _publicKey;
|
||||
private byte[] _privateKey;
|
||||
|
||||
/// <summary>
|
||||
/// Gets key name.
|
||||
/// </summary>
|
||||
public override string Name
|
||||
{
|
||||
get { return "ssh-dss"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads key specific data.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
public override void Load(IEnumerable<byte> data)
|
||||
{
|
||||
MemoryStream ms = null;
|
||||
try
|
||||
{
|
||||
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 SshException("DSS key is not valid for use in specified state");
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes != 0x0102) //version number
|
||||
throw new SshException("DSS key version is not supported.");
|
||||
|
||||
bt = binr.ReadByte();
|
||||
if (bt != 0x00)
|
||||
throw new SshException("DSS key is not valid for use in specified state");
|
||||
|
||||
//------ 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._privateKey = binr.ReadBytes(elems);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (ms != null)
|
||||
{
|
||||
ms.Dispose();
|
||||
ms = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the public key.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override CryptoPublicKey GetPublicKey()
|
||||
{
|
||||
return new CryptoPublicKeyDss(this._p, this._q, this._g, this._publicKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the signature.
|
||||
/// </summary>
|
||||
/// <param name="key">The key data bytes.</param>
|
||||
/// <returns></returns>
|
||||
public override byte[] GetSignature(IEnumerable<byte> key)
|
||||
{
|
||||
var ss1 = new DsaDigitalSignature(this._p, this._q, this._g, this._privateKey, null);
|
||||
var signature = ss1.CreateSignature(key.ToArray());
|
||||
return new SignatureKeyData
|
||||
{
|
||||
AlgorithmName = this.Name,
|
||||
Signature = signature,
|
||||
}.GetBytes().ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets key data byte array.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The data byte array.
|
||||
/// </returns>
|
||||
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 = (int)(modint[3] << 24 | modint[2] << 16 | modint[1] << 8 | modint[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
count = bt; // we already have the data size
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Renci.SshNet.Common;
|
||||
using Renci.SshNet.Security.Cryptography;
|
||||
using Renci.SshNet.Security.Cryptography.Ciphers;
|
||||
|
||||
namespace Renci.SshNet.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents RSA private key
|
||||
/// </summary>
|
||||
internal class CryptoPrivateKeyRsa : CryptoPrivateKey
|
||||
{
|
||||
private byte[] _modulus;
|
||||
private byte[] _exponent;
|
||||
private byte[] _dValue;
|
||||
private byte[] _pValue;
|
||||
private byte[] _qValue;
|
||||
private byte[] _dpValue;
|
||||
private byte[] _dqValue;
|
||||
private byte[] _inverseQ;
|
||||
|
||||
/// <summary>
|
||||
/// Gets key name.
|
||||
/// </summary>
|
||||
public override string Name
|
||||
{
|
||||
get { return "ssh-rsa"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads key specific data.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
public override void Load(IEnumerable<byte> data)
|
||||
{
|
||||
MemoryStream ms = null;
|
||||
try
|
||||
{
|
||||
ms = new MemoryStream(data.ToArray());
|
||||
using (var binr = new BinaryReader(ms))
|
||||
{
|
||||
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 SshException("RSA key is not valid for use in specified state");
|
||||
|
||||
twobytes = binr.ReadUInt16();
|
||||
if (twobytes != 0x0102) //version number
|
||||
throw new SshException("RSA key version is not supported.");
|
||||
|
||||
bt = binr.ReadByte();
|
||||
if (bt != 0x00)
|
||||
throw new SshException("RSA key is not valid for use in specified state");
|
||||
|
||||
//------ 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);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (ms != null)
|
||||
{
|
||||
ms.Dispose();
|
||||
ms = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the public key.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override CryptoPublicKey GetPublicKey()
|
||||
{
|
||||
return new CryptoPublicKeyRsa(this._modulus, this._exponent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the signature.
|
||||
/// </summary>
|
||||
/// <param name="key">The key data bytes.</param>
|
||||
/// <returns></returns>
|
||||
public override byte[] GetSignature(IEnumerable<byte> key)
|
||||
{
|
||||
var signature = new RsaDigitalSignature(this._exponent, this._modulus, this._dValue, this._dpValue, this._dqValue, this._inverseQ, this._pValue, this._qValue);
|
||||
|
||||
return new SignatureKeyData
|
||||
{
|
||||
AlgorithmName = this.Name,
|
||||
Signature = signature.CreateSignature(key.ToArray()),
|
||||
}.GetBytes().ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets key data byte array.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The data byte array.
|
||||
/// </returns>
|
||||
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 = (int)(modint[3] << 24 | modint[2] << 16 | modint[1] << 8 | modint[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
count = bt; // we already have the data size
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Renci.SshNet.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents base class for public keys
|
||||
/// </summary>
|
||||
public abstract class CryptoPublicKey : CryptoKey
|
||||
{
|
||||
/// <summary>
|
||||
/// Verifies the signature.
|
||||
/// </summary>
|
||||
/// <param name="hash">The hash.</param>
|
||||
/// <param name="signature">The signature.</param>
|
||||
/// <returns>true if signature verified; otherwise false.</returns>
|
||||
public abstract bool VerifySignature(IEnumerable<byte> hash, IEnumerable<byte> signature);
|
||||
}
|
||||
}
|
||||
@@ -1,173 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using Renci.SshNet.Common;
|
||||
using Renci.SshNet.Security.Cryptography;
|
||||
|
||||
namespace Renci.SshNet.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents DSS public key
|
||||
/// </summary>
|
||||
public class CryptoPublicKeyDss : CryptoPublicKey
|
||||
{
|
||||
private byte[] _p;
|
||||
private byte[] _q;
|
||||
private byte[] _g;
|
||||
private byte[] _publicKey;
|
||||
|
||||
/// <summary>
|
||||
/// Gets key name.
|
||||
/// </summary>
|
||||
public override string Name
|
||||
{
|
||||
get { return "ssh-dss"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CryptoPublicKeyDss"/> class.
|
||||
/// </summary>
|
||||
public CryptoPublicKeyDss()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CryptoPublicKeyDss"/> class.
|
||||
/// </summary>
|
||||
/// <param name="p">The p value.</param>
|
||||
/// <param name="q">The q value.</param>
|
||||
/// <param name="g">The g value.</param>
|
||||
/// <param name="publicKey">The public key value.</param>
|
||||
public CryptoPublicKeyDss(byte[] p, byte[] q, byte[] g, byte[] publicKey)
|
||||
{
|
||||
this._p = p;
|
||||
this._q = q;
|
||||
this._g = g;
|
||||
this._publicKey = publicKey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads key specific data.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
public override void Load(IEnumerable<byte> data)
|
||||
{
|
||||
MemoryStream ms = null;
|
||||
try
|
||||
{
|
||||
ms = new MemoryStream(data.ToArray());
|
||||
using (var br = new BinaryReader(ms))
|
||||
{
|
||||
|
||||
var pl = (uint)(br.ReadByte() << 24 | br.ReadByte() << 16 | br.ReadByte() << 8 | br.ReadByte());
|
||||
|
||||
_p = br.ReadBytes((int)pl);
|
||||
|
||||
var ql = (uint)(br.ReadByte() << 24 | br.ReadByte() << 16 | br.ReadByte() << 8 | br.ReadByte());
|
||||
|
||||
_q = br.ReadBytes((int)ql);
|
||||
|
||||
var gl = (uint)(br.ReadByte() << 24 | br.ReadByte() << 16 | br.ReadByte() << 8 | br.ReadByte());
|
||||
|
||||
_g = br.ReadBytes((int)gl);
|
||||
|
||||
var xl = (uint)(br.ReadByte() << 24 | br.ReadByte() << 16 | br.ReadByte() << 8 | br.ReadByte());
|
||||
|
||||
_publicKey = br.ReadBytes((int)xl);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (ms != null)
|
||||
{
|
||||
ms.Dispose();
|
||||
ms = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the signature.
|
||||
/// </summary>
|
||||
/// <param name="hash">The hash.</param>
|
||||
/// <param name="signature">The signature.</param>
|
||||
/// <returns>
|
||||
/// true if signature verified; otherwise false.
|
||||
/// </returns>
|
||||
public override bool VerifySignature(IEnumerable<byte> hash, IEnumerable<byte> signature)
|
||||
{
|
||||
|
||||
long i = 0;
|
||||
long j = 0;
|
||||
byte[] tmp;
|
||||
var sig = signature.ToArray();
|
||||
if (sig[0] == 0 && sig[1] == 0 && sig[2] == 0)
|
||||
{
|
||||
long i1 = (sig[i++] << 24) & 0xff000000;
|
||||
long i2 = (sig[i++] << 16) & 0x00ff0000;
|
||||
long i3 = (sig[i++] << 8) & 0x0000ff00;
|
||||
long i4 = (sig[i++]) & 0x000000ff;
|
||||
j = i1 | i2 | i3 | i4;
|
||||
|
||||
i += j;
|
||||
|
||||
i1 = (sig[i++] << 24) & 0xff000000;
|
||||
i2 = (sig[i++] << 16) & 0x00ff0000;
|
||||
i3 = (sig[i++] << 8) & 0x0000ff00;
|
||||
i4 = (sig[i++]) & 0x000000ff;
|
||||
j = i1 | i2 | i3 | i4;
|
||||
|
||||
tmp = new byte[j];
|
||||
Array.Copy(sig, (int)i, tmp, 0, (int)j);
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
var sig1 = new DsaDigitalSignature(_p, _q, _g, null, _publicKey);
|
||||
return sig1.VerifySignature(hash.ToArray(), sig);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets key data byte array.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The data byte array.
|
||||
/// </returns>
|
||||
public override IEnumerable<byte> GetBytes()
|
||||
{
|
||||
return new DsaPublicKeyData
|
||||
{
|
||||
P = this._p,
|
||||
Q = this._q,
|
||||
G = this._g,
|
||||
Public = this._publicKey,
|
||||
}.GetBytes();
|
||||
}
|
||||
|
||||
private class DsaPublicKeyData : SshData
|
||||
{
|
||||
public byte[] P { get; set; }
|
||||
|
||||
public byte[] Q { get; set; }
|
||||
|
||||
public byte[] G { get; set; }
|
||||
|
||||
public byte[] Public { get; set; }
|
||||
|
||||
protected override void LoadData()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SaveData()
|
||||
{
|
||||
this.Write("ssh-dss");
|
||||
this.WriteBinaryString(this.P);
|
||||
this.WriteBinaryString(this.Q);
|
||||
this.WriteBinaryString(this.G);
|
||||
this.WriteBinaryString(this.Public);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using Renci.SshNet.Common;
|
||||
using Renci.SshNet.Security.Cryptography;
|
||||
using Renci.SshNet.Security.Cryptography.Ciphers;
|
||||
|
||||
namespace Renci.SshNet.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents RSA public key
|
||||
/// </summary>
|
||||
public class CryptoPublicKeyRsa : CryptoPublicKey
|
||||
{
|
||||
private byte[] _modulus;
|
||||
|
||||
private byte[] _exponent;
|
||||
|
||||
/// <summary>
|
||||
/// Gets key name.
|
||||
/// </summary>
|
||||
public override string Name
|
||||
{
|
||||
get { return "ssh-rsa"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CryptoPublicKeyRsa"/> class.
|
||||
/// </summary>
|
||||
public CryptoPublicKeyRsa()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CryptoPublicKeyRsa"/> class.
|
||||
/// </summary>
|
||||
/// <param name="modulus">The modulus.</param>
|
||||
/// <param name="exponent">The exponent.</param>
|
||||
internal CryptoPublicKeyRsa(byte[] modulus, byte[] exponent)
|
||||
{
|
||||
this._modulus = modulus;
|
||||
this._exponent = exponent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads key specific data.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
public override void Load(IEnumerable<byte> data)
|
||||
{
|
||||
MemoryStream ms = null;
|
||||
try
|
||||
{
|
||||
ms = new MemoryStream(data.ToArray());
|
||||
using (var br = new BinaryReader(ms))
|
||||
{
|
||||
var el = (uint)(br.ReadByte() << 24 | br.ReadByte() << 16 | br.ReadByte() << 8 | br.ReadByte());
|
||||
|
||||
this._exponent = br.ReadBytes((int)el);
|
||||
|
||||
var ml = (uint)(br.ReadByte() << 24 | br.ReadByte() << 16 | br.ReadByte() << 8 | br.ReadByte());
|
||||
|
||||
this._modulus = br.ReadBytes((int)ml);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (ms != null)
|
||||
{
|
||||
ms.Dispose();
|
||||
ms = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the signature.
|
||||
/// </summary>
|
||||
/// <param name="hash">The hash.</param>
|
||||
/// <param name="signature">The signature.</param>
|
||||
/// <returns>
|
||||
/// true if signature verified; otherwise false.
|
||||
/// </returns>
|
||||
public override bool VerifySignature(IEnumerable<byte> hash, IEnumerable<byte> signature)
|
||||
{
|
||||
long i = 0;
|
||||
long j = 0;
|
||||
byte[] tmp;
|
||||
|
||||
var sig = signature.ToArray();
|
||||
if (sig[0] == 0 && sig[1] == 0 && sig[2] == 0)
|
||||
{
|
||||
long i1 = (sig[i++] << 24) & 0xff000000;
|
||||
long i2 = (sig[i++] << 16) & 0x00ff0000;
|
||||
long i3 = (sig[i++] << 8) & 0x0000ff00;
|
||||
long i4 = (sig[i++]) & 0x000000ff;
|
||||
j = i1 | i2 | i3 | i4;
|
||||
|
||||
i += j;
|
||||
|
||||
i1 = (sig[i++] << 24) & 0xff000000;
|
||||
i2 = (sig[i++] << 16) & 0x00ff0000;
|
||||
i3 = (sig[i++] << 8) & 0x0000ff00;
|
||||
i4 = (sig[i++]) & 0x000000ff;
|
||||
j = i1 | i2 | i3 | i4;
|
||||
|
||||
tmp = new byte[j];
|
||||
Array.Copy(sig, (int)i, tmp, 0, (int)j);
|
||||
sig = tmp;
|
||||
}
|
||||
|
||||
var sig1 = new RsaDigitalSignature(this._exponent, this._modulus);
|
||||
|
||||
return sig1.VerifySignature(hash.ToArray(), sig);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets key data byte array.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The data byte array.
|
||||
/// </returns>
|
||||
public override IEnumerable<byte> GetBytes()
|
||||
{
|
||||
return new RsaPublicKeyData
|
||||
{
|
||||
E = this._exponent,
|
||||
Modulus = this._modulus,
|
||||
}.GetBytes();
|
||||
}
|
||||
|
||||
private class RsaPublicKeyData : SshData
|
||||
{
|
||||
public byte[] Modulus { get; set; }
|
||||
|
||||
public byte[] E { get; set; }
|
||||
|
||||
protected override void LoadData()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SaveData()
|
||||
{
|
||||
this.Write("ssh-rsa");
|
||||
this.WriteBinaryString(this.E);
|
||||
this.WriteBinaryString(this.Modulus);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,12 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// <param name="cipher">The cipher.</param>
|
||||
public CipherDigitalSignature(HashAlgorithm hash, AsymmetricCipher cipher)
|
||||
{
|
||||
if (hash == null)
|
||||
throw new ArgumentNullException("hash");
|
||||
|
||||
if (cipher == null)
|
||||
throw new ArgumentNullException("cipher");
|
||||
|
||||
this._hash = hash;
|
||||
this._cipher = cipher;
|
||||
}
|
||||
@@ -32,7 +38,7 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="signature">The signature.</param>
|
||||
/// <returns></returns>
|
||||
public override bool VerifySignature(byte[] input, byte[] signature)
|
||||
public override bool Verify(byte[] input, byte[] signature)
|
||||
{
|
||||
var sig = this._cipher.Decrypt(signature);
|
||||
|
||||
@@ -68,7 +74,7 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// </summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <returns></returns>
|
||||
public override byte[] CreateSignature(byte[] input)
|
||||
public override byte[] Sign(byte[] input)
|
||||
{
|
||||
// Calculate hash value
|
||||
var hashData = this.Hash(input);
|
||||
@@ -103,6 +109,7 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
|
||||
protected static List<byte> DerEncode(byte[] hashData)
|
||||
{
|
||||
// TODO: Replace with DER Encoding
|
||||
// TODO: Replace with algorithm code
|
||||
var algorithm = new byte[] { 6, 5, 43, 14, 3, 2, 26 };
|
||||
var algorithmParams = new byte[] { 5, 0 };
|
||||
|
||||
@@ -16,56 +16,20 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
|
||||
private bool _isPrivate;
|
||||
|
||||
private BigInteger _exponent;
|
||||
|
||||
private BigInteger _modulus;
|
||||
private BigInteger _d;
|
||||
private BigInteger _dp;
|
||||
private BigInteger _dq;
|
||||
private BigInteger _inverseQ;
|
||||
private BigInteger _p;
|
||||
private BigInteger _q;
|
||||
private RsaKey _key;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RsaCipher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="exponent">The exponent.</param>
|
||||
/// <param name="modulus">The modulus.</param>
|
||||
public RsaCipher(BigInteger exponent, BigInteger modulus)
|
||||
/// <param name="key">The RSA key.</param>
|
||||
public RsaCipher(RsaKey key)
|
||||
{
|
||||
//if (key == null)
|
||||
// throw new ArgumentNullException("key");
|
||||
//this._publicKey = key;
|
||||
this._exponent = exponent;
|
||||
this._modulus = modulus;
|
||||
this._isPrivate = false;
|
||||
}
|
||||
if (key == null)
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RsaCipher"/> class.
|
||||
/// </summary>
|
||||
/// <param name="exponent">The exponent.</param>
|
||||
/// <param name="modulus">The modulus.</param>
|
||||
/// <param name="d">The d.</param>
|
||||
/// <param name="dp">The dp.</param>
|
||||
/// <param name="dq">The dq.</param>
|
||||
/// <param name="inverseQ">The inverse Q.</param>
|
||||
/// <param name="p">The p.</param>
|
||||
/// <param name="q">The q.</param>
|
||||
public RsaCipher(BigInteger exponent, BigInteger modulus, BigInteger d, BigInteger dp, BigInteger dq, BigInteger inverseQ, BigInteger p, BigInteger q)
|
||||
{
|
||||
//if (key == null)
|
||||
// throw new ArgumentNullException("key");
|
||||
//this._privateKey = key;
|
||||
this._exponent = exponent;
|
||||
this._modulus = modulus;
|
||||
this._d = d;
|
||||
this._dp = dp;
|
||||
this._dq = dq;
|
||||
this._inverseQ = inverseQ;
|
||||
this._p = p;
|
||||
this._q = q;
|
||||
this._isPrivate = true;
|
||||
this._key = key;
|
||||
|
||||
this._isPrivate = !this._key.D.IsZero;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -101,7 +65,7 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
{
|
||||
BigInteger random = BigInteger.One;
|
||||
|
||||
var max = this._modulus - 1;
|
||||
var max = this._key.Modulus - 1;
|
||||
|
||||
while (random <= BigInteger.One || random >= max)
|
||||
{
|
||||
@@ -112,29 +76,28 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
|
||||
random = new BigInteger(bytesArray.Reverse().ToArray());
|
||||
}
|
||||
|
||||
BigInteger blindedInput = BigInteger.PositiveMod((BigInteger.ModPow(random, this._exponent, this._modulus) * input), this._modulus);
|
||||
BigInteger blindedInput = BigInteger.PositiveMod((BigInteger.ModPow(random, this._key.Exponent, this._key.Modulus) * input), this._key.Modulus);
|
||||
|
||||
// mP = ((input Mod p) ^ dP)) Mod p
|
||||
var mP = BigInteger.ModPow((blindedInput % this._p), this._dp, this._p);
|
||||
var mP = BigInteger.ModPow((blindedInput % this._key.P), this._key.DP, this._key.P);
|
||||
|
||||
// mQ = ((input Mod q) ^ dQ)) Mod q
|
||||
var mQ = BigInteger.ModPow((blindedInput % this._q), this._dq, this._q);
|
||||
var mQ = BigInteger.ModPow((blindedInput % this._key.Q), this._key.DQ, this._key.Q);
|
||||
|
||||
var h = BigInteger.PositiveMod(((mP - mQ) * this._inverseQ), this._p);
|
||||
var h = BigInteger.PositiveMod(((mP - mQ) * this._key.InverseQ), this._key.P);
|
||||
|
||||
var m = h * this._q + mQ;
|
||||
var m = h * this._key.Q + mQ;
|
||||
|
||||
BigInteger rInv = BigInteger.ModInverse(random, this._modulus);
|
||||
BigInteger rInv = BigInteger.ModInverse(random, this._key.Modulus);
|
||||
|
||||
result = BigInteger.PositiveMod((m * rInv), this._modulus);
|
||||
result = BigInteger.PositiveMod((m * rInv), this._key.Modulus);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = BigInteger.ModPow(input, this._exponent, this._modulus);
|
||||
result = BigInteger.ModPow(input, this._key.Exponent, this._key.Modulus);
|
||||
}
|
||||
|
||||
return result.ToByteArray().Reverse().ToArray();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,13 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="signature">The signature.</param>
|
||||
/// <returns></returns>
|
||||
public abstract bool VerifySignature(byte[] input, byte[] signature);
|
||||
public abstract bool Verify(byte[] input, byte[] signature);
|
||||
|
||||
/// <summary>
|
||||
/// Creates the signature.
|
||||
/// </summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <returns></returns>
|
||||
public abstract byte[] CreateSignature(byte[] input);
|
||||
public abstract byte[] Sign(byte[] input);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,30 +13,23 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// </summary>
|
||||
public class DsaDigitalSignature : DigitalSignature
|
||||
{
|
||||
private BigInteger _p;
|
||||
private BigInteger _q;
|
||||
private BigInteger _g;
|
||||
private BigInteger _privateKey;
|
||||
private BigInteger _publicKey;
|
||||
private static RNGCryptoServiceProvider _randomizer = new System.Security.Cryptography.RNGCryptoServiceProvider();
|
||||
|
||||
private HashAlgorithm _hash;
|
||||
|
||||
private DsaKey _key;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DsaDigitalSignature"/> class.
|
||||
/// </summary>
|
||||
/// <param name="p">The p.</param>
|
||||
/// <param name="q">The q.</param>
|
||||
/// <param name="g">The g.</param>
|
||||
/// <param name="privateKey">The private key.</param>
|
||||
/// <param name="publicKey">The public key.</param>
|
||||
public DsaDigitalSignature(byte[] p, byte[] q, byte[] g, byte[] privateKey, byte[] publicKey)
|
||||
/// <param name="key">The DSA key.</param>
|
||||
public DsaDigitalSignature(DsaKey key)
|
||||
{
|
||||
this._p = new BigInteger(p.Reverse().ToArray());
|
||||
this._q = new BigInteger(q.Reverse().ToArray());
|
||||
this._g = new BigInteger(g.Reverse().ToArray());
|
||||
if (privateKey != null)
|
||||
this._privateKey = new BigInteger(privateKey.Reverse().ToArray());
|
||||
if (publicKey != null)
|
||||
this._publicKey = new BigInteger(publicKey.Reverse().ToArray());
|
||||
if (key == null)
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
this._key = key;
|
||||
|
||||
this._hash = new SHA1Hash();
|
||||
}
|
||||
|
||||
@@ -46,7 +39,7 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="signature">The signature.</param>
|
||||
/// <returns></returns>
|
||||
public override bool VerifySignature(byte[] input, byte[] signature)
|
||||
public override bool Verify(byte[] input, byte[] signature)
|
||||
{
|
||||
var hashInput = this._hash.ComputeHash(input);
|
||||
|
||||
@@ -69,26 +62,26 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
BigInteger s = new BigInteger(sBytes);
|
||||
|
||||
// Reject the signature if 0 < r < q or 0 < s < q is not satisfied.
|
||||
if (r <= 0 || r >= this._q)
|
||||
if (r <= 0 || r >= this._key.Q)
|
||||
return false;
|
||||
|
||||
if (s <= 0 || s >= this._q)
|
||||
if (s <= 0 || s >= this._key.Q)
|
||||
return false;
|
||||
|
||||
// Calculate w = s−1 mod q
|
||||
BigInteger w = BigInteger.ModInverse(s, this._q);
|
||||
BigInteger w = BigInteger.ModInverse(s, this._key.Q);
|
||||
|
||||
// Calculate u1 = H(m)·w mod q
|
||||
BigInteger u1 = hm * w % this._q;
|
||||
BigInteger u1 = hm * w % this._key.Q;
|
||||
|
||||
// Calculate u2 = r * w mod q
|
||||
BigInteger u2 = r * w % this._q;
|
||||
BigInteger u2 = r * w % this._key.Q;
|
||||
|
||||
u1 = BigInteger.ModPow(this._g, u1, this._p);
|
||||
u2 = BigInteger.ModPow(this._publicKey, u2, this._p);
|
||||
u1 = BigInteger.ModPow(this._key.G, u1, this._key.P);
|
||||
u2 = BigInteger.ModPow(this._key.Y, u2, this._key.P);
|
||||
|
||||
// Calculate v = ((g pow u1 * y pow u2) mod p) mod q
|
||||
BigInteger v = ((u1 * u2) % this._p) % this._q;
|
||||
BigInteger v = ((u1 * u2) % this._key.P) % this._key.Q;
|
||||
|
||||
// The signature is valid if v = r
|
||||
return v == r;
|
||||
@@ -99,7 +92,7 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// </summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <returns></returns>
|
||||
public override byte[] CreateSignature(byte[] input)
|
||||
public override byte[] Sign(byte[] input)
|
||||
{
|
||||
var hashInput = this._hash.ComputeHash(input);
|
||||
|
||||
@@ -114,26 +107,30 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
|
||||
do
|
||||
{
|
||||
// TODO: Take random function to base class
|
||||
// TODO: Take random function to BigInteger
|
||||
|
||||
// Generate a random per-message value k where 0 < k < q
|
||||
do
|
||||
{
|
||||
//k = new BigInteger(q.BitLength, random);
|
||||
k = BigInteger.Parse("980263959677973875983479554308083464979482795347", System.Globalization.NumberStyles.None, CultureInfo.InvariantCulture);
|
||||
var bytesArray = new byte[20];
|
||||
_randomizer.GetBytes(bytesArray);
|
||||
|
||||
bytesArray[bytesArray.Length - 1] = (byte)(bytesArray[bytesArray.Length - 1] & 0x7F); // Ensure not a negative value
|
||||
k = new BigInteger(bytesArray.Reverse().ToArray());
|
||||
}
|
||||
while (k <= 0 || k >= this._q);
|
||||
while (k <= 0 || k >= this._key.Q);
|
||||
|
||||
// Calculate r = ((g pow k) mod p) mod q
|
||||
r = BigInteger.ModPow(this._g, k, this._p) % this._q;
|
||||
r = BigInteger.ModPow(this._key.G, k, this._key.P) % this._key.Q;
|
||||
|
||||
// In the unlikely case that r = 0, start again with a different random k
|
||||
} while (r.IsZero);
|
||||
|
||||
|
||||
// Calculate s = ((k pow −1)(H(m) + x*r)) mod q
|
||||
k = (BigInteger.ModInverse(k, this._q) * (m + this._privateKey * r));
|
||||
k = (BigInteger.ModInverse(k, this._key.Q) * (m + this._key.X * r));
|
||||
|
||||
s = k % this._q;
|
||||
s = k % this._key.Q;
|
||||
|
||||
// In the unlikely case that s = 0, start again with a different random k
|
||||
} while (s.IsZero);
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets public key Y.
|
||||
/// </summary>
|
||||
public BigInteger Y { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets private key X.
|
||||
/// </summary>
|
||||
public BigInteger X { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the G.
|
||||
/// </summary>
|
||||
public BigInteger G { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Q.
|
||||
/// </summary>
|
||||
public BigInteger Q { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the P.
|
||||
/// </summary>
|
||||
public BigInteger P { get; private set; }
|
||||
|
||||
private DigitalSignature _digitalSignature;
|
||||
/// <summary>
|
||||
/// Gets the digital signature.
|
||||
/// </summary>
|
||||
protected override DigitalSignature DigitalSignature
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._digitalSignature == null)
|
||||
{
|
||||
this._digitalSignature = new DsaDigitalSignature(this);
|
||||
}
|
||||
return this._digitalSignature;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the public.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The public.
|
||||
/// </value>
|
||||
public override BigInteger[] Public
|
||||
{
|
||||
get
|
||||
{
|
||||
return new BigInteger[] { this.P, this.Q, this.G, this.Y };
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value.Length != 4)
|
||||
throw new InvalidOperationException("Invalid public key.");
|
||||
|
||||
this.P = value[0];
|
||||
this.Q = value[1];
|
||||
this.G = value[2];
|
||||
this.Y = value[3];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the private.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The private.
|
||||
/// </value>
|
||||
protected override BigInteger[] Private
|
||||
{
|
||||
get
|
||||
{
|
||||
//return new BigInteger[] { this.P, this.Q, this.G, this.Y, this.X };
|
||||
return new BigInteger[] { this.P, this.Q, this.G, this.X };
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value.Length != 5)
|
||||
throw new InvalidOperationException("Invalid private key.");
|
||||
|
||||
this.P = value[0];
|
||||
this.Q = value[1];
|
||||
this.G = value[2];
|
||||
this.Y = value[3];
|
||||
this.X = value[4];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DsaKey"/> class.
|
||||
/// </summary>
|
||||
public DsaKey()
|
||||
: base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DsaKey"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">DER encoded private key data.</param>
|
||||
public DsaKey(byte[] data)
|
||||
: base(data)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Renci.SshNet.Common;
|
||||
using Renci.SshNet.Security.Cryptography;
|
||||
|
||||
namespace Renci.SshNet.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for asymmetric cipher algorithms
|
||||
/// </summary>
|
||||
public abstract class Key
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the key specific digital signature.
|
||||
/// </summary>
|
||||
protected abstract DigitalSignature DigitalSignature { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the public key.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The public.
|
||||
/// </value>
|
||||
public abstract BigInteger[] Public { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the private key.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The private.
|
||||
/// </value>
|
||||
protected abstract BigInteger[] Private { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Key"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">DER encoded private key data.</param>
|
||||
public Key(byte[] data)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException("data");
|
||||
|
||||
var der = new DerData(data);
|
||||
var version = der.ReadBigInteger();
|
||||
|
||||
var keys = new List<BigInteger>();
|
||||
while (!der.IsEndOfData)
|
||||
{
|
||||
keys.Add(der.ReadBigInteger());
|
||||
}
|
||||
|
||||
this.Private = keys.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Key"/> class.
|
||||
/// </summary>
|
||||
public Key()
|
||||
: base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signs the specified data with the key.
|
||||
/// </summary>
|
||||
/// <param name="data">The data to sign.</param>
|
||||
/// <returns>Signed data.</returns>
|
||||
public byte[] Sign(byte[] data)
|
||||
{
|
||||
return this.DigitalSignature.Sign(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the signature.
|
||||
/// </summary>
|
||||
/// <param name="data">The data to verify.</param>
|
||||
/// <param name="signature">The signature to verify against.</param>
|
||||
/// <returns></returns>
|
||||
public bool VerifySignature(byte[] data, byte[] signature)
|
||||
{
|
||||
return this.DigitalSignature.Verify(data, signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,26 +16,9 @@ namespace Renci.SshNet.Security.Cryptography
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RsaDigitalSignature"/> class.
|
||||
/// </summary>
|
||||
/// <param name="exponent">The exponent.</param>
|
||||
/// <param name="modulus">The modulus.</param>
|
||||
/// <param name="d">The D value.</param>
|
||||
/// <param name="dp">The DP value.</param>
|
||||
/// <param name="dq">The DQ value.</param>
|
||||
/// <param name="inverseQ">The InverseQ value.</param>
|
||||
/// <param name="p">The P value.</param>
|
||||
/// <param name="q">The Q value.</param>
|
||||
public RsaDigitalSignature(byte[] exponent, byte[] modulus, byte[] d, byte[] dp, byte[] dq, byte[] inverseQ, byte[] p, byte[] q)
|
||||
: base(new SHA1Hash(), new RsaCipher(new BigInteger(exponent.Reverse().ToArray()), new BigInteger(modulus.Reverse().ToArray()), new BigInteger(d.Reverse().ToArray()), new BigInteger(dp.Reverse().ToArray()), new BigInteger(dq.Reverse().ToArray()), new BigInteger(inverseQ.Reverse().ToArray()), new BigInteger(p.Reverse().ToArray()), new BigInteger(q.Reverse().ToArray())))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RsaDigitalSignature"/> class.
|
||||
/// </summary>
|
||||
/// <param name="exponent">The exponent.</param>
|
||||
/// <param name="modulus">The modulus.</param>
|
||||
public RsaDigitalSignature(byte[] exponent, byte[] modulus)
|
||||
: base(new SHA1Hash(), new RsaCipher(new BigInteger(exponent.Reverse().ToArray()), new BigInteger(modulus.Reverse().ToArray())))
|
||||
/// <param name="rsaKey">The RSA key.</param>
|
||||
public RsaDigitalSignature(RsaKey rsaKey)
|
||||
: base(new SHA1Hash(), new RsaCipher(rsaKey))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Renci.SshNet.Common;
|
||||
using Renci.SshNet.Security.Cryptography;
|
||||
|
||||
namespace Renci.SshNet.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains RSA private and public key
|
||||
/// </summary>
|
||||
public class RsaKey : Key
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the modulus.
|
||||
/// </summary>
|
||||
public BigInteger Modulus { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the exponent.
|
||||
/// </summary>
|
||||
public BigInteger Exponent { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the D.
|
||||
/// </summary>
|
||||
public BigInteger D { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the P.
|
||||
/// </summary>
|
||||
public BigInteger P { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Q.
|
||||
/// </summary>
|
||||
public BigInteger Q { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the DP.
|
||||
/// </summary>
|
||||
public BigInteger DP { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the DQ.
|
||||
/// </summary>
|
||||
public BigInteger DQ { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the inverse Q.
|
||||
/// </summary>
|
||||
public BigInteger InverseQ { get; private set; }
|
||||
|
||||
private DigitalSignature _digitalSignature;
|
||||
/// <summary>
|
||||
/// Gets the digital signature.
|
||||
/// </summary>
|
||||
protected override DigitalSignature DigitalSignature
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._digitalSignature == null)
|
||||
{
|
||||
this._digitalSignature = new RsaDigitalSignature(this);
|
||||
}
|
||||
return this._digitalSignature;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the public.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The public.
|
||||
/// </value>
|
||||
public override BigInteger[] Public
|
||||
{
|
||||
get
|
||||
{
|
||||
return new BigInteger[] { this.Exponent, this.Modulus };
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value.Length != 2)
|
||||
throw new InvalidOperationException("Invalid private key.");
|
||||
|
||||
this.Exponent = value[0];
|
||||
this.Modulus = value[1];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the private.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The private.
|
||||
/// </value>
|
||||
protected override BigInteger[] Private
|
||||
{
|
||||
get
|
||||
{
|
||||
return new BigInteger[] { this.Modulus, this.Exponent, this.D, this.P, this.Q, this.DP, this.DQ, this.InverseQ };
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value.Length != 8)
|
||||
throw new InvalidOperationException("Invalid private key.");
|
||||
|
||||
this.Modulus = value[0];
|
||||
this.Exponent = value[1];
|
||||
this.D = value[2];
|
||||
this.P = value[3];
|
||||
this.Q = value[4];
|
||||
this.DP = value[5];
|
||||
this.DQ = value[6];
|
||||
this.InverseQ = value[7];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RsaKey"/> class.
|
||||
/// </summary>
|
||||
public RsaKey()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RsaKey"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">DER encoded private key data.</param>
|
||||
public RsaKey(byte[] data)
|
||||
: base(data)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Renci.SshNet.Common;
|
||||
using Renci.SshNet.Security.Cryptography;
|
||||
|
||||
namespace Renci.SshNet.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for SSH host algorithms.
|
||||
/// </summary>
|
||||
public abstract class HostAlgorithm
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the host key name.
|
||||
/// </summary>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the host key data.
|
||||
/// </summary>
|
||||
public abstract byte[] Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HostAlgorithm"/> class.
|
||||
/// </summary>
|
||||
/// <param name="name">The host key name.</param>
|
||||
public HostAlgorithm(string name)
|
||||
{
|
||||
this.Name = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signs the specified data.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <returns></returns>
|
||||
public abstract byte[] Sign(byte[] data);
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the signature.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <param name="signature">The signature.</param>
|
||||
/// <returns></returns>
|
||||
public abstract bool VerifySignature(byte[] data, byte[] signature);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using Renci.SshNet.Messages.Transport;
|
||||
using System.Diagnostics;
|
||||
using Renci.SshNet.Messages;
|
||||
using Renci.SshNet.Common;
|
||||
using Renci.SshNet.Security.Cryptography;
|
||||
|
||||
namespace Renci.SshNet.Security
|
||||
{
|
||||
@@ -72,6 +73,8 @@ namespace Renci.SshNet.Security
|
||||
{
|
||||
var exchangeHash = this.CalculateHash();
|
||||
|
||||
// TODO: See how to improve this area
|
||||
|
||||
var bytes = this._hostKey;
|
||||
|
||||
var length = (uint)(this._hostKey[0] << 24 | this._hostKey[1] << 16 | this._hostKey[2] << 8 | this._hostKey[3]);
|
||||
@@ -80,9 +83,7 @@ namespace Renci.SshNet.Security
|
||||
|
||||
var data = bytes.Skip(4 + algorithmName.Length);
|
||||
|
||||
CryptoPublicKey key = this.Session.ConnectionInfo.HostKeyAlgorithms[algorithmName].CreateInstance<CryptoPublicKey>();
|
||||
|
||||
key.Load(data);
|
||||
var key = this.Session.ConnectionInfo.HostKeyAlgorithms[algorithmName](this._hostKey);
|
||||
|
||||
return key.VerifySignature(exchangeHash, this._signature);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Renci.SshNet.Common;
|
||||
using Renci.SshNet.Security.Cryptography;
|
||||
|
||||
namespace Renci.SshNet.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements key support for host algorithm.
|
||||
/// </summary>
|
||||
public class KeyHostAlgorithm : HostAlgorithm
|
||||
{
|
||||
private Key _key;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the public key data.
|
||||
/// </summary>
|
||||
public override byte[] Data
|
||||
{
|
||||
get
|
||||
{
|
||||
return new SshKeyData(this.Name, this._key.Public).GetBytes();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="KeyHostAlgorithm"/> class.
|
||||
/// </summary>
|
||||
/// <param name="name">Host key name.</param>
|
||||
/// <param name="key">Host key.</param>
|
||||
public KeyHostAlgorithm(string name, Key key)
|
||||
: base(name)
|
||||
{
|
||||
this._key = key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HostAlgorithm"/> class.
|
||||
/// </summary>
|
||||
/// <param name="name">Host key name.</param>
|
||||
/// <param name="key">Host key.</param>
|
||||
/// <param name="data">Host key encoded data.</param>
|
||||
public KeyHostAlgorithm(string name, Key key, byte[] data)
|
||||
: base(name)
|
||||
{
|
||||
this._key = key;
|
||||
|
||||
var sshKey = new SshKeyData();
|
||||
sshKey.Load(data);
|
||||
this._key.Public = sshKey.Keys;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signs the specified data.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <returns></returns>
|
||||
public override byte[] Sign(byte[] data)
|
||||
{
|
||||
return new SignatureKeyData(this.Name, this._key.Sign(data)).GetBytes().ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the signature.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <param name="signature">The signature.</param>
|
||||
/// <returns></returns>
|
||||
public override bool VerifySignature(byte[] data, byte[] signature)
|
||||
{
|
||||
var signatureData = new SignatureKeyData();
|
||||
signatureData.Load(signature);
|
||||
|
||||
return this._key.VerifySignature(data, signatureData.Signature);
|
||||
}
|
||||
|
||||
private class SshKeyData : SshData
|
||||
{
|
||||
public BigInteger[] Keys { get; private set; }
|
||||
|
||||
public string Name { get; private set; }
|
||||
|
||||
public SshKeyData()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public SshKeyData(string name, params BigInteger[] keys)
|
||||
{
|
||||
this.Name = name;
|
||||
this.Keys = keys;
|
||||
}
|
||||
|
||||
protected override void LoadData()
|
||||
{
|
||||
this.Name = this.ReadString();
|
||||
var keys = new List<BigInteger>();
|
||||
while (!this.IsEndOfData)
|
||||
{
|
||||
keys.Add(this.ReadBigInt());
|
||||
}
|
||||
this.Keys = keys.ToArray();
|
||||
}
|
||||
|
||||
protected override void SaveData()
|
||||
{
|
||||
this.Write(this.Name);
|
||||
foreach (var key in this.Keys)
|
||||
{
|
||||
this.Write(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SignatureKeyData : SshData
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the algorithm.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The name of the algorithm.
|
||||
/// </value>
|
||||
public string AlgorithmName { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the signature.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The signature.
|
||||
/// </value>
|
||||
public byte[] Signature { get; private set; }
|
||||
|
||||
public SignatureKeyData()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public SignatureKeyData(string name, byte[] signature)
|
||||
{
|
||||
this.AlgorithmName = name;
|
||||
this.Signature = signature;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when type specific data need to be loaded.
|
||||
/// </summary>
|
||||
protected override void LoadData()
|
||||
{
|
||||
this.AlgorithmName = this.ReadString();
|
||||
this.Signature = this.ReadBinaryString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when type specific data need to be saved.
|
||||
/// </summary>
|
||||
protected override void SaveData()
|
||||
{
|
||||
this.Write(this.AlgorithmName);
|
||||
this.WriteBinaryString(this.Signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user