Jump to content

Password Encryption


Recommended Posts

I am in need of hashing out my passwords in scripts, but in order to do this I need to understand the code that I use and that it works ok. I have created a couple of test scripts to help me do this, but I am having some issues with these.

The first script (works fine), I obtained from the examples and modified it slightly:

#include <GUIConstantsEx.au3>
#include <EditConstants.au3>
#include <WindowsConstants.au3>
#include <Crypt.au3>
#include <WinAPI.au3>
; Example of realtime RC4 encryption
$hWnd=GUICreate("Realtime Encrypting",400,300,-1)
$hInputEdit=GUICtrlCreateEdit("",0,0,400,150,$ES_WANTRETURN)
$hOutputEdit=GUICtrlCreateEdit("",0,150,400,150,$ES_READONLY)
GUIRegisterMsg($WM_COMMAND,"WM_COMMAND")
GUISetState(@SW_SHOW)

Do
 $msg=GUIGetMsg()
Until $msg=$GUI_EVENT_close
Func WM_COMMAND($hWinHandle,$iMsg,$wParam,$lParam)
 ; If something was changed in the input editbox
 If _WinAPI_HiWord($wParam)=$EN_CHANGE And _WINAPI_LoWord($wParam)=$hInputEdit Then
  $bEncrypted = _Crypt_HashData(GUICtrlRead($hInputEdit),$CALG_MD5)
  GUICtrlSetData($hOutputEdit,$bEncrypted)
 EndIf
EndFunc

So with the above script I can get a hashed password, which I then embed in my script.

I then used the script below to confirm it is reading a cleartext password and able to convert it to the hash password in my script. This part works.

#include <Crypt.au3>
; Example of hashing data and using it to authenticate password
; This is the MD5-hash of the correct password
$bPasswordHash="0xE10ADC3949BA59ABBE56E057F20F883E"
$bPassword = Binary("0xE10ADC3949BA59ABBE56E057F20F883E")
$sPassword=InputBox("Login","Please type the correct password.","","*")
$password = _Crypt_HashData($sPassword,$CALG_MD5)
If $password = $bPasswordHash Then
MsgBox(64,"Access Granted","Password correct!" & @CRLF & BinaryToString($bPassword))
Else
MsgBox(16,"Access Denied","You entered the wrong password!")
EndIf

What I need to do and have tried in the example above is convert my hash password into a cleartext string, so when I send the password with out programs it works.

I was hoping the Binary function would work, but I am obviously misunderstanding it.

Can someone offer me any help/advice please?

Thanks,

Jeff

Link to comment
Share on other sites

Hi,

I am not sure what you mean by...

What I need to do and have tried in the example above is convert my hash password into a cleartext string, so when I send the password with out programs it works.

...but a hash is one-way, you can not just 'decrypt' it.

About the script, _Crypt_HashData returns a binary string, you can just store it as string and then compare it.

#include <Crypt.au3>

; Password=password
; Example of hashing data and using it to authenticate password
; This is the MD5-hash of the correct password
$bPasswordHash = '0x5F4DCC3B5AA765D61D8327DEB882CF99'
$sPassword = InputBox("Login", "Please type the correct password.", "", "*")
$bPassword = _Crypt_HashData($sPassword, $CALG_MD5)
If $bPassword = $bPasswordHash Then
    MsgBox(64, "Access Granted", "Password correct!")
Else
    MsgBox(16, "Access Denied", "You entered the wrong password!")
EndIf
Link to comment
Share on other sites

Thanks for the quick response Robjong.

I understand. I didn't realise a hash couldn't just be decrypted, as stupid as that sounds! :-)

Well let me present what my actual goal is and maybe you or someone else has an idea for how I can do this.

I work for a school and those kids are curious souls! I have a script that I use along with WDS and after imaging the machine, creating a grub menu, creating a restore partition and setting up the profile, the machine will attempt to join the domain if they have an IP in our subnet. The script works great, but what I don't want, or I am hoping to avoid, is have a cleartext password sitting in my exe. The thing I worry is if a student figures out how to decompile the exe and then a password with domain rights is out there.

Here is my script, well at least the function that joins the domain:

