How rdp passwords are encrypted

About Terminal Server, Citrix, Delphi and other stuff

How rdp passwords are encrypted

 Ever wondered how mstsc saves passwords? If you open an RDP file with a text editor like Notepad you can see the encrypted password. In this article I will show you how to encrypt and decrypt these passwords. Besides password recovery this enables you to create rpd files programmatically or perhaps update the password in many rdp files with a batch file.

So if we save a password with mstsc what does it look like? To see that open an rdp file with a text editor (eg Notepad) and you will see something like this:

screen mode id:i:1
desktopwidth:i:1280
desktopheight:i:750
session bpp:i:24
winposstr:s:2,3,188,8,1062,721
full address:s:MyServer
compression:i:1
keyboardhook:i:2
audiomode:i:0
redirectdrives:i:0
redirectprinters:i:0
redirectcomports:i:0
redirectsmartcards:i:0
displayconnectionbar:i:1
autoreconnection enabled:i:1
username:s:MyUserName
domain:s:MyDomain
alternate shell:s:
shell working directory:s:
password 51:b:01000000D08C9DDF0115D1118C7A00C04FC297EB0100000052A9E191EA75A948B359790578C9371A0000000008000000700073007700000003660000A8000000100000000A1DCCD2E50775CA25EC3857164B34DC0000000004800000A000000010000000FCE1A645B9B61AA450946BB6F955058108020000D83591CA47562D6DDAA689F050AE145039EBE22E00D1D3AEAA98373C7B63C3E8E7149072DF989EA43EFCE20513AD3D27B11BE7F17066A688E1DCE828AF85460AAC327B38E90776DB962888E4393D19637578984B19A187AAD95F6D2726ADE7DD315FF56C15FF5B3031014EDDCC3C24D1B81779AFDB006EE575F5BEFB8D2D2138D9D9D642BBB251CC5ED7226968764856EC660A646BACE748A13D6002A9A537AA70710615650B9387EED66DE28BD57B304BBDD7B581B943DA628EB0289E30A8BA784B76F7885BECCAB4FEF7820E97EE3C6E036EEAF6EAA669288DF2FCACC9BEC045C907EBBDE87AFB8CC6B07A600BD63AC891B61D95C2265DD9FD5E635D61BFBF5EDC28311375066611C610FB533D64515B643C82F57D9B183B05C156D91BC0974D38E546022B139E82452E6F1EDF76E52F732C3904E5E433F8F3D488DB0698427DBB0791A9F207F8CB6654CB8410BAF4A59C4F9E821E589ABC1E6E6E1D432181B690408F6884FE1007895A4D26D4A5A2C7458EE747DA35D44AC9FB08AB5477EA3E7CCDB3E37EE20FAFD0D0CF9584E420598B7003B347943AC28048F45E0FD21AD08148FFADCE0E7877219259A7BE722FFAE845A429BA2CF0A71F2D19EA7495530FABDB5106E8D404A38A7E6394C38457640EA7398C5D55F0C4D342CC6A39C77E10A2A5145AEA40B14F5C7C3760334D83C9BE748383FADE231248537353817D51F7B44F61B406ABC61400000071C354139F458B02D978015F785B97F7F6B307380
disable wallpaper:i:1
disable full window drag:i:1
disable menu anims:i:1
disable themes:i:0
disable cursor setting:i:0
bitmapcachepersistenable:i:1

As you can see the password is somehow encrypted before it was saved and automatically decrypted when you open the file with mstsc. .

I did some analysis on mstsc.exe and mstsc uses the functions CryptProtectData and CryptUnProtectData which are both exported by crypt32.dll. Since those API calls are documented let’s try to encrypt a password with mstsc and one ourselves and compare the output:

function CryptRDPPassword(sPassword: string): string;
var DataIn: DATA_BLOB;
    DataOut: DATA_BLOB;
    pwDescription: PWideChar;
    PwdHash: string;
begin
  PwdHash := ”;                                      

  DataOut.cbData := 0;
  DataOut.pbData := nil;                                      

  // RDP uses UniCode
  DataIn.pbData := Pointer(WideString(sPassword));
  DataIn.cbData := Length(sPassword) * SizeOf(WChar);                                      

  // RDP always sets description to psw
  pwDescription := WideString(‘psw’);                                      

  if CryptProtectData(@DataIn,
                      pwDescription,
                      nil,
                      nil,
                      nil,
                      CRYPTPROTECT_UI_FORBIDDEN,  // Never show interface
                      @DataOut) then
  begin
    PwdHash := BlobDataToHexStr(DataOut.pbData, DataOut.cbData);
  end;
  Result := PwdHash;                                      

  // Cleanup
  LocalFree(Cardinal(DataOut.pbData));
  LocalFree(Cardinal(DataIn.pbData));                                      

So we encrypt the password “secret” and compare this with the same password saved by mstsc
MSTSC:

01000000D08C9DDF0115D1118C7A00C04FC297EB0100000052A9E191EA75A948B359790578C9371A0000000008000000700073007700000003660000A8000000100000000A1DCCD2E50775CA25EC3857164B34DC0000000004800000A000000010000000FCE1A645B9B61AA450946BB6F955058108020000D83591CA47562D6DDAA689F050AE145039EBE22E00D1D3AEAA98373C7B63C3E8E7149072DF989EA43EFCE20513AD3D27B11BE7F17066A688E1DCE828AF85460AAC327B38E90776DB962888E4393D19637578984B19A187AAD95F6D2726ADE7DD315FF56C15FF5B3031014EDDCC3C24D1B81779AFDB006EE575F5BEFB8D2D2138D9D9D642BBB251CC5ED7226968764856EC660A646BACE748A13D6002A9A537AA70710615650B9387EED66DE28BD57B304BBDD7B581B943DA628EB0289E30A8BA784B76F7885BECCAB4FEF7820E97EE3C6E036EEAF6EAA669288DF2FCACC9BEC045C907EBBDE87AFB8CC6B07A600BD63AC891B61D95C2265DD9FD5E635D61BFBF5EDC28311375066611C610FB533D64515B643C82F57D9B183B05C156D91BC0974D38E546022B139E82452E6F1EDF76E52F732C3904E5E433F8F3D488DB0698427DBB0791A9F207F8CB6654CB8410BAF4A59C4F9E821E589ABC1E6E6E1D432181B690408F6884FE1007895A4D26D4A5A2C7458EE747DA35D44AC9FB08AB5477EA3E7CCDB3E37EE20FAFD0D0CF9584E420598B7003B347943AC28048F45E0FD21AD08148FFADCE0E7877219259A7BE722FFAE845A429BA2CF0A71F2D19EA7495530FABDB5106E8D404A38A7E6394C38457640EA7398C5D55F0C4D342CC6A39C77E10A2A5145AEA40B14F5C7C3760334D83C9BE748383FADE231248537353817D51F7B44F61B406ABC61400000071C354139F458B02D978015F785B97F7F6B307380

CryptRDPPassword:

01000000D08C9DDF0115D1118C7A00C04FC297EB0100000052A9E191EA75A948B359790578C9371A0000000008000000700073007700000003660000A800000010000000F68F88DF66E436846C077BF402E46EB90000000004800000A000000010000000FE8CEBCF943F9CEC9F3C3A1E0710BEC510000000A647D6ADB728E51F071C854F0BFFF66F140000003B271D41D3D256BCCC4DD255701C14B7489A081D

As you can see the length of a password encrypted by mstsc is 1329 bytes and the one from CryptRDPPassword is smaller. Actually mstsc generates fixed length passwords and our function’s length is based upon the password. Even more strange is that mstsc password is always 1329 bytes because the input password is unicode which should produce an even size length. It doesn’t really matter though because mstsc.exe accepts the smaller sized passwords without any problems.
For now I will leave with a demo tool I wrote to encrypt and decrypt rdp passwords. But in a followup article I will show you how te encrypt the passwords to the full length 1329 bytes the same way mstsc does.

Do you find this article usefull, why not leave a comment?

Related posts:

Please consider donating something (even a small amount is ok) to support this site and my work:



112 Responses for "How rdp passwords are encrypted"KD 1

