diff --git a/src/Renci.SshNet/AgentAuthenticationMethod.cs b/src/Renci.SshNet/AgentAuthenticationMethod.cs
new file mode 100644
index 000000000..17df72918
--- /dev/null
+++ b/src/Renci.SshNet/AgentAuthenticationMethod.cs
@@ -0,0 +1,228 @@
+#if NETFRAMEWORK && !NET20 && !NET35
+using System;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using Renci.SshNet.Common;
+using Renci.SshNet.Messages;
+using Renci.SshNet.Messages.Authentication;
+
+namespace Renci.SshNet {
+ ///
+ /// Provides functionality to perform private key authentication.
+ ///
+ public class AgentAuthenticationMethod : AuthenticationMethod, IDisposable {
+ private AuthenticationResult _authenticationResult = AuthenticationResult.Failure;
+ private EventWaitHandle _authenticationCompleted = new ManualResetEvent (false);
+ private bool _isSignatureRequired;
+
+ ///
+ /// Gets authentication method name
+ ///
+ public override string Name {
+ get { return "publickey"; }
+ }
+
+ ///
+ ///
+ ///
+ public IAgentProtocol Protocol { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The username.
+ /// The key files.
+ /// is whitespace or null.
+ public AgentAuthenticationMethod (string username, IAgentProtocol protocol) : base (username) {
+ Protocol = protocol;
+ }
+
+ ///
+ /// Authenticates the specified session.
+ ///
+ /// The session to authenticate.
+ ///
+ public override AuthenticationResult Authenticate (Session session) {
+ if (Protocol == null)
+ return AuthenticationResult.Failure;
+
+ session.UserAuthenticationSuccessReceived += Session_UserAuthenticationSuccessReceived;
+ session.UserAuthenticationFailureReceived += Session_UserAuthenticationFailureReceived;
+ session.UserAuthenticationPublicKeyReceived += Session_UserAuthenticationPublicKeyReceived;
+
+ session.RegisterMessage ("SSH_MSG_USERAUTH_PK_OK");
+
+ try {
+ foreach (var identity in Protocol.GetIdentities ()) {
+ _authenticationCompleted.Reset ();
+ _isSignatureRequired = false;
+
+ var message = new RequestMessagePublicKey (ServiceName.Connection,
+ Username,
+ identity.Type,
+ identity.Blob);
+
+ // Send public key authentication request
+ session.SendMessage (message);
+
+ session.WaitOnHandle (_authenticationCompleted);
+
+ if (_isSignatureRequired) {
+ _authenticationCompleted.Reset ();
+
+ var signatureMessage = new RequestMessagePublicKey (ServiceName.Connection,
+ Username,
+ identity.Type,
+ identity.Blob);
+
+ var signatureData = new SignatureData (message, session.SessionId).GetBytes ();
+
+ signatureMessage.Signature = this.Protocol.SignData (identity, signatureData);
+
+ // Send public key authentication request with signature
+ session.SendMessage (signatureMessage);
+ }
+
+ session.WaitOnHandle (_authenticationCompleted);
+
+ if (_authenticationResult == AuthenticationResult.Success) {
+ break;
+ }
+ }
+ return _authenticationResult;
+ } finally {
+ session.UserAuthenticationSuccessReceived -= Session_UserAuthenticationSuccessReceived;
+ session.UserAuthenticationFailureReceived -= Session_UserAuthenticationFailureReceived;
+ session.UserAuthenticationPublicKeyReceived -= Session_UserAuthenticationPublicKeyReceived;
+ session.UnRegisterMessage ("SSH_MSG_USERAUTH_PK_OK");
+ }
+ }
+
+ private void Session_UserAuthenticationSuccessReceived (object sender, MessageEventArgs e) {
+ this._authenticationResult = AuthenticationResult.Success;
+
+ this._authenticationCompleted.Set ();
+ }
+
+ private void Session_UserAuthenticationFailureReceived (object sender, MessageEventArgs e) {
+ if (e.Message.PartialSuccess)
+ _authenticationResult = AuthenticationResult.PartialSuccess;
+ else
+ _authenticationResult = AuthenticationResult.Failure;
+
+ // Copy allowed authentication methods
+ AllowedAuthentications = e.Message.AllowedAuthentications;
+
+ _authenticationCompleted.Set ();
+ }
+
+ private void Session_UserAuthenticationPublicKeyReceived (object sender, MessageEventArgs e) {
+ this._isSignatureRequired = true;
+ this._authenticationCompleted.Set ();
+ }
+
+ #region IDisposable Members
+
+ private bool _isDisposed = false;
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ ///
+ public void Dispose () {
+ Dispose (true);
+ GC.SuppressFinalize (this);
+ }
+
+ ///
+ /// Releases unmanaged and - optionally - managed resources
+ ///
+ /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
+ protected virtual void Dispose (bool disposing) {
+ // Check to see if Dispose has already been called.
+ if (!_isDisposed)
+ return;
+
+ if (disposing) {
+ // If disposing equals true, dispose all managed
+ // and unmanaged resources.
+ if (disposing) {
+ var authenticationCompleted = _authenticationCompleted;
+ // Dispose managed resources.
+ if (this._authenticationCompleted != null) {
+ _authenticationCompleted = null;
+ authenticationCompleted.Dispose ();
+ }
+ }
+
+ // Note disposing has been done.
+ _isDisposed = true;
+ }
+ }
+
+ ///
+ /// Releases unmanaged resources and performs other cleanup operations before the
+ /// is reclaimed by garbage collection.
+ ///
+ ~AgentAuthenticationMethod () {
+ // Do not re-create Dispose clean-up code here.
+ // Calling Dispose(false) is optimal in terms of
+ // readability and maintainability.
+ Dispose (false);
+ }
+
+ #endregion
+
+ private class SignatureData : SshData {
+ private readonly RequestMessagePublicKey _message;
+
+ private byte[] _sessionId;
+ private readonly byte[] _serviceName;
+ private readonly byte[] _authenticationMethod;
+
+ protected override int BufferCapacity {
+ get {
+ var capacity = base.BufferCapacity;
+ capacity += 4; // SessionId length
+ capacity += _sessionId.Length; // SessionId
+ capacity += 1; // Authentication Message Code
+ capacity += 4; // UserName length
+ capacity += _message.Username.Length; // UserName
+ capacity += 4; // ServiceName length
+ capacity += _serviceName.Length; // ServiceName
+ capacity += 4; // AuthenticationMethod length
+ capacity += _authenticationMethod.Length; // AuthenticationMethod
+ capacity += 1; // TRUE
+ capacity += 4; // PublicKeyAlgorithmName length
+ capacity += _message.PublicKeyAlgorithmName.Length; // PublicKeyAlgorithmName
+ capacity += 4; // PublicKeyData length
+ capacity += _message.PublicKeyData.Length; // PublicKeyData
+ return capacity;
+ }
+ }
+
+ public SignatureData (RequestMessagePublicKey message, byte[] sessionId) {
+ _message = message;
+ _sessionId = sessionId;
+ _serviceName = Ascii.GetBytes ("ssh-connection");
+ _authenticationMethod = Ascii.GetBytes ("publickey");
+ }
+
+ protected override void LoadData () {
+ throw new System.NotImplementedException ();
+ }
+
+ protected override void SaveData () {
+ WriteBinaryString (_sessionId);
+ Write ((byte) RequestMessage.AuthenticationMessageCode);
+ WriteBinaryString (_message.Username);
+ WriteBinaryString (_serviceName);
+ WriteBinaryString (_authenticationMethod);
+ Write ((byte) 1); // TRUE
+ WriteBinaryString (_message.PublicKeyAlgorithmName);
+ WriteBinaryString (_message.PublicKeyData);
+ }
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/Renci.SshNet/AgentConnectionInfo.cs b/src/Renci.SshNet/AgentConnectionInfo.cs
new file mode 100644
index 000000000..196fad6cb
--- /dev/null
+++ b/src/Renci.SshNet/AgentConnectionInfo.cs
@@ -0,0 +1,164 @@
+#if NETFRAMEWORK && !NET20 && !NET35
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Text;
+
+namespace Renci.SshNet {
+ ///
+ /// Provides connection information when private key authentication method is used
+ ///
+ public class AgentConnectionInfo : ConnectionInfo, IDisposable {
+ ///
+ /// Gets the key files used for authentication.
+ ///
+ public IAgentProtocol Protocol { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Connection host.
+ /// Connection username.
+ /// Connection key files.
+ public AgentConnectionInfo (string host, string username, IAgentProtocol protocol) : this (host, 22, username, ProxyTypes.None, string.Empty, 0, string.Empty, string.Empty, protocol) {
+
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Connection host.
+ /// Connection port.
+ /// Connection username.
+ /// Connection key files.
+ public AgentConnectionInfo (string host, int port, string username, IAgentProtocol protocol) : this (host, port, username, ProxyTypes.None, string.Empty, 0, string.Empty, string.Empty, protocol) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Connection host.
+ /// The port.
+ /// Connection username.
+ /// Type of the proxy.
+ /// The proxy host.
+ /// The proxy port.
+ /// The key files.
+ public AgentConnectionInfo (string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, IAgentProtocol protocol) : this (host, port, username, proxyType, proxyHost, proxyPort, string.Empty, string.Empty, protocol) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Connection host.
+ /// The port.
+ /// Connection username.
+ /// Type of the proxy.
+ /// The proxy host.
+ /// The proxy port.
+ /// The proxy username.
+ /// The key files.
+ public AgentConnectionInfo (string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, IAgentProtocol protocol) : this (host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, string.Empty, protocol) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Connection host.
+ /// Connection username.
+ /// Type of the proxy.
+ /// The proxy host.
+ /// The proxy port.
+ /// The key files.
+ public AgentConnectionInfo (string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, IAgentProtocol protocol) : this (host, 22, username, proxyType, proxyHost, proxyPort, string.Empty, string.Empty, protocol) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Connection host.
+ /// Connection username.
+ /// Type of the proxy.
+ /// The proxy host.
+ /// The proxy port.
+ /// The proxy username.
+ /// The key files.
+ public AgentConnectionInfo (string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, IAgentProtocol protocol) : this (host, 22, username, proxyType, proxyHost, proxyPort, proxyUsername, string.Empty, protocol) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Connection host.
+ /// Connection username.
+ /// Type of the proxy.
+ /// The proxy host.
+ /// The proxy port.
+ /// The proxy username.
+ /// The proxy password.
+ /// The key files.
+ public AgentConnectionInfo (string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, IAgentProtocol protocol) : this (host, 22, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword, protocol) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Connection host.
+ /// The port.
+ /// Connection username.
+ /// Type of the proxy.
+ /// The proxy host.
+ /// The proxy port.
+ /// The proxy username.
+ /// The proxy password.
+ /// The key files.
+ public AgentConnectionInfo (string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, IAgentProtocol protocol) : base (host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword, new AgentAuthenticationMethod (username, protocol)) {
+ this.Protocol = protocol;
+ }
+
+ #region IDisposable Members
+
+ private bool isDisposed = false;
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ ///
+ public void Dispose () {
+ Dispose (true);
+
+ GC.SuppressFinalize (this);
+ }
+
+ ///
+ /// Releases unmanaged and - optionally - managed resources
+ ///
+ /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
+ protected virtual void Dispose (bool disposing) {
+ // Check to see if Dispose has already been called.
+ if (!this.isDisposed) {
+ // If disposing equals true, dispose all managed
+ // and unmanaged resources.
+ if (disposing) {
+ // Dispose managed resources.
+ if (this.AuthenticationMethods != null) {
+ foreach (var authenticationMethods in this.AuthenticationMethods.OfType ()) {
+ authenticationMethods.Dispose ();
+ }
+ }
+ }
+
+ // Note disposing has been done.
+ isDisposed = true;
+ }
+ }
+
+ ///
+ /// Releases unmanaged resources and performs other cleanup operations before the
+ /// is reclaimed by garbage collection.
+ ///
+ ~AgentConnectionInfo () {
+ // Do not re-create Dispose clean-up code here.
+ // Calling Dispose(false) is optimal in terms of
+ // readability and maintainability.
+ Dispose (false);
+ }
+
+ #endregion
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/Renci.SshNet/COPYDATASTRUCT.cs b/src/Renci.SshNet/COPYDATASTRUCT.cs
new file mode 100644
index 000000000..f25d1c9d0
--- /dev/null
+++ b/src/Renci.SshNet/COPYDATASTRUCT.cs
@@ -0,0 +1,13 @@
+#if NETFRAMEWORK && !NET20 && !NET35
+using System;
+using System.Runtime.InteropServices;
+
+namespace Renci.SshNet.Pageant {
+ [StructLayout (LayoutKind.Sequential)]
+ internal struct COPYDATASTRUCT {
+ public IntPtr dwData;
+ public int cbData;
+ public IntPtr lpData;
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/Renci.SshNet/IAgentProtocol.cs b/src/Renci.SshNet/IAgentProtocol.cs
new file mode 100644
index 000000000..e1357fa45
--- /dev/null
+++ b/src/Renci.SshNet/IAgentProtocol.cs
@@ -0,0 +1,24 @@
+#if NETFRAMEWORK && !NET20 && !NET35
+using System.Collections.Generic;
+
+namespace Renci.SshNet {
+ ///
+ ///
+ ///
+ public interface IAgentProtocol {
+ ///
+ ///
+ ///
+ ///
+ IEnumerable GetIdentities ();
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ byte[] SignData (IdentityReference identity, byte[] data);
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/Renci.SshNet/IdentityReference.cs b/src/Renci.SshNet/IdentityReference.cs
new file mode 100644
index 000000000..987eb6c68
--- /dev/null
+++ b/src/Renci.SshNet/IdentityReference.cs
@@ -0,0 +1,36 @@
+#if NETFRAMEWORK && !NET20 && !NET35
+namespace Renci.SshNet {
+ ///
+ ///
+ ///
+ public class IdentityReference {
+ ///
+ ///
+ ///
+ public string Type { get; private set; }
+
+ ///
+ ///
+ ///
+ public byte[] Blob { get; private set; }
+
+ ///
+ ///
+ ///
+ public string Comment { get; private set; }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public IdentityReference (string type, byte[] blob, string comment) {
+ this.Type = type;
+ this.Blob = blob;
+ this.Comment = comment;
+ }
+
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/Renci.SshNet/NativeMethods.cs b/src/Renci.SshNet/NativeMethods.cs
new file mode 100644
index 000000000..df4fc88e3
--- /dev/null
+++ b/src/Renci.SshNet/NativeMethods.cs
@@ -0,0 +1,15 @@
+#if NETFRAMEWORK && !NET20 && !NET35
+using System;
+using System.Runtime.InteropServices;
+
+namespace Renci.SshNet.Pageant {
+ internal class NativeMethods {
+ [DllImport ("user32.dll")]
+ public static extern IntPtr SendMessage (IntPtr hWnd, uint dwMsg, IntPtr wParam, IntPtr lParam);
+
+ [DllImportAttribute ("user32.dll", EntryPoint = "FindWindowA", CallingConvention = CallingConvention.Winapi,
+ ExactSpelling = true)]
+ public static extern IntPtr FindWindow ([MarshalAsAttribute (UnmanagedType.LPStr)] string lpClassName, [MarshalAsAttribute (UnmanagedType.LPStr)] string lpWindowName);
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/Renci.SshNet/PageantProtocol.cs b/src/Renci.SshNet/PageantProtocol.cs
new file mode 100644
index 000000000..42b768844
--- /dev/null
+++ b/src/Renci.SshNet/PageantProtocol.cs
@@ -0,0 +1,200 @@
+#if NETFRAMEWORK && !NET20 && !NET35
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.MemoryMappedFiles;
+using System.Net;
+using System.Runtime.InteropServices;
+using System.Text;
+using Renci.SshNet.Common;
+
+namespace Renci.SshNet.Pageant {
+ ///
+ ///
+ ///
+ public class PageantProtocol : IAgentProtocol {
+
+ #region Constants
+
+ private const int WM_COPYDATA = 0x004A;
+
+ private const long AGENT_COPYDATA_ID = 0x804e50ba;
+ private const int AGENT_COPYDATA_ID_INT = unchecked ((int) AGENT_COPYDATA_ID);
+
+ private const int AGENT_MAX_MSGLEN = 8192;
+
+ ///
+ ///
+ ///
+ public const byte SSH2_AGENTC_REQUEST_IDENTITIES = 11;
+
+ ///
+ ///
+ ///
+ public const byte SSH2_AGENT_IDENTITIES_ANSWER = 12;
+
+ ///
+ ///
+ ///
+ public const byte SSH2_AGENTC_SIGN_REQUEST = 13;
+
+ ///
+ ///
+ ///
+ public const byte SSH2_AGENT_SIGN_RESPONSE = 14;
+
+ #endregion
+
+ ///
+ ///
+ ///
+ public static bool IsRunning {
+ get {
+ var hWnd = NativeMethods.FindWindow ("Pageant", "Pageant");
+
+ return hWnd != IntPtr.Zero;
+ }
+ }
+
+ ///
+ ///
+ ///
+ public PageantProtocol () {
+ var hWnd = NativeMethods.FindWindow ("Pageant", "Pageant");
+
+ if (hWnd == IntPtr.Zero) {
+ throw new SshException ("Pageant not running");
+ }
+
+ }
+
+ #region Implementation of IAgentProtocol
+
+ IEnumerable IAgentProtocol.GetIdentities () {
+ var hWnd = NativeMethods.FindWindow ("Pageant", "Pageant");
+
+ if (hWnd == IntPtr.Zero) {
+ yield break;
+ }
+
+ string mmFileName = Path.GetRandomFileName ();
+
+ using (var mmFile = MemoryMappedFile.CreateNew (mmFileName, AGENT_MAX_MSGLEN)) {
+ var security = mmFile.GetAccessControl ();
+ security.SetOwner (System.Security.Principal.WindowsIdentity.GetCurrent ().User);
+ mmFile.SetAccessControl (security);
+ using (var accessor = mmFile.CreateViewAccessor ()) {
+
+ accessor.Write (0, IPAddress.NetworkToHostOrder (AGENT_MAX_MSGLEN - 4));
+ accessor.Write (4, SSH2_AGENTC_REQUEST_IDENTITIES);
+
+ COPYDATASTRUCT copyData = new COPYDATASTRUCT ();
+ if (IntPtr.Size == 4) {
+ copyData.dwData = new IntPtr (unchecked ((int) AGENT_COPYDATA_ID));
+ } else {
+ copyData.dwData = new IntPtr (AGENT_COPYDATA_ID);
+ }
+ copyData.cbData = mmFileName.Length + 1;
+ copyData.lpData = Marshal.StringToCoTaskMemAnsi (mmFileName);
+ IntPtr copyDataPtr = Marshal.AllocHGlobal (Marshal.SizeOf (copyData));
+ Marshal.StructureToPtr (copyData, copyDataPtr, false);
+ IntPtr resultPtr = NativeMethods.SendMessage (hWnd, WM_COPYDATA, IntPtr.Zero, copyDataPtr);
+ Marshal.FreeHGlobal (copyData.lpData);
+ Marshal.FreeHGlobal (copyDataPtr);
+
+ if (resultPtr == IntPtr.Zero) {
+ yield break;
+ }
+
+ if (accessor.ReadByte (4) != SSH2_AGENT_IDENTITIES_ANSWER) {
+ yield break;
+ }
+
+ int numberOfIdentities = IPAddress.HostToNetworkOrder (accessor.ReadInt32 (5));
+
+ if (numberOfIdentities == 0) {
+ yield break;
+ }
+
+ int position = 9;
+ for (int i = 0; i < numberOfIdentities; i++) {
+ int blobSize = IPAddress.HostToNetworkOrder (accessor.ReadInt32 (position));
+ position += 4;
+
+ var blob = new byte[blobSize];
+
+ accessor.ReadArray (position, blob, 0, blobSize);
+ position += blobSize;
+ int commnetLenght = IPAddress.HostToNetworkOrder (accessor.ReadInt32 (position));
+ position += 4;
+ var commentChars = new byte[commnetLenght];
+ accessor.ReadArray (position, commentChars, 0, commnetLenght);
+ position += commnetLenght;
+
+ string comment = Encoding.ASCII.GetString (commentChars);
+ string type = Encoding.ASCII.GetString (blob, 4, blob[3]); // needs more testing kind of hack
+
+ yield return new IdentityReference (type, blob, comment);
+
+ }
+ }
+
+ }
+ }
+
+ byte[] IAgentProtocol.SignData (IdentityReference identity, byte[] data) {
+ var hWnd = NativeMethods.FindWindow ("Pageant", "Pageant");
+
+ if (hWnd == IntPtr.Zero) {
+ return new byte[0];
+ }
+
+ string mmFileName = Path.GetRandomFileName ();
+
+ using (var mmFile = MemoryMappedFile.CreateNew (mmFileName, AGENT_MAX_MSGLEN)) {
+ using (var accessor = mmFile.CreateViewAccessor ()) {
+ var security = mmFile.GetAccessControl ();
+ security.SetOwner (System.Security.Principal.WindowsIdentity.GetCurrent ().User);
+ mmFile.SetAccessControl (security);
+
+ accessor.Write (0, IPAddress.NetworkToHostOrder (AGENT_MAX_MSGLEN - 4));
+ accessor.Write (4, SSH2_AGENTC_SIGN_REQUEST);
+ accessor.Write (5, IPAddress.NetworkToHostOrder (identity.Blob.Length));
+ accessor.WriteArray (9, identity.Blob, 0, identity.Blob.Length);
+ accessor.Write (9 + identity.Blob.Length, IPAddress.NetworkToHostOrder (data.Length));
+ accessor.WriteArray (13 + identity.Blob.Length, data, 0, data.Length);
+
+ COPYDATASTRUCT copyData = new COPYDATASTRUCT ();
+ if (IntPtr.Size == 4) {
+ copyData.dwData = new IntPtr (unchecked ((int) AGENT_COPYDATA_ID));
+ } else {
+ copyData.dwData = new IntPtr (AGENT_COPYDATA_ID);
+ }
+ copyData.cbData = mmFileName.Length + 1;
+ copyData.lpData = Marshal.StringToCoTaskMemAnsi (mmFileName);
+ IntPtr copyDataPtr = Marshal.AllocHGlobal (Marshal.SizeOf (copyData));
+ Marshal.StructureToPtr (copyData, copyDataPtr, false);
+ IntPtr resultPtr = NativeMethods.SendMessage (hWnd, WM_COPYDATA, IntPtr.Zero, copyDataPtr);
+ Marshal.FreeHGlobal (copyData.lpData);
+ Marshal.FreeHGlobal (copyDataPtr);
+
+ if (resultPtr == IntPtr.Zero) {
+ return new byte[0];
+ }
+
+ if (accessor.ReadByte (4) != SSH2_AGENT_SIGN_RESPONSE) {
+ return new byte[0];
+ }
+
+ int size = IPAddress.HostToNetworkOrder (accessor.ReadInt32 (5));
+ var ret = new byte[size];
+ accessor.ReadArray (9, ret, 0, size);
+ return ret;
+ }
+ }
+ }
+
+ #endregion
+ }
+}
+#endif
\ No newline at end of file