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