I always thought the RDP key was easy to decrypt, but it still seems safe because you can only use it for local rdp files. If I grab an RDP from another computer, I get a :
I receive a “error decrypting: key not valid for use in specified state.”
When using other security pen test tools they also do not work for non-local RDP files.
Other then someone owning the remote computer (at which point I’m hosed anyway), what is the risk of storing passwords in RDP files?

Remko 2

The password is encrypted and hashed with the SID (Security Identifier) of the Windows user account. So it’s reasonably safe since you need both the computer and the user account.

3

[...] Continue at source… [...]

victor 4

Hello,

I tried doing this in vc++ but the password never seems to work be able to decrypt with your program.

DATA_BLOB in, out;
BYTE *pbDataInput =(BYTE *)”secret”;
DWORD cbDataInput = strlen((char*)pbDataInput)*sizeof(WCHAR);
in.pbData=pbDataInput;
in.cbData=cbDataInput;
CryptProtectData(&in,L”psw”,NULL,NULL,NULL,CRYPTPROTECT_UI_FORBIDDEN,&out);

char* encPass=(char*)calloc(out.cbData*2,1)
int count=0;
while ( count <= out.cbData ){
sprintf(encPass,”%s%02X”,encPass,out.pbData[count]);
count++;
}
MessageBox(NULL,encPass,”Encrypted password”,MB_OK);

Can you verify what might be wrong here?
I have tried several variations of the above code but no matter what I try it never seems to decrypt properly.

Remko 5

You have to convert out.pbData (pointer to byte) to a string of hex, I think that’s where it goes wrong. Does your output resemble mine?
I convert it like this:

while (I > 0) do begin
Dec(I);
HexStr := HexStr + IntToHex(P^, 2);
Inc(P);
end;

(where P = out.pbData, I=out.cbSize)

Dirk 6

Hi,
i also tried with CryptProtectData, in Python and C++ but never got it to work.

My Python solution:

import win32crypt

pwdHashStr=”"
pwdHash = win32crypt.CryptProtectData(“PASSWORD”,’psw’,None,None,None,0)

##Convert to hex
for char in pwdHash:
pwdHashStr+=”%02X” % ord(char)

print “\nPWD Hash:”,pwdHashStr

print “\nUncrypt:”
print win32crypt.CryptUnprotectData(pwdHash,None,None,None,0)

Output:

PWD Hash: 01000000D08C9DDF0115D1118C7A00C04FC297EB010000004A27EBCD6B02F2448918F77C9638045A0000000008000000700073007700000003660000A800000010000000C6408D7DD8AAE0EB8A79D0C19FABAD8B0000000004800000A00000001000000082E84BC5CE10A8E7F26DE3364A317FA810000000C7890ADAB5BEA9E5A3B610801F4F2C971400000024083669349AC945DFEE697CB49F2D6404BE6E00

Uncrypt:
[u'psw', 'PASSWORD']

But this never worked in RDP, when I put my Hash in your RDP.exe to decode the string I always get ?? as result.

What is wrong?

PS: Victor, does it work at your site?

Dirk 7

PS: My Hash look’s like this:

01000000D08C9DDF0115D1118C7A00C04FC297EB010000004A27EBCD6B02F2448918F77C9638045A0000000008000000700073007700000003660000A80000001000000057002AA83DA5F9A74789FC43EA60205D0000000004800000A000000010000000F788991DB7B4DFDE1B3D0AE3F31802FA10000000EA7B94B97D21A81E3AF8A4203B7389F5140000007F255A17BA47CCD8B1FB7DC9CC182B9B0F9F0AD1

Your hash, on the same machine:

01000000D08C9DDF0115D1118C7A00C04FC297EB01000000283D9E8DDFEB004A912EDC94A2CF3C730400000008000000700073007700000003660000A80000001000000095ECF426B3AC7BE103C0AF75821F389B0000000004800000A000000010000000AA374CEF59A65D7602669A09378A49D618000000873493205666BAE282951B87DF1E4474AF81C263B36E28A014000000F3C8A5933DC4F37728C5EFB4EEEC5951FC36EB26

Remko 8

Dirk you are not using Unicode, that’s why your hash is too short. Convert your cleartext password to Unicode before passing it in to CryptProtectData. Maybe Victor has the same issue?

djinn 9

Yeah, that’s it. Thanx.

10

[...] Read the original article here: http://www.remkoweijnen.nl/blog/2007/10/18/how-rdp-passwords-are-encrypted/ [...]

Zero 11

Hey,

you wrote: “But in a followup article I will show you how te encrypt the passwords to the full length 1329 bytes the same way mstsc does.”

But where can i find this article??

Regards Zero

Remko 12

Don’t worry the followup will appear shortly!
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.

Daniel 13

Greate thing, thanks!

Simon White 14

I would like to generate the RDP file on the fly from a web server so that the file does not exist anywhere on disk. I would simply like to be able pass a function the password and have the return value as the hash that I could use in generating the RDP.

In this way I could assign passwords to the TS accounts that the user never knows and the RDP file would be created and returned to the user so they can access their RDP applications. Since the user is already logged into my server via a web portal they could easily click on a link on the web page and access their RDP applications without logging in again.

Remko 15

Simon, I don’t think this will work. An encrypted password is only valid for the Windows user who encrypted it (or in case op special encryption options for all users on the Windows machine it was encrypted on).

Simon White 16

Remko, since I am the administrator of the server I can setup the user and the passwords which means I can login as the required user and generate the hash. So I will simply store them in an encrypted table which I could then use to get the appropriated hash when dynamically creating the rdp file. I think this should work and achieve the same goal.

decksta 17

Do you have a command line version of this wonderful utility?

Remko 18

@simon: do you need a commandlinetool for this (just like decksta)?

@decksta: not yet, maybe you can use the Python version that was submitted by a reader? I plan to make a commandline version in the followup article though but time is lacking at the moment.

Simon White 19

At the moment I do not need a command line version at present but who knows down the road it might be handy.

Zero 20

Hey,

