4

I'm trying to write C# application that can remotely change the RealVNC password on another box.

What works currently is that I can pull a password from a box that has already been changed, store it as a hex string, and then send it to another box AND then change the password that way but I need to be able to change the password or randomize it on the fly.

I'm having problems with creating the correct binary to place in the registry.

I know the VNC key:

byte[] Key = { 23, 82, 107, 6, 35, 78, 88, 7 };

So using the above key and passing "1234" as the password to encrypt using the following code:

public static byte[] EncryptTextToMemory(string Data, byte[] Key)
{
    try
    {
        MemoryStream mStream = new MemoryStream()

        DESCryptoServiceProvider desProvider = new DESCryptoServiceProvider();
        desProvider.Mode = CipherMode.ECB;
        desProvider.Key = Key;

        CryptoStream cStream = new CryptoStream(mStream,
            desProvider.CreateEncryptor(),
            CryptoStreamMode.Write);

        byte[] toEncrypt = new ASCIIEncoding().GetBytes(Data);

        cStream.Write(toEncrypt, 0, toEncrypt.Length);
        cStream.FlushFinalBlock();

        byte[] ret = mStream.ToArray();

        cStream.Close();
        mStream.Close();

        return ret;
    }
    catch (CryptographicException ex)
    {
        MessageBox.Show("A Cryptographic error occurred: " + ex.Message);
        return null;
    }

After passing the returned byte array to BitConverter.ToString, I would expect to get the same hex values as stored in the registry of a password already set to 1234 with RealVNC itself, but I'm not.

Brad Rem
  • 6,036
  • 2
  • 25
  • 50
DrkNite72
  • 41
  • 1
  • 4
  • Any luck? I've looked at the vncpwdump src code and apparently something is done to the key before it is used. I'm was trying to reproduce the encryption through openssl but so far it's been fruitless. – olivervbk Aug 28 '12 at 16:14
  • 1
    Seems that DES uses reverse bit ordering on the password to encrypt... [link](http://www.vidarholen.net/contents/junk/vnc.html) Have not tested it though. – olivervbk Aug 28 '12 at 17:23

1 Answers1

6

Here are my sources to encrypt/decrypt VNC password:

public static string EncryptVNC(string password)
    {
        if (password.Length > 8)
        {
            password = password.Substring(0, 8);
        }
        if (password.Length < 8)
        {
            password = password.PadRight(8, '\0');
        }

        byte[] key = { 23, 82, 107, 6, 35, 78, 88, 7 };
        byte[] passArr = new ASCIIEncoding().GetBytes(password);
        byte[] response = new byte[passArr.Length];
        char[] chars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

        // reverse the byte order
        byte[] newkey = new byte[8];
        for (int i = 0; i < 8; i++)
        {
            // revert desKey[i]:
            newkey[i] = (byte)(
                ((key[i] & 0x01) << 7) |
                ((key[i] & 0x02) << 5) |
                ((key[i] & 0x04) << 3) |
                ((key[i] & 0x08) << 1) |
                ((key[i] & 0x10) >> 1) |
                ((key[i] & 0x20) >> 3) |
                ((key[i] & 0x40) >> 5) |
                ((key[i] & 0x80) >> 7)
                );
        }
        key = newkey;
        // reverse the byte order

        DES des = new DESCryptoServiceProvider();
        des.Padding = PaddingMode.None;
        des.Mode = CipherMode.ECB;

        ICryptoTransform enc = des.CreateEncryptor(key, null);
        enc.TransformBlock(passArr, 0, passArr.Length, response, 0);

        string hexString = String.Empty;
        for (int i = 0; i < response.Length; i++)
        {
            hexString += chars[response[i] >> 4];
            hexString += chars[response[i] & 0xf];
        }
        return hexString.Trim().ToLower();
    }

And to decrypt:

public static string DecryptVNC(string password)
    {
        if (password.Length < 16)
        {
            return string.Empty;
        }

        byte[] key = { 23, 82, 107, 6, 35, 78, 88, 7 };
        byte[] passArr = ToByteArray(password);
        byte[] response = new byte[passArr.Length];

        // reverse the byte order
        byte[] newkey = new byte[8];
        for (int i = 0; i < 8; i++)
        {
            // revert key[i]:
            newkey[i] = (byte)(
                ((key[i] & 0x01) << 7) |
                ((key[i] & 0x02) << 5) |
                ((key[i] & 0x04) << 3) |
                ((key[i] & 0x08) << 1) |
                ((key[i] & 0x10) >> 1) |
                ((key[i] & 0x20) >> 3) |
                ((key[i] & 0x40) >> 5) |
                ((key[i] & 0x80) >> 7)
                );
        }
        key = newkey;
        // reverse the byte order

        DES des = new DESCryptoServiceProvider();
        des.Padding = PaddingMode.None;
        des.Mode = CipherMode.ECB;

        ICryptoTransform dec = des.CreateDecryptor(key, null);
        dec.TransformBlock(passArr, 0, passArr.Length, response, 0);

        return System.Text.ASCIIEncoding.ASCII.GetString(response);
    }

Also this function is needed:

public static byte[] ToByteArray(String HexString)
    {
        int NumberChars = HexString.Length;
        byte[] bytes = new byte[NumberChars / 2];

        for (int i = 0; i < NumberChars; i += 2)
        {
            bytes[i / 2] = Convert.ToByte(HexString.Substring(i, 2), 16);
        }

        return bytes;
    }

At top add:

using System.Security.Cryptography;

Can't remember where I got the code from. I am not the original author.

Andrej K.
  • 61
  • 1
  • 2