How rdp passwords are encrypted 2

Several months ago I wrote about encrypting and decrypting RDP passwords. I left one thing open: encrypting the password up to the full 1329 bytes as mstsc does.

Many people were curious about it so I hope the answer is not a disappointment because it’s actually really simple (but I took me a while to figure that out nonetheless). In what I figure is an attempt to hide the password length mstsc always fills up the password with zeroes until it has 512 bytes length.

Then the password is encrypted like I described earlier which gives us a 1328 bytes password hash. So we have one mystery left, how to reach the 1329 bytes size which still is a strange value since the password is in Unicode which takes 2 bytes per char (so the size should be even).

As it turns out, mstsc just adds a zero!

RDP v2 Screenshot

Remote Desktop Password Encryption & Decryption Tool (3293)

Leave a Reply

  1. Hi,
    I tried using the .NET wrapper provided by MS and using the help. But your tool is not able to decrypt the same. Could you please post the code for the encryption?

  2. Is it possible to generate a hash for another user / Sid ? – I have a requirement using HP thin clients to generate the appropriate hash to insert in default.rdp file – it works for Adminstrator user on the thin client – but obviously not for the User account.

  3. Hi,
    I would like distribute the same file.rdp on my 2 different XP WS (with the same pwd).
    Please, could you said me how to generate the ‘passord 51:b:’ with VBscript?
    Thank for your reply.
    Regards.
    Dominik

  4. @Dominique: This is not possible with VBS since there is no COM object that supports CryptProtect Data api.
    You would either have to create a commandline encryption tool or a com enabled one to encrypt passwords with vbs.

  5. Hi,
    In that case, is your rdp2.exe usable from a command line with parameters?
    Best regards.
    Dominik

  6. Remko, thanks for your Web site, thanks also to Justin Shepard for the translation into VB.
    I have change something’s within his code and adapted the sub main to create an executable object with VB express 2005 (please transfer this news to Jeremy…)
    Concerning my main code, I use 2 parameters (arguments): input file name & output file name. At the end of the encryption, the 1329 bytes are completed with the end of the encryption of 256 spaces.
    ####################################
    Imports System
    Imports System.IO
    Imports System.Text
    Imports System.Runtime.InteropServices
    Imports System.ComponentModel
    Imports Microsoft.VisualBasic

    Public Module RdpEncrypt

    Public Class DPAPI
    _
    Private Shared Function CryptProtectData( _
    ByRef pPlainText As DATA_BLOB, _
    ByVal szDescription As String, _
    ByRef pEntropy As DATA_BLOB, _
    ByVal pReserved As IntPtr, _
    ByRef pPrompt As CRYPTPROTECT_PROMPTSTRUCT, _
    ByVal dwFlags As Integer, _
    ByRef pCipherText As DATA_BLOB _
    ) As Boolean
    End Function

    _
    Private Shared Function CryptUnprotectData( _
    ByRef pCipherText As DATA_BLOB, _
    ByRef pszDescription As String, _
    ByRef pEntropy As DATA_BLOB, _
    ByVal pReserved As IntPtr, _
    ByRef pPrompt As CRYPTPROTECT_PROMPTSTRUCT, _
    ByVal dwFlags As Integer, _
    ByRef pPlainText As DATA_BLOB _
    ) As Boolean
    End Function

    _
    Friend Structure DATA_BLOB
    Public cbData As Integer
    Public pbData As IntPtr
    End Structure

    _
    Friend Structure CRYPTPROTECT_PROMPTSTRUCT
    Public cbSize As Integer
    Public dwPromptFlags As Integer
    Public hwndApp As IntPtr
    Public szPrompt As String
    End Structure

    Private Const CRYPTPROTECT_UI_FORBIDDEN As Integer = 1
    Private Const CRYPTPROTECT_LOCAL_MACHINE As Integer = 4

    Private Shared Sub InitPrompt _
    ( _
    ByRef ps As CRYPTPROTECT_PROMPTSTRUCT _
    )
    ps.cbSize = Marshal.SizeOf(GetType(CRYPTPROTECT_PROMPTSTRUCT))
    ps.dwPromptFlags = 0
    ps.hwndApp = IntPtr.Zero
    ps.szPrompt = Nothing
    End Sub

    Private Shared Sub InitBLOB _
    ( _
    ByVal data As Byte(), _
    ByRef blob As DATA_BLOB _
    )
    ‘ Use empty array for null parameter.
    If data Is Nothing Then
    data = New Byte(0) {}
    End If

    ‘ Allocate memory for the BLOB data.
    blob.pbData = Marshal.AllocHGlobal(data.Length)

    ‘ Make sure that memory allocation was successful.
    If blob.pbData.Equals(IntPtr.Zero) Then
    Throw New Exception( _
    “Unable to allocate data buffer for BLOB structure.”)
    End If

    ‘ Specify number of bytes in the BLOB.
    blob.cbData = data.Length
    Marshal.Copy(data, 0, blob.pbData, data.Length)
    End Sub

    Public Enum KeyType
    UserKey = 1
    MachineKey
    End Enum

    Private Shared defaultKeyType As KeyType = KeyType.UserKey

    Public Shared Function Encrypt _
    ( _
    ByVal keyType As KeyType, _
    ByVal plainText As String, _
    ByVal entropy As String, _
    ByVal description As String _
    ) As String
    If plainText Is Nothing Then
    plainText = String.Empty
    End If
    If entropy Is Nothing Then
    entropy = String.Empty
    End If

    Dim result As Byte()
    Dim encrypted As String = “”
    Dim i As Integer
    result = Encrypt(keyType, _
    Encoding.Unicode.GetBytes(plainText), _
    Encoding.Unicode.GetBytes(entropy), _
    description)
    For i = 0 To result.Length – 1
    encrypted = encrypted & Convert.ToString(result(i), 16).PadLeft(2, “0″).ToUpper()
    Next
    Return encrypted.ToString()
    End Function

    Public Shared Function Encrypt _
    ( _
    ByVal keyType As KeyType, _
    ByVal plainTextBytes As Byte(), _
    ByVal entropyBytes As Byte(), _
    ByVal description As String _
    ) As Byte()
    If plainTextBytes Is Nothing Then
    plainTextBytes = New Byte(0) {}
    End If

    If entropyBytes Is Nothing Then
    entropyBytes = New Byte(0) {}
    End If

    If description Is Nothing Then
    description = String.Empty
    End If

    Dim plainTextBlob As DATA_BLOB = New DATA_BLOB
    Dim cipherTextBlob As DATA_BLOB = New DATA_BLOB
    Dim entropyBlob As DATA_BLOB = New DATA_BLOB

    Dim prompt As _
    CRYPTPROTECT_PROMPTSTRUCT = New CRYPTPROTECT_PROMPTSTRUCT
    InitPrompt(prompt)

    Try
    Try
    InitBLOB(plainTextBytes, plainTextBlob)
    Catch ex As Exception
    Throw New Exception(“Cannot initialize plaintext BLOB.”, ex)
    End Try

    Try
    InitBLOB(entropyBytes, entropyBlob)
    Catch ex As Exception
    Throw New Exception(“Cannot initialize entropy BLOB.”, ex)
    End Try

    Dim flags As Integer = CRYPTPROTECT_UI_FORBIDDEN

    If keyType = keyType.MachineKey Then
    flags = flags Or (CRYPTPROTECT_LOCAL_MACHINE)
    End If

    Dim success As Boolean = CryptProtectData( _
    plainTextBlob, _
    description, _
    entropyBlob, _
    IntPtr.Zero, _
    prompt, _
    flags, _
    cipherTextBlob)

    If Not success Then
    Dim errCode As Integer = Marshal.GetLastWin32Error()

    Throw New Exception(“CryptProtectData failed.”, _
    New Win32Exception(errCode))
    End If

    Dim cipherTextBytes(cipherTextBlob.cbData) As Byte

    Marshal.Copy(cipherTextBlob.pbData, cipherTextBytes, 0, _
    cipherTextBlob.cbData)

    Return cipherTextBytes
    Catch ex As Exception
    Throw New Exception(“DPAPI was unable to encrypt data.”, ex)
    Finally
    If Not (plainTextBlob.pbData.Equals(IntPtr.Zero)) Then
    Marshal.FreeHGlobal(plainTextBlob.pbData)
    End If

    If Not (cipherTextBlob.pbData.Equals(IntPtr.Zero)) Then
    Marshal.FreeHGlobal(cipherTextBlob.pbData)
    End If

    If Not (entropyBlob.pbData.Equals(IntPtr.Zero)) Then
    Marshal.FreeHGlobal(entropyBlob.pbData)
    End If
    End Try
    End Function

    End Class

    Sub Main(ByVal args() As String)
    Try
    Dim INfilename As String = args(0) ‘Input file with string without CrLf
    Dim OUTfilename As String = args(1) ‘Output file
    Dim EncryptedText As String
    Dim TextToEncrypt As String
    Dim EncryptedBlank As String
    Dim BlankToEncrypt As String = Space(256)

    TextToEncrypt = File.ReadAllText(INfilename)

    EncryptedText = DPAPI.Encrypt(DPAPI.KeyType.MachineKey, TextToEncrypt, Nothing, “psw”)
    EncryptedBlank = DPAPI.Encrypt(DPAPI.KeyType.MachineKey, BlankToEncrypt, Nothing, “psw”)

    File.WriteAllText(OUTfilename, EncryptedText & _
    Right(EncryptedBlank, 1329 – Len(EncryptedText))) ‘Encrypted blank to complete to 1329

    Catch ex As Exception
    While Not (ex Is Nothing)
    Console.WriteLine(ex.Message)
    ex = ex.InnerException
    End While
    End Try
    End Sub

    End Module
    ####################################
    Regards.
    Dominik

  7. Hi Remko,

    In your original post in the comments you wrote:
    “I will write a new demo app to accompany the article that encrypts the full length password and can encrypt password that are valid for machine instead of user.
    This makes it possible (eg) to publish an rdp connection.”

    I’m just wondering if this is the app you were talking about. I tried to encrypt a password using the tool but didn’t see any option for machine vs. user; I tried it anyway but it doesn’t seem to work for any other user that signs on to the machine besides the one the password was encrypted under.

    Any tips? Basically what I’m trying to do is make an RDP file that I can save under All Users\Desktop and any user who signs in can use it to connect to another machine using a single username/password. I tried your LaunchRDP utility however the missing ‘toolbar’ is an issue for me (users need to be able to minimize the remote desktop window)

    Thanks!

  8. Hello Remko,

    Can you please give me code in C++ which does password encryption same as RDP does?

    I am working on very urgent requirement.

    It will be greate if you help me.

    Thanks

    Jignesh

  9. Hi Remko !!
    Can you please provide the source code in VC++ 6.0/mfc for the encryption/decryption tool that you have used in your ‘Remote Desktop Password Encryption & Decryption Tool (395)’.

    Thanks in advance :)

  10. Dominique Descat, if you will not be against, I would use your code for one of sourceforge projects: RDPman and it’s derivate?

    Thanks.

    (In e-mail it’s not .ur – shold be .ru, thanks for understanding)

  11. I used this tool to encrypt my password and put it in an RDP file.

    It seems that Windows (XP Pro SP3) ignores the username and password entries that I put in the RDP file and will only use the credentials stored in the registry. It doesn’t matter whether I launch the RDP by double-clicking it or launching it using mstsc from a command prompt.

    Does anyone know how to get Windows use the credentials I have stored in the RDP file? Is it because of the version of mstsc (and supporting files) that I am using? A policy? Thanks a lot

  12. I want automated the file creation with .rdp extension for remote desktop and your program is very good but in my vb6 program the call at your program is not the good way.

    is not possible for you create an rdp.dll with the encrypt function only ????

    Best regards

  13. Pingback: Decrypt Remote Desktop Mobile password | Windows CE Programming

  14. Thank you for another informative site. Where else may just I am getting that type of info written in such a perfect approach? I have a mission that I’m just now working on, and I’ve been at the look out for such info.