i write some Time before!
I`m always waiting for the App that creates the real RDP Password String!
PLS let me know if the Application is ready!

Regards Zero!

ok 21

hi the information is helpfull.
how ever can anybody help me with a compleate c++ class that can lunch the remote desktop client (with user name and password i have them) programatically.

my idea is to create a .rdp file programatially using a given username and password then lunch the remote desktop client application using this file.

I know it looks like I am a bit lazy , but its not so.
I will learn deeply the code and change it to fit my project. I need a sort-cut to sturt learning this issue faster. (wish to go hier in code knowlege as fast as possible).

Landon 22

Hi,
I’ve tried to encrypt using CryptProtectData() and then converting the DATA_BLOB to string. In addition, I created a .RDP file using Remote Desktop Connection client with the same password.
The hash value obtained from my program is always different from the one in the .RDP file.
The string used is “PASSWORD”

My Hash value:
01000000d08c9ddf0115d1118c7a00c04fc297eb010000009448dc0c98616943b32c279bf72dedd8000000001e00000045006e00630072007900700074006500640020006400610074006100000003660000a800000010000000826a248787f46b3c72a842fe47c4e4540000000004800000a0000000100000005f2a9a1972fd97deb41a9fd1f981e9a318000000e70bf7d99b9a00c97e222ac9cdfb9e7724e0174b8fdd932a14000000956f52f5d0f96825fcebe5a0c28475160cb6810f

Generated Hash Value:
01000000D08C9DDF0115D1118C7A00C04FC297EB010000009448DC0C98616943B32C279BF72DEDD80000000008000000700073007700000003660000A8000000100000006847E172F2395916195B27E7DB40ED610000000004800000A00000001000000047C2181F972C3B7F7729E42873D392EA08020000982634568984F785E52AD05245AA9684C6EBC0ACF4E61540464C8CFC1121B4DC951F45E71425F4F7588D9AAF06F20BE2CE220CF46FC86242C828DC5AF1A3E26707FE6322EB2CCB473D6DE52C89677F2CA0EE644452E3E94F2B6B976883F37D2BAADF4393297A54A2006892F7CCF3F843A223C73EA28D1C219BEC85D6CB775F959893635E15DE95453A76DE1862C16B754902FA7A60FACED79B2DACC6E1255F93FAAD0525706E74A4B6897E13FF714F9451EB3223DBC2DD21E0EA3DA6C7495A27C7AE108D874907E1468AF955809BA2F3033AD37EA583BE04859D06167973919DDE833AED8F932879C38C4C21330EDA108F9D3BEE304060C85D493BD9F549825AD2064E62B0CD84444EAC63F8534F5548D1FA2F159297722BC4AB1E7349CDA02592F4ED9B4E03C3A874FD0C1CC812BBA8028F3DA5BDBB33B20F3401732E868B6F01599101C783197DB77A5787D78F2205F4A2524ECCAD3BFDA6AF2859F3BD139233658393C27BFB27BAEB24C8252ABA4E975EE4FB05D6E8D9F605A44E1B664B39569D919FBE2F6EB5DA927976BB3F9A7C1977B97077607D8F2E8759AEC8C5430279F2CEB71A48F7D71C40327B6D0A2469C923F40083441826C10010AA90AC4B0E286880F9FBFF84FB04CEE8D2A3F85D5D319E76732D677AD56A8F603C410F2E5AEEEEAA70745EE7E0B01AD959A7DE5D526E54C0B488938AEDB5FE35E5FD0E1847B2600374DB040DDF1400000062637475F860671DEAA7CBCD8D00092DFF1F40E40

My Code snippet:

std::wstring strTmp = CT2W(password.GetString());
BYTE *pbDataInput = (BYTE *)(strTmp.c_str());
DWORD cbDataInput = wcslen((wchar_t *)pbDataInput) * sizeof(wchar_t);

CString encryptedData;

DataIn.pbData = pbDataInput;
DataIn.cbData = cbDataInput;

if(CryptProtectData(&DataIn,
L”cyr”,
NULL,
NULL,
NULL,
CRYPTPROTECT_UI_FORBIDDEN ,
&DataOut))
{
//Convert the Byte to string

BYTE* pb;
pb = DataOut.pbData;

for(DWORD i =0; i != DataOut.cbData; i++)
{
unsigned char ch =*pb;
unsigned char ch0 = ch & 0xf0;
ch0 = (ch>>4) & 0x0F;
unsigned char ch1 = ch & 0x0F;

encryptedData.AppendFormat(_T(“%x%x”),ch0,ch1);
pb++;
}

mehdi 23

hi,
i have mstsc 6.0, but in my RDP file i dont find the line :
password 51:b: !!!
even when i check the checkedbox : save the password on the console…
should i add the line by my self !?

Remko 24

@mehdi: the version 6 client cannot save the password but can read passwords saved in .rdp file. So you can indeed place it in with notepad. I use also a modified version of the old client that can be used without installing the v6 client to save password in .rdp files.

Remko 25

@Landon: yes the string generated by mstsc is longer, it’s always fixed size 3129 bytes. It doesn’t matter though your shorter hash should work as well. Please remember that you need to encode the password in unicode so LPWSTR (PWideChar in Delphi).

FrankO 26

Hello,
I know it’s not really what you are working on here, but I want to be able to use remote desktop without the password encryption so the password stays with the file wherever it is (on any machine/any user). I have no great security concerns, and the encryption is a royal pain to me. I installed version 5.1 on Vista Ultimate. It was tricky, but I did it. I would be very grateful for a solution.

Remko 27

@FrankO: You could use my LaunchRDP commandline tool. It accepts paramaters like servername, username and password. You could just save it in a .bat file.

raghu 28

Hi where i will find LaunchRDP command line tool

raghu 30

how to encrypt the password as similar as mstsc encryption( 1329) bytes. Is there is any code?

raghu 31

thanks remko. how to encrypt the password as similar as mstsc encryption( 1329) bytes. Is there is any code?

Master-Guy 33

Any luck on the follow-up post?
I’d like to have the demo of the encryptor with the full 1329 chars.

askQ 34

Hi remko,

I had following C code and generated RDP password string, but it doesn’t work when I pasted in .rdp file or use your tool to decrypted, but it can be decrypted by my program, what’s wrong with it?

#include
#include
#include

int main(void) {

int count =0;
char *encPass;
DATA_BLOB DataIn;
DATA_BLOB DataOut;
LPWSTR description = NULL;
LPWSTR pwd = L”ssl”;
DataIn.pbData = (BYTE *)pwd;

if (DataIn.pbData == NULL) {
return 0;
}

DataIn.cbData = (DWORD)strlen((const char*)DataIn.pbData) + 1;

if (CryptProtectData(
&DataIn,
(LPCWSTR)L”simple.wincrypt”,
NULL,
NULL,
NULL,
CRYPTPROTECT_UI_FORBIDDEN,
&DataOut))
{
printf(“encryption phase worked. \n”);
encPass = (char*)calloc(DataOut.cbData*2,1);
for (count=0; count cl Printf11.c /link crypt32.lib
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80×86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

Printf11.c
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:Printf11.exe
crypt32.lib
Printf11.obj

C:\workspace>Printf11
encryption phase worked.
01000000D08C9DDF0115D1118C7A00C04FC297EB010000005AC022B53B045C488238D63E13C750D8
0000000020000000730069006D0070006C0065002E00770069006E00630072007900700074000000
03660000A800000010000000A8A5C34F23D6424D9D95DFCA47DC830A0000000004800000A0000000
10000000C477C79214DB8016909E9B2DFBBC56F0080000003933B47CC7B9D98314000000517D0F50
FA8804EB2254B66D3518570D21D5395F

askQ 35

Here is the code again:

int main(void) {

int count =0;
char *encPass;
DATA_BLOB DataIn;
DATA_BLOB DataOut;
LPWSTR description = NULL;
LPWSTR pwd = L”ssl”;
DataIn.pbData = (BYTE *)pwd;

if (DataIn.pbData == NULL) {
return 1;
}

DataIn.cbData = (DWORD)strlen((const char*)DataIn.pbData) + 1;

if (CryptProtectData(
&DataIn,
(LPCWSTR)L”simple.wincrypt”,
NULL,
NULL,
NULL,
CRYPTPROTECT_UI_FORBIDDEN,
&DataOut))
{
printf(“encryption phase worked. \n”);
encPass = (char*)calloc(DataOut.cbData*2,1);
for (count=0; count < DataOut.cbData; count++ ){

sprintf(encPass, “%s%02X”, encPass, DataOut.pbData[count]);
}
printf(“%s”, encPass);

LocalFree(DataOut.pbData);
} else {
printf(“encryption Fail. \n”);
}
return 0;
}

Remko 36

@askQ: I think you are passing a wrong size to the cbData parameter. You should pass length in bytes (not charcount!) without the #0 terminator.

coderguy 37

Remko,

Thanks for providing your code and your utility.

I have 2 issues if you don’t mind me asking:

1) The only issue I have with the LaunchRDP util is that there is no “top bar (the one with minimize)” to get out of RDP, I have to ALT-TAB. Am I passing something wrong to the LaunchRDP util?

2) .NET comes with a wrapper to use CryptProtectData(), but I couldn’t get it working. Has anyone done this in .NET (C# or VB)?

coderguy 39

I’ve got an encoding problem too, but I can’t figure out where it’s going wrong.

The first part of my hashcode is coming out like this:
1000D08C9DDF115D

Running your enc util, your hash code comes out like this:
01000000D08C9DDF0115D

Hmm, looks like mine is 8-bit and yours is 16-bit or something?

Sorry for the trouble…

coderguy 40

Maybe it’s my hex conversion that’s wrong, hmm, any ideas anyone? (See above post)

coderguy 41

For anyone else having this issue in .NET

I seemed to have fixed it by doing 2 things:

1) Altered this VB.NET sample code to return bytes in the main encrypt function instead of the base 64 string:
http://www.obviex.com/samples/dpapi.aspxadding

2) Added a for next loop to add leading 0′s to the hex conversion

If someone needs the full code, let me know and I guess I’ll paste it, but it’s so long that I did not want to paste it in here.

‘Convert user inputted password to unicode
Dim unicodePass As String = Encoding.Unicode.GetString(Encoding.ASCII.GetBytes(tb1.Text))

Dim encBytes() As Byte = modDAPI.DPAPI.Encrypt(DPAPI.KeyType.UserKey, unicodePass, Nothing, “psw”)
‘tbOut.Text = encBytes.ToString

Dim I As Integer

For I = 0 To encBytes.Length – 1
If encBytes(I).ToString.Length = 1 Then ‘Add 0′s because the .NET hex conversion returns no leading 0 placeholder for Hex
tbOut.Text += “0″ & Hex(encBytes(I))
Else
tbOut.Text += Hex(encBytes(I))
End If

Next

coderguy 42

nm, my code still has a problem. Sorry for the multiple posts.

Remko 43

@coderguy: so what’s your remaining problem? If you encrypt the same password the output size should be equal.

44

[...] months ago I wrote about encrypting and decrypting RDP passwords. I left one thing open: encrypting the password up to [...]

Doug Roorda 45

Any chance some one would be kind enough to post a command line tool for doing this?

Xander 46

I am working with vb.net like coderguy and used the information provided by him when I wrote my encryption program. The output from your tool and the output from my tool vary slightly. Coderguy, do you have your tool working properly?

Yours 01000000D08C9DDF0115D1118C7A00C04FC297EB01000000A4013C8EBA796A498B162E334AE3E05D0400000008000000700073007700000003660000A8000000100000003EBAC3BF9275344D8ECFED55E5E041A50000000004800000A0000000100000005B260261C9ACE8F62800A8F795019DB610000000EE00F714D561B363DFFD0944DA0AFE7C1400000073868F5861436ACB68FBF7233829208607C81C3F

Mine 01000000D08C9DDF0115D1118C7A00C04FC297EB010000001EA7CE8D6F7424AB5507AE53C3AAF7B0000000008000000700073007700000003660000A800000010000000CC4F30EBC7B859F448C5CDF3CD542E40000000004800000A00000001000000006C5C696CEE5FEB1B3FFB78A37A2A28080000009E3025E68A1AE7961400000013220712975272B29EF1D7DA93FE73E8EE32EF7600

Justin 47

Okay, I’m going bonkers here.

I’ve used the sample code from the DPAPI page to build a command-line VB app. In the Encrypt() As String function, I replaced the line:

Return Convert.ToBase64String( _
Encrypt(keyType, _
Encoding.UTF8.GetBytes(plainText), _
Encoding.UTF8.GetBytes(entropy), _
description))

with:

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
If result(i).ToString.Length = 1 Then
encrypted = encrypted & “0″ & Hex(result(i))
Else
encrypted = encrypted & Hex(result(i))
End If
Next
Return encrypted

I get what *looks* like a valid encoded password, but it neither works when dropped into an RDP file, nor does it decode correctly with Remko’s app.

What am I doing wrong?

DanielHeth 48

coderguy, is it possible for you to post your full code somewhere and maybe link to it here?

DanielHeth 49

ok, strike that… just figured it out… kinda…

1. first i am using the code from http://www.obviex.com/samples/dpapi.aspx that Remko described…

2. modified the following function as per Justin

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

‘Return Convert.ToBase64String( _
‘ Encrypt(keyType, _
‘ Encoding.UTF8.GetBytes(plainText), _
‘ Encoding.UTF8.GetBytes(entropy), _
‘ description))

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
If result(i).ToString.Length = 1 Then
encrypted = encrypted & “0″ & Hex(result(i))
Else
encrypted = encrypted & Hex(result(i))
End If
Next
Return encrypted
End Function

3. Lastly, from my main app… i call the function as follows:
DPAPI.Encrypt(Crypto.DPAPI.KeyType.MachineKey, “password”, Nothing, “psw”)

4. then i use Remko’s tool http://www.remkoweijnen.nl/blog/download/rdp.zip to verify my outputed hash…

The problem i’m running into is the hash is correct only if i encrypt the word password, if i try to encrypt anything else, the hash fails…
anybody with ideas?

Remko 50

@Daniel: Have you tried using the CryptBinaryToString Function (http://msdn2.microsoft.com/en-us/library/aa379887(VS.85).aspx) to convert the hash to a string (to make sure that is done correctly)?

Ben Ocean 51

Has anyone had any luck, or know how to generate the hash in PHP (on a linux based machine)?

(Posted in wrong blog bost before)

Remko 52

@Ben: The encryption uses Win32 API to encrypt so I don’t think this is possible (and requires either the user’s or machine’s sid). Your best bet would be to somehow fire a script or executable on a remote windows machine that can do the encryption for you…

Ben Ocean 53

Yeah I guess that can work via a web interface and a downloadable batch file

Thanks.

lolosoph 54

Hi all,
after lot of tests, I was able to use the generated hash in an RDP file by :

1/ using DanielHeth code in post 49, that means using

Encoding.Unicode.GetBytes(plainText)

instead of

Encoding.UTF8.GetBytes(plainText)

2/ replacing :

For i = 0 To result.Length – 1
If result(i).ToString.Length = 1 Then
encrypted = encrypted & “0″ & Hex(result(i))
Else
encrypted = encrypted & Hex(result(i))
End If
Next
Return encrypted

with (c# code):

StringBuilder encrypted = new StringBuilder();

for (int i = 0; i <= result.Length – 1; i++)
encrypted.Append(
Convert.ToString(
result[i], 16).PadLeft(2, ’0′).ToUpper());

return encrypted.ToString();

Or if you prefer, let the “if then” test, but instead of testing

result(i).ToString.Length = 1

you have to test

Convert.ToString(result[i], 16).Length = 1

because in case of byte value ’1010′ for example, whose hex representation is “A”, the string representation is “10″ and the leading “0″ isn’t added.

Another tip : if you still have unicode strings, don’t try to convert it again into unicode before calling the Encrypt method…

Justin 55

Taking the DPAPI code, replacing the for loop (see post 47/49) with:

For i = 0 To result.Length – 1
encrypted = encrypted & Convert.ToString(result(i),16).PadLeft(2,”0″).ToUpper()
Next

and then calling the method with:
DPAPI.Encrypt(DPAPI.KeyType.MachineKey, text, Nothing, “psw”)

Yielded successful results. I now have a console app that I can call with a password argument and have it spit out a working .RDP password hash!

Thanks again to everyone who helped figure this out in the comments, especially Daniel and Lolosoph.

56

[...] Shepard converted my code to encrypt RPD passwords to VB.NET: ‘======SOF   Imports System Imports System.Text Imports [...]

jeremy 57

I would really REALLY benefit from a command line version. I’m looking to incorporating something like this into a batch script.

Please please please!

Mike 58

Hey guys,

Has anyone come up with an RDP password encryptor for Windows CE by any chance?

Thanks

Mike

Jan 59

Hi,

I’m using another way of encoding valid rdp-passwordslike this:

Private Shared Function GetEncodedPassword(ByVal password As String) As String
Dim encoded As Byte() = DPAPI.Encrypt(DPAPI.KeyType.UserKey, System.Text.Encoding.Unicode.GetBytes(password), Nothing, Nothing)
Dim temp As String = BitConverter.ToString(encoded).Replace(“-”, “”)
Return temp
End Function

But my question is how to decrypt it back to a readable password. Please share your code to do this.

Thanks,
Jan

Jan 60

OK, got it:

Dim bytes As Byte() = HexToData(TextBox1.Text)
Dim lunicodeencoding As New System.Text.UnicodeEncoding

Dim lDecryptedBytes As Byte() = Unprotect(bytes, Nothing, Security.Cryptography.DataProtectionScope.CurrentUser)

TextBox2.Text = lunicodeencoding.GetString(lDecryptedBytes)

Private Shared Function HexToData(ByVal hexString As String) As Byte()
If hexString Is Nothing Then
Return Nothing
End If
If hexString.Length Mod 2 = 1 Then
hexString = “0″c + hexString ‘ Up to you whether to pad the first or last byte
End If

Dim data As Byte() = New Byte(hexString.Length / 2 – 1) {}
For i As Integer = 0 To data.Length – 1
data(i) = Convert.ToByte(hexString.Substring(i * 2, 2), 16)
Next
Return data
End Function

Jan

JeremyW 61

Thanks Remko for the great article. I needed to have some way of automating the creation of RDP files with the password already included.

After a crash course in VB.NET I was able to put together a utility that gives me the proper hash.

I used http://www.obviex.com/samples/dpapi.aspx and made the suggested changes from Justin and DanielHeth (see comments 47, 49, and 55)

I’ve never written a program before (and I’m not sure you can call what I did “writing a program”) but if anybody wants to use the utility I’ve posted it at this link http://www.petri.co.il/forums/showthread.php?t=25204

BTW – I’m not the same Jeremy as the one above but I believe this is what he is looking for.

Daniel 62

Could someone PLEASE rewrite this code for Windows CE? That would be very very great!! Thanks!

daniel 63

hello
thanks for this solution I created a powershell script wich uses it to create a complete rdp file and it works fine see bellow.
now I need to be able to decrypt the password and this part need the same modification as the encrypt part but I am not a c# specialist so can someone help me to modify this part of the c# code?
I think it is this one

—————-c#——————–
public static string Decrypt( string cipherText,
string entropy,
out string description)
{
// Make sure that parameters are valid.
if (entropy == null) entropy = String.Empty;

return Encoding.UTF8.GetString(
Decrypt( Convert.FromBase64String(cipherText),
Encoding.UTF8.GetBytes(entropy),
out description));
}

powershell script to create a rdp file and launch the TS

powershell code to create a rdp file and launch the terminal session

#———–code begin———————-
$server = Read-Host “enter the server name”
$dll =”./DPAPI.dll”
[void][Reflection.Assembly]::LoadFile($dll)

$secmdp = get-credential
$ptr = [System.Runtime.InteropServices.Marshal]::`
SecureStringToBSTR($secmdp.password)
$mdp = [System.Runtime.InteropServices.Marshal]::`
PtrToStringUni($ptr)

$user = $secmdp.username

$encrypted=[DPAPI]::Encrypt([DPAPI+KeyType]::`
UserKey,$mdp,$null,”psw”)