Func _JoinDomainWMI()
Const $JOIN_DOMAIN = 1
Const $ACCT_CREATE = 2
Const $ACCT_DELETE = 4
Const $WIN9X_UPGRADE = 16
Const $DOMAIN_JOIN_IF_JOINED = 32
Const $JOIN_UNSECURE = 64
Const $MACHINE_PASSWORD_PASSED = 128
Const $DEFERRED_SPN_SET = 256
Const $INSTALL_INVOCATION = 262144
Const $OU = "OU=" & $selSchool1 & ",OU=1to1,OU=Workstations,DC=domain,DC=net"
$strDomain = "domain.net"
$strPassword = "Password"
$strUser = "username"
$strComputer = @ComputerName
$objComputer = ObjGet("winmgmts:{impersonationLevel=Impersonate}!" & _
   $strComputer & "rootcimv2:Win32_ComputerSystem.Name='" _
    & $strComputer & "'")
$ReturnValue = $objComputer.JoinDomainOrWorkGroup($strDomain, _
   $strPassword, _
   $strDomain & "" & $strUser, _
   $OU, _
   $JOIN_DOMAIN + $ACCT_CREATE)
EndFunc   ;==>_JoinDomainWMI

I think If I send the hash password to AD, it's not going to understand it and think the password is wrong, so this is why I wanted to store the password hash, but also have it decrypt it in the script so the cleartext password isn't visible.

Hopefully my final goal makes sense.

Edited by jazzyjeff
Link to comment
Share on other sites

I have a similar situation but using sysprep from Microsoft to join the XP machines to our student's domain. Sysprep doesn't encrypt the password for joining the systems to the domain, so the password is visible if anyone manages to access the C: drive, they're blocked from seeing it in My Computer but you can get there through the command line.

What I did to get past this is to create a unique user account that has the rights to join an unlimited number of computers to the domain, the standard users can join up to 10 even if not admins, but this user has no log in rights or any other rights on any of the systems. It's a workaround that works here.

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

Storing any sensitive information, let alone passwords of this nature, in AutoIt scripts is a bad idea to say the least.

AutoIt scripts can be decompiled and any information contained inside will be exposed, obfuscation does nothing to help this, it just makes it a little harder.

If you would encrypt the information and the script does not require human interaction the key has to be stored which renders the encryption worthless.

One possible implementation of encryption could be to save the password as an encrypted string, then store the encryption key as a hash.

When the script starts, the user enters the key which we match against the stored hash, if successful assign the encryption key to a variable, this variable can then be used to decrypt the password.

However we can not consider this approach to be very secure. (the password is stored in memory and the hash can be cracked with the use of rainbow tables for example etc.)

Example script:

#include <Crypt.au3>


_Crypt_Startup()

; Password=password
; Key=secret
;~ ConsoleWrite("Global $sPasswordCT = '" & _Encrypt("password", "secret") & "'" & @CRLF) ; DO NOT FORGET TO REMOVE THIS LINE
;~ ConsoleWrite("Global $sPasswordHash = '" & _Crypt_HashData("password", $CALG_SHA1) & "'" & @CRLF) ; DO NOT FORGET TO REMOVE THIS LINE

Global $sPasswordCT = '0x3F10544A42DE8D16C2C590C20640A00D'
Global $sPasswordHash = '0x5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD8'
Global $sJoinDomainPassword = ''

If _PromptPassword() Then
    $sJoinDomainPassword = _Decrypt("password", $sPasswordCT)
    ConsoleWrite("ct=" & $sJoinDomainPassword & @CRLF)
    MsgBox(64, "Access Granted", "Decrypted key: " & $sJoinDomainPassword)
    ; use the password...
    $sJoinDomainPassword = ''
Else
    MsgBox(16, "Access Denied", "Invalid password!")
    Exit
EndIf

_Crypt_Shutdown()


Func _PromptPassword()
    Local $sPassword = InputBox("Login", "Please type the correct password.", "", "*")
    Local $bPassword = _Crypt_HashData($sPassword, $CALG_SHA1)
    If $bPassword == $sPasswordHash Then
        Return True
    Else
        Return False
    EndIf
EndFunc

