Skip to content
This repository has been archived by the owner on Feb 19, 2019. It is now read-only.

Allow specifying password to skip dialog #22

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions VncSharp/PasswordDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Security;

namespace VncSharp
{
Expand Down Expand Up @@ -125,12 +126,16 @@ private void InitializeComponent()
/// Creates an instance of PasswordDialog and uses it to obtain the user's password.
/// </summary>
/// <returns>Returns the user's password as entered, or null if he/she clicked Cancel.</returns>
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;
}
Expand Down
19 changes: 14 additions & 5 deletions VncSharp/RemoteDesktop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
using System.Drawing.Drawing2D;

using VncSharp.Encodings;
using System.Security;

namespace VncSharp
{
Expand All @@ -36,7 +37,7 @@ namespace VncSharp
/// <summary>
/// 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.
/// </summary>
public delegate string AuthenticateDelegate();
public delegate SecureString AuthenticateDelegate();

/// <summary>
/// SpecialKeys is a list of the various keyboard combinations that overlap with the client-side and make it
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -135,6 +137,13 @@ public int VncPort {
}
}

/// <summary>
/// The password to authenticate with. If left blank, user will be prompted for the password
/// </summary>
public SecureString Password {
set { _Password = value; }
}

/// <summary>
/// True if the RemoteDesktop is connected and authenticated (if necessary) with a remote VNC Host; otherwise False.
/// </summary>
Expand Down Expand Up @@ -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
Expand All @@ -372,7 +381,7 @@ public void Connect(string host, int display, bool viewOnly, bool scaled)
/// <exception cref="System.InvalidOperationException">Thrown if the RemoteDesktop control is already Connected. See <see cref="VncSharp.RemoteDesktop.IsConnected" />.</exception>
/// <exception cref="System.NullReferenceException">Thrown if the password is null.</exception>
/// <param name="password">The user's password.</param>
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.");
Expand Down
26 changes: 20 additions & 6 deletions VncSharp/VncClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
using System.Windows.Forms;

using VncSharp.Encodings;
using System.Security;
using System.Runtime.InteropServices;

namespace VncSharp
{
Expand Down Expand Up @@ -216,7 +218,7 @@ protected byte GetSupportedSecurityType(byte[] types)
/// </summary>
/// <param name="password">The password to use.</param>
/// <returns>Returns True if Authentication worked, otherwise False.</returns>
public bool Authenticate(string password)
public bool Authenticate(SecureString password)
{
if (password == null) throw new ArgumentNullException("password");

Expand Down Expand Up @@ -245,7 +247,7 @@ public bool Authenticate(string password)
/// Performs VNC Authentication using VNC DES encryption. See the RFB Protocol doc 6.2.2.
/// </summary>
/// <param name="password">A string containing the user's password in clear text format.</param>
protected void PerformVncAuthentication(string password)
protected void PerformVncAuthentication(SecureString password)
{
byte[] challenge = rfb.ReadSecurityChallenge();
rfb.WriteSecurityResponse(EncryptChallenge(password, challenge));
Expand All @@ -257,15 +259,27 @@ protected void PerformVncAuthentication(string password)
/// <param name="password">The user's password.</param>
/// <param name="challenge">The challenge sent by the server.</param>
/// <returns>Returns the encrypted challenge.</returns>
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
Expand Down