$fichier =
“screen mode id:i:1
desktopwidth:i:1024
desktopheight:i:768
session bpp:i:16
winposstr:s:2,3,169,96,1201,897
full address:s:$server
compression:i:1
keyboardhook:i:2
audiomode:i:0
redirectdrives:i:1
redirectprinters:i:0
redirectcomports:i:0
redirectsmartcards:i:1
displayconnectionbar:i:1
autoreconnection enabled:i:1
username:s:$user
alternate shell:s:
shell working directory:s:
disable wallpaper:i:1
disable full window drag:i:1
disable menu anims:i:1
disable themes:i:0
disable cursor setting:i:0
bitmapcachepersistenable:i:1
password 51:b:$encrypted

Set-Content -path “./$server.rdp” -Value $fichier
mstsc “./$server.rdp”
Start-Sleep -Seconds 2
Remove-Item “./$server.rdp”

#————-end of code ————————

abdul jalil 64

i have made the programe in VC that generate hash for admin is
01000000D08C9DDF0115D1118C7A00C04FC297EB01000000E73580BB89962146AF1BFB1D1447A54500000000340000004C006900620070007500720070006C00650020005300650063007500720065002000500061007300730077006F0072006400000003660000A8000000100000005E9CF384DFD13810017BC4DA02F5C2620000000004800000A000000010000000ACB8381A053457FF958EA2582AC7FE8D08000000911206F22AB76EE614000000025EE3F451A6B5AB9FE61E60B2B7F2A460D692EE