Func _Decrypt($sKey, $sData)
    Local $hKey = _Crypt_DeriveKey($sKey, $CALG_AES_256)
    Local $sDecrypted = BinaryToString(_Crypt_DecryptData(Binary($sData), $hKey, $CALG_USERKEY))
    _Crypt_DestroyKey($hKey)
    Return $sDecrypted
EndFunc

Func _Encrypt($sKey, $sData)
    Local $hKey = _Crypt_DeriveKey($sKey, $CALG_AES_256)
    Local $bEncrypted = _Crypt_EncryptData($sData, $hKey, $CALG_USERKEY)
    _Crypt_DestroyKey($hKey)
    Return $bEncrypted
EndFunc

I think a workaround like BrewManNH suggested might be your best option, maybe in combination with something like this.

Edited by Robjong
Link to comment
Share on other sites

You guys are awesome! Thank you both.

The account we had in the script is already locked down to purely join machines to the domain, but I still wanted the password to be hashed out if possible. Your _Decrypt() function did the trick Robjong.

I don't need all the entering of passwords, but that was obviously great for testing and helps me understand what's going on. Once I got it how I wanted, I am able to use the code below to get my password.

Thanks again guys. This is truly awesome. I'll be using this in a lot more scripts! Made sure to add you in the comments, so if I get to release some my apps as examples, you can take the credit (amount others who have helped)!

:-) I do write a fair amount of the code myself too though lol

#include <Crypt.au3>
; Code provided by Robjong - Autoit
_Crypt_Startup()
Global $sPasswordCT = '0x3F10544A42DE8D16C2C590C20640A00D'
Global $sJoinDomainPassword = ''
$sJoinDomainPassword = _Decrypt("password", $sPasswordCT)
MsgBox(0,"Password","Admin password: " & $sJoinDomainPassword)
_Crypt_Shutdown()
Func _Decrypt($sKey, $sData)
    Local $hKey = _Crypt_DeriveKey($sKey, $CALG_AES_256)
    Local $sDecrypted = BinaryToString(_Crypt_DecryptData(Binary($sData), $hKey, $CALG_USERKEY))
    _Crypt_DestroyKey($hKey)
    Return $sDecrypted
EndFunc
Edited by jazzyjeff
Link to comment
Share on other sites

I just want to note that, in the script from your last post, all the information needed to decrypt the password (key, data, scheme) is available to anyone who has the script, which defeats the purpose of the encryption.

The problem is that in order for this approach to work the decryption key can not be in the script, it does nothing else then 'hide' the password in the script from prying eyes (who have access to source).

So we might say...

#include <Crypt.au3>
_Crypt_Startup()
Global $sPasswordCT = '0x3F10544A42DE8D16C2C590C20640A00D'
Global $sJoinDomainPassword = ''
$sJoinDomainPassword = _Decrypt("password", $sPasswordCT)
MsgBox(0,"Password","Admin password: " & $sJoinDomainPassword)
_Crypt_Shutdown()
Func _Decrypt($sKey, $sData)
    Local $hKey = _Crypt_DeriveKey($sKey, $CALG_AES_256)
    Local $sDecrypted = BinaryToString(_Crypt_DecryptData(Binary($sData), $hKey, $CALG_USERKEY))
    _Crypt_DestroyKey($hKey)
    Return $sDecrypted
EndFunc

...is basicly the same as...

Global $sJoinDomainPassword = 'secret'

.

If you run you script you get the decrypted data, if you run my example you only get to the decrypted data if you know the password.

Edit: added explanation

Edit 2: There is no need for credits, you learned how to do it and then did it.

.

Edited by Robjong
Link to comment
Share on other sites

Hi Robjong,

Thanks for the heads up. I get what your saying, that if they get to the source they then have the key to get decrypt the password easily.

The thing is I need to make the process automated though, and with your script in it's entirety it seems like I have to have the user enter a password?. It's kind of that convenience versus security thing. Ideally it would be as secure as possible, but if it takes away some automation it's defeating the purpose. The fact that the password is now hidden at least in cleartext, and the exe itself is encrypted is hopefully enough.

I'm probably going to have some kid crack it now! :-)

