From 9183b96c01e0b6e29e92d3240fc992e6a1ec56ca Mon Sep 17 00:00:00 2001 From: rickparrish Date: Sun, 18 Sep 2016 19:46:09 -0400 Subject: [PATCH] Allow specifying password to skip dialog --- VncSharp/PasswordDialog.cs | 11 ++++++++--- VncSharp/RemoteDesktop.cs | 19 ++++++++++++++----- VncSharp/VncClient.cs | 26 ++++++++++++++++++++------ 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/VncSharp/PasswordDialog.cs b/VncSharp/PasswordDialog.cs index fc8e00e..b4ea8a4 100644 --- a/VncSharp/PasswordDialog.cs +++ b/VncSharp/PasswordDialog.cs @@ -20,6 +20,7 @@ using System.Collections; using System.ComponentModel; using System.Windows.Forms; +using System.Security; namespace VncSharp { @@ -125,12 +126,16 @@ private void InitializeComponent() /// Creates an instance of PasswordDialog and uses it to obtain the user's password. /// /// Returns the user's password as entered, or null if he/she clicked Cancel. - public static string GetPassword() + public static SecureString GetPassword() { using(PasswordDialog dialog = new PasswordDialog()) { if (dialog.ShowDialog() == DialogResult.OK) { - return dialog.Password; - } else { + SecureString Result = new SecureString(); + for (int i = 0; i < dialog.Password.Length; i++) { + Result.AppendChar(dialog.Password[i]); + } + return Result; + } else { // If the user clicks Cancel, return null and not the empty string. return null; } diff --git a/VncSharp/RemoteDesktop.cs b/VncSharp/RemoteDesktop.cs index e8bdb9b..17ab815 100644 --- a/VncSharp/RemoteDesktop.cs +++ b/VncSharp/RemoteDesktop.cs @@ -25,6 +25,7 @@ using System.Drawing.Drawing2D; using VncSharp.Encodings; +using System.Security; namespace VncSharp { @@ -36,7 +37,7 @@ namespace VncSharp /// /// When connecting to a VNC Host, a password will sometimes be required. Therefore a password must be obtained from the user. A default Password dialog box is included and will be used unless users of the control provide their own Authenticate delegate function for the task. For example, this might pull a password from a configuration file of some type instead of prompting the user. /// - public delegate string AuthenticateDelegate(); + public delegate SecureString AuthenticateDelegate(); /// /// SpecialKeys is a list of the various keyboard combinations that overlap with the client-side and make it @@ -83,6 +84,7 @@ public class RemoteDesktop : Panel Image designModeDesktop; // Used when painting control in VS.NET designer VncClient vnc; // The Client object handling all protocol-level interaction int port = 5900; // The port to connect to on remote host (5900 is default) + SecureString _Password = null; // The password to authenticate with bool passwordPending = false; // After Connect() is called, a password might be required. bool fullScreenRefresh = false; // Whether or not to request the entire remote screen be sent. VncDesktopTransformPolicy desktopPolicy; @@ -135,6 +137,13 @@ public int VncPort { } } + /// + /// The password to authenticate with. If left blank, user will be prompted for the password + /// + public SecureString Password { + set { _Password = value; } + } + /// /// True if the RemoteDesktop is connected and authenticated (if necessary) with a remote VNC Host; otherwise False. /// @@ -352,13 +361,13 @@ public void Connect(string host, int display, bool viewOnly, bool scaled) if (passwordPending) { // Server needs a password, so call which ever method is refered to by the GetPassword delegate. - string password = GetPassword(); + if ((_Password == null) || (_Password.Length == 0)) _Password = GetPassword(); - if (password == null) { + if (_Password == null) { // No password could be obtained (e.g., user clicked Cancel), so stop connecting return; } else { - Authenticate(password); + Authenticate(_Password); } } else { // No password needed, so go ahead and Initialize here @@ -372,7 +381,7 @@ public void Connect(string host, int display, bool viewOnly, bool scaled) /// Thrown if the RemoteDesktop control is already Connected. See . /// Thrown if the password is null. /// The user's password. - public void Authenticate(string password) + public void Authenticate(SecureString password) { InsureConnection(false); if (!passwordPending) throw new InvalidOperationException("Authentication is only required when Connect() returns True and the VNC Host requires a password."); diff --git a/VncSharp/VncClient.cs b/VncSharp/VncClient.cs index 59e1c88..d2f9631 100644 --- a/VncSharp/VncClient.cs +++ b/VncSharp/VncClient.cs @@ -23,6 +23,8 @@ using System.Windows.Forms; using VncSharp.Encodings; +using System.Security; +using System.Runtime.InteropServices; namespace VncSharp { @@ -216,7 +218,7 @@ protected byte GetSupportedSecurityType(byte[] types) /// /// The password to use. /// Returns True if Authentication worked, otherwise False. - public bool Authenticate(string password) + public bool Authenticate(SecureString password) { if (password == null) throw new ArgumentNullException("password"); @@ -245,7 +247,7 @@ public bool Authenticate(string password) /// Performs VNC Authentication using VNC DES encryption. See the RFB Protocol doc 6.2.2. /// /// A string containing the user's password in clear text format. - protected void PerformVncAuthentication(string password) + protected void PerformVncAuthentication(SecureString password) { byte[] challenge = rfb.ReadSecurityChallenge(); rfb.WriteSecurityResponse(EncryptChallenge(password, challenge)); @@ -257,15 +259,27 @@ protected void PerformVncAuthentication(string password) /// The user's password. /// The challenge sent by the server. /// Returns the encrypted challenge. - protected byte[] EncryptChallenge(string password, byte[] challenge) + protected byte[] EncryptChallenge(SecureString password, byte[] challenge) { byte[] key = new byte[8]; + // Get plain text password + string PlaintextPassword = ""; + IntPtr UnmanagedString = IntPtr.Zero; + try { + UnmanagedString = Marshal.SecureStringToBSTR(password); + PlaintextPassword = Marshal.PtrToStringAuto(UnmanagedString); + } finally { + if (UnmanagedString != IntPtr.Zero) { + Marshal.ZeroFreeBSTR(UnmanagedString); + } + } + // Key limited to 8 bytes max. - if (password.Length >= 8) { - System.Text.Encoding.ASCII.GetBytes(password, 0, 8, key, 0); + if (PlaintextPassword.Length >= 8) { + System.Text.Encoding.ASCII.GetBytes(PlaintextPassword, 0, 8, key, 0); } else { - System.Text.Encoding.ASCII.GetBytes(password, 0, password.Length, key, 0); + System.Text.Encoding.ASCII.GetBytes(PlaintextPassword, 0, password.Length, key, 0); } // VNC uses reverse byte order in key