and i decript form ur software it give me “??” text . cam u give me the code how to decript

AskQ 65

Hi,

I have the password encryption in Windows, but it doesn’t work for Mac, I am using Mac to connect to windows through RDP. Everything works fine except I have to use clear text password, such as:

clear password:s:ssl

Not this on MAC (Windows is fine):
password 51:b:01000000D08C9DDF0115D1118C7A00C04FC297EB010000002297DDAFF6F9064D948A19CE48E83E810400000008000000700073007700000003660000A800000010000000EDB1E62CFD5EF09EAC46111D6794E8710000000004800000A00000001000000036F12B9702F981F8B16D8407EF0B2B95080000001A3094F22CD138EC14000000BF9F4CDB1EEAA4846DE9E390691D43B0A8FDB380

Any idea for encrypting RDP password on MAC ??

Thanks a lot

HLT 66

bonjours,
je veux crypter une image pixel par pixel utilisant la librairie lockbox sous delphi, j’ai cree le code suivant:
.
.

.procedure TMainForm.btncptClick(Sender: TObject);
var ImgCpt:TMDIChild;
Str,StrC:String;
i,j:Integer;
P:PByteArray;
cl:BytePixel;
R:RealPixel;

begin
//Apparence de l’enfant ImgCpt
ImgCpt:=(ActiveMDIChild as TMDIChild);
Str:=’Image cryptée’;

//transfert des pixels de l’image vers la zone memoire
for j:=0 to ht-1 do
begin
for i:=0 to wd-1 do
begin
cl:=getrvalue(ImgCpt.Image1.Picture.Bitmap.Canvas.Pixels[i,j]);
setbyte(cl,Pimt,i+j*wd);
end;
end;

//traitement (cryptage de l’image)
for j:=0 to ht-1 do
begin
for i:=0 to wd-1 do
begin
cl:=getbyte(Pimt,i+j*wd);
StrC:=IntToStr(cl); //Contiendra la valeur cryptée (0…..255)
StrC:=LbRijndael1.EncryptString(StrC);//cryptage avec la composant AES
//StrC=’ fgC7VcLjPJc05ejq30gOvA==’ pour cl=255 (exemple)
Edit2.Text:=StrC; //Pour le test
ShowMessage(”); //Pour le test
Cl:=StrtoInt(strc); //pas efficace ………….(*)
//le text strc=’ fgC7VcLjPJc05ejq30gOvA==’ doit etre converti en integer!!!!! maiiiiiiiis //comment
setrealtype(cl,Pimt,i+j*wd);
end;
end;
//Affichage
PointerToBitmap1(Pimt,p,0,ImgCpt,Str);
ImgCpt.Invalidate;
end;
le probleme se pose à la ligne (*) pour convertir le text en Byte.
svp, Puvez vous m’aidez c’est pour mon projet de fin d’etude
Merci d’avance.

K.O. 67

hi remko
Thanks for the knowledge , I am trying to implement a very simple c program that will take plain text password
and encript it (first do the conversion to unicode ,hash , and finally encrypt) I need a very siple C function for encription only.

I find reverse engeneering your Java/VB programs is a little dificlt , I will be gratfull if you could help.

Thanks.
K.O.

Michael Hollinger 68

I am trying to make this work for Windows CE 5.0. I don’t believe cryptprotectdata API exists on Windows CE 5.0.
I can, however, use Cryptology.ProtectedData.ProtectData.

Does anyone know of a way to use this function to get the same result as above?

Chip Forster 69

The following C# version works for me when I add the resulting encrypted password to an .rdp file.
Please feel free to remove/replace post 69 or at least the source code within it. I’m not sure what “Your comment is awaiting moderation.” means.
Thanks.

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Security.Cryptography;
using System.Linq;
using System.Text;