Link to comment
Share on other sites

  • 1 year later...

Storing any sensitive information, let alone passwords of this nature, in AutoIt scripts is a bad idea to say the least.

AutoIt scripts can be decompiled and any information contained inside will be exposed, obfuscation does nothing to help this, it just makes it a little harder.

If you would encrypt the information and the script does not require human interaction the key has to be stored which renders the encryption worthless.

One possible implementation of encryption could be to save the password as an encrypted string, then store the encryption key as a hash.

When the script starts, the user enters the key which we match against the stored hash, if successful assign the encryption key to a variable, this variable can then be used to decrypt the password.

However we can not consider this approach to be very secure. (the password is stored in memory and the hash can be cracked with the use of rainbow tables for example etc.)

Example script:

#include <Crypt.au3>


_Crypt_Startup()

; Password=password
; Key=secret
;~ ConsoleWrite("Global $sPasswordCT = '" & _Encrypt("password", "secret") & "'" & @CRLF) ; DO NOT FORGET TO REMOVE THIS LINE
;~ ConsoleWrite("Global $sPasswordHash = '" & _Crypt_HashData("password", $CALG_SHA1) & "'" & @CRLF) ; DO NOT FORGET TO REMOVE THIS LINE

Global $sPasswordCT = '0x3F10544A42DE8D16C2C590C20640A00D'
Global $sPasswordHash = '0x5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD8'
Global $sJoinDomainPassword = ''

If _PromptPassword() Then
    $sJoinDomainPassword = _Decrypt("password", $sPasswordCT)
    ConsoleWrite("ct=" & $sJoinDomainPassword & @CRLF)
    MsgBox(64, "Access Granted", "Decrypted key: " & $sJoinDomainPassword)
    ; use the password...
    $sJoinDomainPassword = ''
Else
    MsgBox(16, "Access Denied", "Invalid password!")
    Exit
EndIf

_Crypt_Shutdown()


Func _PromptPassword()
    Local $sPassword = InputBox("Login", "Please type the correct password.", "", "*")
    Local $bPassword = _Crypt_HashData($sPassword, $CALG_SHA1)
    If $bPassword == $sPasswordHash Then
        Return True
    Else
        Return False
    EndIf
EndFunc

Func _Decrypt($sKey, $sData)
    Local $hKey = _Crypt_DeriveKey($sKey, $CALG_AES_256)
    Local $sDecrypted = BinaryToString(_Crypt_DecryptData(Binary($sData), $hKey, $CALG_USERKEY))
    _Crypt_DestroyKey($hKey)
    Return $sDecrypted
EndFunc

Func _Encrypt($sKey, $sData)
    Local $hKey = _Crypt_DeriveKey($sKey, $CALG_AES_256)
    Local $bEncrypted = _Crypt_EncryptData($sData, $hKey, $CALG_USERKEY)
    _Crypt_DestroyKey($hKey)
    Return $bEncrypted
EndFunc

I think a workaround like BrewManNH suggested might be your best option, maybe in combination with something like this.

 

 

I hope this is not considered hijacking of a thread, but I'm hoping that Robjong or someone else can clarify something about Robjong's solution.  I understand that the OP's main goal was to balance security with convenience, and that in his case he preferred to lean further on convenience, not requiring user intervention, in which case requesting a user to enter a password was undesirable. However, I believe that in my company's case, we would not have a problem with requesting user input at the start of a script.

My question is this: Am I correct in believing that requesting a user to enter an actual password, and storing that input into a variable for the duration of the script, is not secure? When Robjong said that "the password is stored in memory", was he referring to the encrypted string stored in the script itself, or was it that once the password is decrypted to cleartext, it resides in memory and is accessible during script execution (or possibly after) by anyone with enough skill and malicious intent to find it?

I apologize if these should be obvious; I am fairly new to AutoIT and only have a general background in programming, no real expertise in any language. Thank you in advance!

Link to comment
Share on other sites

  • 2 weeks later...

The variable you put your decrypted password into is stored in memory, and yes anyone with the required knowledge would be able to access it there. After the script has ended,, I'm not sure, I'd leave that up to the developers to tell us whether or not the memory locations are cleared.

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...