namespace mstscpw
{
class Mstscpw
{
private const int CRYPTPROTECT_UI_FORBIDDEN = 0×1;
// Wrapper for the NULL handle or pointer.
static private IntPtr NullPtr = ( ( IntPtr ) ( ( int ) ( 0 ) ) );
// Wrapper for DPAPI CryptProtectData function.
[DllImport ( "crypt32.dll", SetLastError = true,
CharSet = System.Runtime.InteropServices.CharSet.Auto )]
private static extern bool CryptProtectData (
ref DATA_BLOB pPlainText,
[MarshalAs ( UnmanagedType.LPWStr )]string szDescription,
IntPtr pEntroy,
IntPtr pReserved,
IntPtr pPrompt,
int dwFlags,
ref DATA_BLOB pCipherText );
// BLOB structure used to pass data to DPAPI functions.
[StructLayout ( LayoutKind.Sequential, CharSet = CharSet.Unicode )]
internal struct DATA_BLOB
{
public int cbData;
public IntPtr pbData;
}

private static void InitBLOB ( byte[] data, ref DATA_BLOB blob )
{
blob.pbData = Marshal.AllocHGlobal ( data.Length );
if ( blob.pbData == IntPtr.Zero )
throw new Exception ( “Unable to allocate buffer for BLOB data.” );

blob.cbData = data.Length;
Marshal.Copy ( data, 0, blob.pbData, data.Length );
}

public string encryptpw ( string pw )
{
byte[] pwba = Encoding.Unicode.GetBytes ( pw );
DATA_BLOB dataIn = new DATA_BLOB ( );
DATA_BLOB dataOut = new DATA_BLOB ( );
StringBuilder epwsb = new StringBuilder ( );
try
{
try
{
InitBLOB ( pwba, ref dataIn );
}
catch ( Exception ex )
{
throw new Exception ( “Cannot initialize dataIn BLOB.”, ex );
}

bool success = CryptProtectData (
ref dataIn,
“psw”,
NullPtr,
NullPtr,
NullPtr,
CRYPTPROTECT_UI_FORBIDDEN,
ref dataOut );

if ( !success )
{
int errCode = Marshal.GetLastWin32Error ( );
throw new Exception ( “CryptProtectData failed.”, new Win32Exception ( errCode ) );
}

byte[] epwba = new byte[dataOut.cbData];
Marshal.Copy ( dataOut.pbData, epwba, 0, dataOut.cbData );
// Convert hex data to hex characters (suitable for a string)
for ( int i = 0; i < dataOut.cbData; i++ )
epwsb.Append ( Convert.ToString ( epwba[i], 16 ).PadLeft ( 2, ’0′ ).ToUpper ( ) );
}
catch ( Exception ex )
{
throw new Exception ( “unable to encrypt data.”, ex );
}
finally
{
if ( dataIn.pbData != IntPtr.Zero )
Marshal.FreeHGlobal ( dataIn.pbData );

if ( dataOut.pbData != IntPtr.Zero )
Marshal.FreeHGlobal ( dataOut.pbData );
}
return epwsb.ToString ( );
}
}
// Test code:
class program
{
static void Main ( string[] args )
{
Mstscpw mstscpw = new Mstscpw ( );
string epw = mstscpw.encryptpw ( “password” );
Console.WriteLine ( “Encrypted password for \”password\” {0} characters: \r\n{1}”, epw.Length, epw );
Console.ReadLine ( );
}
}
}

Suren 70

hi abdul,
Can u share the VC code with me.

amir 71

hi

when i click decrypt, an error load as result :

error decrypting : the data is invalid.

or :

error decrypting : key not valid for use in specified state.

how to decrypt ? ?

if it works why show me errors.

Remko 72

Amir, please provide some more details:
Are you decrypting a key that was encrypted by the tool or an existing password from an rdp file. If it’s from an rdp file did the same windows user (on the same machine) encrypt it?

amir 73

no its an existing password on my RDP file in my document folder, i’m just testing, and i wanna know really anyone can decrypt it !

like this :
password 51:b:01000000D08C9DDF0115D1118C7A00C04FC297EB0100000090B029B6432BC8469DA2FAFA1AB328670000000008000000700073007700000003660000A800000010000000BEFAB53C2E5CB63E70E91FC1FD2DD6E60000000004800000A00000001000000077BFEB9C6D347E2934A1B8C80073674308020000128F00CFBDB8F5D1817C2E767A2BF57ABBEE92AC692AA581C800E9A2C6E349A69559493DE04AC0784A4FEA642835DEB5C2502FB07953A03A211A90A1F91D0DA634533949FE0E135C18F46435129503AF98F80BF07AF554A71ACFDD7E456ED6D58F9372BDD4838CFD3B6CE1BCE9F9763B5B191E4E4CA1A7B449EEB99A90B1C14B2802AF0D912DB7492B7A2984465F3C95D36B3EFB338F6D56491F555F86548D4C82DF76408F264F9DD06E44FB793D983BB6EBEEE271BADD6873D52DB0FD293857C74BD111A33C27A1017486E1053D44E3A056F520651793090532713064E0838FE604C1F3FABF372CB84FB6B97F96A4681A24BC509ECD25455FA347B90EBF020FE7584309A69539DE6179201BA22805A727A8858AAD81F809C34CFA565494095B79F7AE3276EA748FC949146BDBED54944417431680B52012BAEC3AB67C2A59D751F0CC5B0E75B6F9A0F45BAF0B9FBD97E1AA9D7028207F5AA01B70B5D0224E6D7A9B2E2A155445224EA36DCA0D03876B9DF451C53B546A2D444F6AF1D33929B65CB1BC254A6D0C2E92A472FC14BCBD3F9FC4DE0638C82ED62DFD5CBECDD587BDAD45CDC3050DC47700D3CA6543B47971D2B81FD81A42D85CE7318DFB76B10FEE785A7D24FC2C998095E391AE192E839E3886422E6719F42D0517D11CB17E4FF918010CC59B3064C087E52B8EF4C7D869B97FFE306C49E4BD0BD2FF60FEBAF1EE3F1B3800621D55A91400000011AF335B5BACED71A13676BA4C88C332F4D8B1AC0

Glenn 74

amir,
I just double checked and triple checked. A password encrypted on one workstation is not portable to another, even for the same user in the domain. The encryption using CryptProtectData is specific to machine/user only.

Ata 76

Why does my RDP file from Windows Vista SP1 does not contain “password 51:b:”?

Does your tool no longer work?

Remko 77

@Ata: The 6.0 client version no longer saves passwords in the rdp file. However it can still read passwords already stored in rdp file. I use a patched version of the old client (v4) that can be used together with the v6 version.

Stewart Grainger 79

On my VB 2005 app I have on page load:

Dim strHashCode
strHashCode = “Secret”
Me.txtHashKey.Text = DPAPI.Encrypt(DPAPI.KeyType.UserKey, strHashCode, Nothing, “pwd”)

This populates a textbox named txtHashKey with the encrypted text but how do I get this to what is reconised by RDP files…?

Stewart

80

[...] and now, I want to show  you how to make your job even easier!  I  ran across this blog, and downloaded his RDP password Hash program.  It got me thinking, I could make my job easier [...]

EverydayNerd 81

Hello! I found your rdp password hash very useful! I’ve incorporated it into a script I wrote to create rdp files. Take a look here: http://everydaynerd.com/microsoft/save-password-in-rdp-file

Thanks again, and enjoy!

Nullstring 82

@ChipForster

How do you decrypt that? You C# code working just fine. Can you share your Decrypt Method too?

micingamja 83

thanks a lot.

jerome 84

This source is working very fine for me ! So use it without restriction. If it can help !

DATA_BLOB DataIn, DataOut;
WCHAR pwDescription [7];
PWCHAR pwPassword;
CString PwdHash;
LPCSTR desc = “psw”;

PwdHash = “”;
DataOut.cbData = 0;
DataOut.pbData = NULL;

pwPassword = (WCHAR *) LocalAlloc (LPTR, passwd.GetLength () * sizeof (WCHAR));
MultiByteToWideChar (CP_ACP, 0, passwd, passwd.GetLength (), pwPassword, passwd.GetLength () * sizeof (WCHAR));

// RDP uses UniCode
DataIn.pbData = (BYTE *) pwPassword;//(BYTE *) (LPWSTR) passwd.GetBuffer (passwd.GetLength ());
DataIn.cbData = passwd.GetLength () * sizeof(WCHAR);

// RDP always sets description to psw
MultiByteToWideChar (CP_ACP, 0, desc, 3, pwDescription, 3 * sizeof (WCHAR));

if (CryptProtectData (&DataIn,
pwDescription,
NULL,
NULL,
NULL,
CRYPTPROTECT_UI_FORBIDDEN, // Never show interface
&DataOut) )
{
CString encryptedData;
BYTE* pb;
pb = DataOut.pbData;

for(DWORD i =0; i != DataOut.cbData; i++)
{
unsigned char ch =*pb;
unsigned char ch0 = ch & 0xf0;
ch0 = (ch>>4) & 0x0F;
unsigned char ch1 = ch & 0x0F;

encryptedData.AppendFormat(_T(“%x%x”),ch0,ch1);
pb++;
}
// PwdHash est le mot de passe encodé en hexadécimal pour être utilisable par le RDP de Microsoft.
PwdHash = encryptedData;
}
/*
// Ceci est pour tester le décryptage de la donnée re?ue.
LPWSTR pDescrOut = NULL;
CryptUnprotectData (&DataOut,
&pDescrOut,
NULL,
NULL,
NULL,
CRYPTPROTECT_UI_FORBIDDEN,
&DataIn);*/

LocalFree (DataOut.pbData);
LocalFree (DataIn.pbData);

return PwdHash;

jerome 85

in my last comment i omitted to say that i created a function with one parameter names passwd of CString type.

This function is coded in C++.

Bernd Schnitzer 86

First of all, thanks for sharing this.

A friend of mine was developing an intranet web application that lists all customers with additional information on how to access their servers. He asked me for help in writing a small utility that opens a rdp connection via a button click. I ended up with a signed java applet that gets the encrypted rdp password through JNI. A javascript function calls the “create rdpfile” method in the applet.

I rewrote your Delphi-Code in C++ and than I got stuck for hours. Your tool and my library yield to different results. So I did some debugging on your tool and the good old OllyDbg showed up that the dwFlags Parameter in your tool is as follows:
CRYPTPROTECT_UI_FORBIDDEN|CRYPTPROTECT_LOCAL_MACHINE

After this change my code was running smoothly.

Bernd

jacky 87

dear jerome,
can you share the source code ?

None 88

Folks,

I’m trying to create a program to generate .rdp files, but my password encryptation code is not working, it just encrypt the first character of any string. Can you help me?

Source Code
+++++++++++++++++++++++++++++++++++++++
int main(){

FILE *f;
int count =0;
char *enc;
DATA_BLOB DataIn;
DATA_BLOB DataOut;
LPWSTR description = NULL;
LPWSTR pwd = L”password”;
DataIn.pbData = (BYTE *)pwd;

if (DataIn.pbData == NULL) {
return 1;
}

f=fopen(“c:\\temp.txt”,”wb”);

DataIn.cbData = (DWORD)strlen((const char*)DataIn.pbData) + 1;

if (CryptProtectData(&DataIn,(LPCWSTR)L”password”,NULL,NULL,NULL,CRYPTPROTECT_UI_FORBIDDEN,&DataOut)){
enc=(char*)calloc(DataOut.cbData*2,1);
for (count=0; count < DataOut.cbData; count++)
sprintf(enc, “%s%02X”, enc, DataOut.pbData[count]);
fprintf(f,”%s”, enc);
LocalFree(DataOut.pbData);
}else{
printf(“Sorry!\n”);
}
fclose(f);
return 0;
}
++++++++++++++++++++++++++++++++++++++
EOF

Thanks

Remko 89

@None: I think the error is here:
DataIn.cbData = (DWORD)strlen((const char*)DataIn.pbData) + 1;

Your input is a Unicode string but you give the count of chars in instead of bytes
try
DataIn.cbData = (DWORD)strlen((const char*)DataIn.pbData) * sizeof(WCHAR); (I don’t think you need to account for the 0 terminator)

None 90

Thanks for your help.

Actually, the error occurs on (DWORD)strlen((const char*)DataIn.pbData), it always returns 1. In my new code I’m passing a string as argument, so I’m using the strlen from the string itself.

My new code:
+++++++++++++++++++++++++++++++++++++
int main(int argc, char **argv){
FILE *f;
DATA_BLOB in, out;
BYTE *pbDataInput2;
BYTE pbDataInput[1024];

pbDataInput2=argv[1];

MultiByteToWideChar(CP_ACP,0,pbDataInput2,strlen(pbDataInput2)+1,pbDataInput,1024);

DWORD cbDataInput = strlen(argv[1])*sizeof(WCHAR);
in.pbData=pbDataInput;
in.cbData=cbDataInput;
CryptProtectData(&in,L”psw”,NULL,NULL,NULL,CRYPTPROTECT_UI_FORBIDDEN,&out);

f=fopen(“c:\\temp.txt”,”wb”);

char* encPass=(char*)calloc(out.cbData*2,1);
int count=0;
while (count < out.cbData){
sprintf(encPass,”%s%02X”,encPass,out.pbData[count]);
count++;
}
fprintf(f,”%s”,encPass);
fclose(f);

}
++++++++++++++++++++++++++++++++++++
EOF

Regards,
None

Martijn 91

This is my C# version.

You can call the function with this code:

byte[] cryptBytes = CryptPassword.DoRawEncryption(Password);
EncryptedPassword = Encoding.UTF8.GetString(cryptBytes);
EncryptedPassword = BitConverter.ToString(cryptBytes).Replace(“-”, “”);

And this is the function:

internal static class CryptPassword
{
#region KeyType enum

public enum KeyType
{
UserKey = 1,
MachineKey
} ;

#endregion

private const int CRYPTPROTECT_LOCAL_MACHINE = 0×4;
private const int CRYPTPROTECT_UI_FORBIDDEN = 0×1;
private static readonly IntPtr NullPtr = ((IntPtr)((0)));
private static KeyType defaultKeyType = KeyType.UserKey;

public static byte[] DoRawEncryption(string strToEncrypt)
{
byte[] cryptBytes = Encrypt(KeyType.UserKey, Encoding.UTF8.GetBytes(strToEncrypt), null, null);

return cryptBytes;
}

// Wrapper for DPAPI CryptProtectData function.
[DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool CryptProtectData(ref DATA_BLOB pPlainText, string szDescription, ref DATA_BLOB pEntropy, IntPtr pReserved, ref CRYPTPROTECT_PROMPTSTRUCT pPrompt, int dwFlags, ref DATA_BLOB pCipherText);

// Wrapper for DPAPI CryptUnprotectData function.
[DllImport("crypt32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool CryptUnprotectData(ref DATA_BLOB pCipherText, ref string pszDescription, ref DATA_BLOB pEntropy, IntPtr pReserved, ref CRYPTPROTECT_PROMPTSTRUCT pPrompt, int dwFlags, ref DATA_BLOB pPlainText);

// BLOB structure used to pass data to DPAPI functions.

private static void InitPrompt(ref CRYPTPROTECT_PROMPTSTRUCT ps)
{
ps.cbSize = Marshal.SizeOf(typeof(CRYPTPROTECT_PROMPTSTRUCT));
ps.dwPromptFlags = 0;
ps.hwndApp = NullPtr;
ps.szPrompt = null;
}

private static void InitBLOB(byte[] data, ref DATA_BLOB blob)
{
// Use empty array for null parameter.
if (data == null)
data = new byte[0];

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

// Make sure that memory allocation was successful.
if (blob.pbData == IntPtr.Zero)
throw new Exception(
“Unable to allocate data buffer for BLOB structure.”);

// Specify number of bytes in the BLOB.
blob.cbData = data.Length;

// Copy data from original source to the BLOB structure.
Marshal.Copy(data, 0, blob.pbData, data.Length);
}

public static string Encrypt(string plainText)
{
return Encrypt(defaultKeyType, plainText, String.Empty, String.Empty);
}

public static string Encrypt(KeyType keyType, string plainText)
{
return Encrypt(keyType, plainText, String.Empty, String.Empty);
}

public static string Encrypt(KeyType keyType, string plainText, string entropy)
{
return Encrypt(keyType, plainText, entropy, String.Empty);
}

public static string Encrypt(KeyType keyType, string plainText, string entropy, string description)
{
// Make sure that parameters are valid.
if (plainText == null) plainText = String.Empty;
if (entropy == null) entropy = String.Empty;

// Call encryption routine and convert returned bytes into a base64-encoded value.
return Convert.ToBase64String(Encrypt(keyType, Encoding.UTF8.GetBytes(plainText), Encoding.UTF8.GetBytes(entropy), description));
}

public static byte[] Encrypt(KeyType keyType, byte[] plainTextBytes, byte[] entropyBytes, string description)
{
// Make sure that parameters are valid.
if (plainTextBytes == null) plainTextBytes = new byte[0];
if (entropyBytes == null) entropyBytes = new byte[0];
if (description == null) description = String.Empty;

// Create BLOBs to hold data.
DATA_BLOB plainTextBlob = new DATA_BLOB();
DATA_BLOB cipherTextBlob = new DATA_BLOB();
DATA_BLOB entropyBlob = new DATA_BLOB();

// We only need prompt structure because it is a required
// parameter.
CRYPTPROTECT_PROMPTSTRUCT prompt = new CRYPTPROTECT_PROMPTSTRUCT();
InitPrompt(ref prompt);

try
{
// Convert plaintext bytes into a BLOB structure.
try
{
InitBLOB(plainTextBytes, ref plainTextBlob);
}
catch (Exception ex)
{
throw new Exception(“Cannot initialize plaintext BLOB.”, ex);
}

// Convert entropy bytes into a BLOB structure.
try
{
InitBLOB(entropyBytes, ref entropyBlob);
}
catch (Exception ex)
{
throw new Exception(“Cannot initialize entropy BLOB.”, ex);
}

// Disable any types of UI.
int flags = CRYPTPROTECT_UI_FORBIDDEN;

// When using machine-specific key, set up machine flag.
if (keyType == KeyType.MachineKey)
flags |= CRYPTPROTECT_LOCAL_MACHINE;

// Call DPAPI to encrypt data.
bool success = CryptProtectData(ref plainTextBlob, description, ref entropyBlob, IntPtr.Zero, ref prompt, flags, ref cipherTextBlob);
// Check the result.
if (!success)
{
// If operation failed, retrieve last Win32 error.
int errCode = Marshal.GetLastWin32Error();

// Win32Exception will contain error message corresponding to the Windows error code.
throw new Exception(“CryptProtectData failed.”);
}

// Allocate memory to hold ciphertext.
byte[] cipherTextBytes = new byte[cipherTextBlob.cbData];

// Copy ciphertext from the BLOB to a byte array.
Marshal.Copy(cipherTextBlob.pbData, cipherTextBytes, 0, cipherTextBlob.cbData);

// Return the result.
return cipherTextBytes;
}
catch (Exception ex)
{
throw new Exception(“DPAPI was unable to encrypt data.”, ex);
}
// Free all memory allocated for BLOBs.
finally
{
if (plainTextBlob.pbData != IntPtr.Zero)
Marshal.FreeHGlobal(plainTextBlob.pbData);

if (cipherTextBlob.pbData != IntPtr.Zero)
Marshal.FreeHGlobal(cipherTextBlob.pbData);

if (entropyBlob.pbData != IntPtr.Zero)
Marshal.FreeHGlobal(entropyBlob.pbData);
}
}

#region Nested type: CRYPTPROTECT_PROMPTSTRUCT

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct CRYPTPROTECT_PROMPTSTRUCT
{
public int cbSize;
public int dwPromptFlags;
public IntPtr hwndApp;
public string szPrompt;
}

#endregion

#region Nested type: DATA_BLOB

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct DATA_BLOB
{
public int cbData;
public IntPtr pbData;
}
#endregion
}

Martijn 92

I can’t figure out how to convert it to a full length mstsc password. Are there any ideas to do this?

93

[...] que esta encriptada. Para crear el String de password encriptado debemos usar una herramienta de Remko Weijnen La pueden bajar de aquí  Remote Desktop Password Encryption & Decryption Tool  [...]

Dave 94

Hi

Im trying to do this in VB6, but Im not getting a valid result. Can someone tell me where I am going wrong.

Email me on thompsdc AT gmail DOT com

Here is the code I’ve done…
———————————————————————
Option Explicit

Private Type DATA_BLOB
cbData As Long
pbData As Long
End Type

Private Declare Sub CopyMemory Lib “kernel32″ Alias “RtlMoveMemory” ( _
hpvDest As Any, _
hpvSource As Any, _
ByVal cbCopy As Long)

Private Declare Function CryptProtectData Lib “crypt32.dll” ( _
ByRef pDataIn As DATA_BLOB, _
ByVal szDataDescr As String, _
ByRef pOptionalEntropy As Any, _
ByRef pvReserved As Any, _
ByRef pPromptStruct As Any, _
ByVal dwFlags As Long, _
ByRef pDataOut As DATA_BLOB) As Long

Public Function CryptRDPPassword(spPassword As String) As String
Dim aDataIn() As Byte
Dim udtDataIn As DATA_BLOB
Dim r As Long
Dim udtDataOut As DATA_BLOB
Dim aDataOut() As Byte
Dim s$, i&

aDataIn = StrConv(spPassword, vbUnicode)
udtDataIn.cbData = UBound(aDataIn) + 1
udtDataIn.pbData = VarPtr(aDataIn(0))

‘StrConv(“psw”, vbUnicode),
r = CryptProtectData(udtDataIn, _
“psw”, _
ByVal vbNullString, _
ByVal vbNullString, _
ByVal vbNullString, _
0, _
udtDataOut)

If r Then
ReDim Preserve aDataOut(udtDataOut.cbData)
CopyMemory aDataOut(0), ByVal udtDataOut.pbData, udtDataOut.cbData

s = “”
For i = 0 To udtDataOut.cbData – 1
s = s & Format(Hex(aDataOut(i)), “00″)
Next
CryptRDPPassword = s
Else
CryptRDPPassword = “Nothing”
End If
End Function

Ben 95

Hello
I search for a ASP or PHP version of this code. I hope to build a web rdp-generator and use it with a form in an intranet. The password generation is the only piece that i miss.

@JW 96

Hi,

I am using an intranet link to startup an RDP (stored on a network drive) using a batch file. I would like to start the RDP without creating it on the users desktop.

I do not mind if the users know the password, I am just trying to eliminate the need for them to enter it when starting the RDP.

Can I somehow use this solution to program the batch file to open the RDP and automatically add in the password for the specific user?

Thanks

ankireddy 97

Hi Every Body,

I am searching java based application for the same.

please help me..

DP 98

Is there a fix or workaround for RDP 6.0? The Hash tool does not seem to work.

Martin 99

asp w?re auch für uns interessant

Dave 100

this one is too good buddy, all good.thanks for that.

pramish 101

can any1 mail me win32crypt.py or provide link for this file?
cant find module re while importing!!
mail me @
thanks

Donkz 102

Hi everybody,

With the help of all the information from over here and at Obviex, I’ve managed to write my own ‘login to Remote Desktop automatically from the command line’ utility, with some extra features. I wrote it for myself, but maybe other people will alsof find it useful. If anybody is interested, it can be found at http://www.donkz.nl/?p=58.

103

[...] need a way to encrypt your password for storage in the .rdp file.  The small application at this blog will help.  For help with each of the settings, check out this Microsoft [...]

Eli 104

You are a super star, all what I needed is working now.
I have to automate remote desktop connection for number of users and it is working thanks to you.
Well done.

dan 105

if you have an vbscript vesion for encrypt function please post it here

Serge 106

Hi,

I try to compile your source with Delphi 7 and it doesn’t compile because the compiler don’t know the DATA_BLOB type and CryptProtectData() function.

What unit should I use in the Uses line please ?

Thanks

Serge

pchicociv 107

Hi! Have you tried this script to connect to a Windows Server 2008? I understand that you can no longer send username and password in the rdp file.

水樹奈々 108

Thanks for sharing this useful post.

Suraj Raj Bhandari 109

Can You provide it’s implementation in VB Script also

Suraj Raj Bhandari 110

Provided exe can work through command prompt ??

nighteblis 111

I tested the example rdp file in vista home and xp professional . But does NOT work in xp professional. It still need to type in the password. So I think this is caused by the mstsc version or os security?

112

[...] Program is compiled by the program, Delphi attribute found the home page:http://remkoweijnen.nl/blog/2007/10/18/how-rdp-passwords-are-encrypted/ [...]


Leave a reply
Recent TweetsRT @plompr: Today I work 4 years for PepperByte. Thank-you #PepperByte and #PepperCrew< Congrats! (hoe laat ben je in Gouda met het gebak?) 2 hours ago

Site Admin | powered by WordPress | Theme




引文来源   How rdp passwords are encrypted
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值