Jump to content

Recommended Posts

Posted (edited)

hi,

 

As a side project for a main I am trying to write a (hopefully reuseable) script.

This is the first time I am using encryption so I might have done something wrong and create a security issue, the goal of the script is so it could be used by other scripts as a login handler/saver.

So if anyone feels like checking wether or not I used encryption/hashing correctly be my guest. Any input is appriciated!!!

 

I feel fairly confident for most(of my) purposes this script will be secure enough.

I have done some testing and I have added a few options.

If anyone would like to use this, there are examples in the script

Feel free to alter it in any way

 

##Version 01/05/2019

#include-once
#Region ##Headers
#include <Array.au3>
#include <Crypt.au3>
#include <File.au3>
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#EndRegion ##Headers
Opt ("GUIOnEventMode", 1)
Opt ("GUIEventOptions", 1)

#Region ##Examples
;Local $aencryption = "4fxRuvY"
;~ _Login_CreateUser(@ScriptDir & "\test.cdt", "testuser", "testpw2", $aencryption, True)
;~ _Login_AskForList(@ScriptDir & "\test.cdt", $aencryption, True)
;~ _Login_DeleteUser(@ScriptDir & "\test.cdt", "testuser", $aencryption)
;~ _Login_CheckUserCredentials(@ScriptDir & "\test.cdt", "testuser", "testpw2", $aencryption)
;~ _Login_ChangePW(@ScriptDir & "\test.cdt", "testuser2", "test", "testpw2", $aencryption)
;~
;~ Notes:
;~  You still need to handle the button functions of the form yourself.
;~  Different apps need different functions after all.
;~  The encryption of the userlist/hash list is purely to protect privacy of the userlist.
;~  This can be easly cracked but even then are the passwords hashed out. Beware!!!
#EndRegion

;###################### Example script () #######################
; this is an example of the script automatically generating an user and then asking for a login
; This is how you could use my script as a login module for your script

;~ #include <Login.au3>
;~ Global $aLoginVars; declare a global array to hold the form variables. This is global for ease of acces of the form elements.
;~ Global $sCurrentUser; declare global string to set what user logged in.

;~ _Login_CreateUser(@ScriptDir & "\test.cdt", "Username", "Password", "4fxRuvY", True); generate a user with username "username" and password "Password"
;~ If @error Then MsgBox(0, "creating error", @error & "     " & @extended)
;~ _Quiz_Login(); do the login


;~ While 1
;~  Sleep(100)
;~ WEnd

;~ Func _Quiz_Login ()
;~  $aLoginVars = _Login_Form_AskLogin() ; create login window
;~  GUISetOnEvent($GUI_EVENT_CLOSE, "Quit", $aLoginVars[0][0]); exitbutton(X) on the form menu bar was clicked
;~  GUICtrlSetOnEvent($aLoginVars[1][0], "_Quiz_Login_Check"); button OK was pressed
;~  GUICtrlSetOnEvent($aLoginVars[2][0], "Quit"); button Cancel was pressed
;~  GUISetState(@SW_SHOW, $aLoginVars[0][0]); Display the generated GUI
;~ EndFunc


;~ Func _Quiz_Login_Check()
;~  Local $sUsername = GUICtrlRead($aLoginVars[4][0]); get username
;~  Local $sPassword = GUICtrlRead($aLoginVars[3][0]); get password
;~  Local $aCheckResult = _Login_CheckUserCredentials(@ScriptDir & "\test.cdt", $sUsername, $sPassword, "4fxRuvY") ; check both
;~  If @error Then MsgBox(0,"@error", @error & "        extended:" & @extended) ; check for errors
;~  If $aCheckResult[0] = True Then; user is correct
;~      If $aCheckResult[1] = True Then
;~          $sCurrentUser = $sUsername; PW is correct
;~      EndIf
;~  EndIf
;~ EndFunc

;~ Func Quit ()
;~  Exit
;~ EndFunc
;########################### End of examplescript ################


#Region ##Functions
; _Login_CreateUser ====================================================================================================================
; Description ...:  Creates and writes a new user to the file. If the file does not exist it will try to make a new one.
;                   You have to provide the encryption array.
;                   For more info please check comments section/ the actual script comments :-)
; Syntax ........: _Login_CreateUser ($sUsername, $sPassword, $sEncryptionPW, $sFileLocation,[$bCreateNew = False])
; Parameters ....: $sFileLocation       - a string containing the FULL path to the file.(make sure permissions are sufficient to write there).
;                  $sUsername           - a string containing the username.(Clear txt.)
;                  $sPassword           - a string containing the password.(Clear txt.)
;                  $sEncryptionPW          - a string containing the encryption PW(Clear txt)
; Return values .: 1 if succes , 0 and sets @error if there is an error
; Author ........: Ternal
;
;@error 1: - Path does not exist($sFileLocation)    -@extended 1 : Bool to make a new path was set to false and path does not exist.
;                                                                                           -@extended 2 : Could not open file.(In use or permissions?)
;
;@error 2: Encryption   PW incorrect                        -@extended 1 :It less then 6 chars or there is a space in it.
;                                                                                           -@extended 2 : Function failed to decrypt file, PW incorrect or file corrupted.
;
;@error 3 :User already exists
;
;@error4 :Failed to create user                                 -@extended 1 : In a new file.
;                                                                                           -@extended 2 :In an existing file.
;
; ===============================================================================================================================
Func _Login_CreateUser($sFileLocation, $sUsername, $sPassword, $sEncryptionPW, $bCreateNew = Default)
    If $bCreateNew = Default Then $bCreateNew = False ; parameter setting
    Local $hFile ; declare the var for the filehandle

    If Not (FileExists($sFileLocation)) Then ;check if path exists
        If $bCreateNew = False Then Return SetError(1, 1, 0) ; if the Bool to create a new path is not set and the path does not exist return and set error
        $hFile = FileOpen($sFileLocation, 9) ; create new path if it did not exist
        If $hFile = -1 Then Return SetError(1, 2, 0) ; selfexplaining I guess?
        FileClose($hFile) ; close da file to reopen it elsewhere, they told me I should do this asap always.
    EndIf ; end of the things to do when the path does not exist

    Local $sInputCombined = $sUsername & $sPassword ; to avoid checking each string seperatly
    If (Not (IsString($sUsername) And IsString($sPassword))) Or StringInStr($sInputCombined, " ") Or StringInStr($sInputCombined, ";") Or StringInStr($sInputCombined, "/") Or StringInStr($sInputCombined, "\") Then Return SetError(2, 0, 0) ; inputchecking
    If StringInStr($sEncryptionPW, " ") Then Return SetError(2, 1, 0) ; inputchecking
    If StringLen($sEncryptionPW) < 6 Then Return SetError(2, 1, 0) ; inputchecking
    Local $aUserlist = _Login_AskForList($sFileLocation, $sEncryptionPW, True)
    If _ArraySearch($aUserlist, $sUsername) > -1 Then Return SetError(3, 0, 0) ; checks if username already exists
    ;If we are still in function by now this means there are no errors given by our inputchecking

    Local $aPWHash = _HashPW($sUsername, $sPassword)
    $hFile = FileOpen($sFileLocation, 17) ; open the file in binary write mode
    FileSetPos($hFile, 0, 0) ; set pos back to 0( because it was opened in mode 17)
    Local $sEncryptedContent = FileRead($hFile) ; read the file
    Local $iFileSize = BinaryLen($sEncryptedContent)
    If $iFileSize < 4 Then ; file was empty, so we create the first entry.
        LogWrite("_Login_CreateUser", "New Credential file started @ " & $sFileLocation)
        Local $sFirstString = __StringEncrypt(True, $sUsername & ";/;" & $aPWHash[0] & ";/;" & $aPWHash[1] & ";/\;", $sEncryptionPW) ; encrypt the credentials with delimeters
        FileSetPos($hFile, 0, 0) ; set cursor at the start of the file
        FileWrite($hFile, $sFirstString) ; write to the file
        FileFlush($hFile) ; save to disk
        FileSetPos($hFile, 0, 0) ; set cursor at start of file
        Local $sEncryptedContentTest = FileRead($hFile) ; read the data back from file to string. this is to ensure that the Function will not run further if it was saved incorrectly.
        FileClose($hFile) ; close the file for now
        If Not StringInStr(__StringEncrypt(False, $sEncryptedContentTest, $sEncryptionPW), $sUsername & ";/;" & $aPWHash[0] & ";/;" & $aPWHash[1] & ";/\;") Then ; decrypt the file and check if the new credentials are added to it
            LogWrite("_Login_CreateUser", "Failure to write correctly to a new file") ; it came out wrong
            Return SetError(4, 1, 0)
        Else
            Return 1 ; the first credential is in the file... YAAAAY
        EndIf
    Else
        FileClose($hFile) ; close the file to reopen it in overwrite mode.(to make sure everything works correctly, I had some issues with not getting the right cursor pos so I used this out of lazyness)
    EndIf
    FileCopy($sFileLocation, $sFileLocation & ".bak", 9)

    Local $aCredentialList = __String2Array(__StringEncrypt(False, $sEncryptedContent, $sEncryptionPW)) ;  convert the encrypted string to arrayformat for easier handling.(array is the standard format to be used).
    Local $iOldSize = UBound($aCredentialList, 1) ; get the current size of the array
    If $iFileSize > 6 And $iOldSize = 0 Then
        Return SetError(2, 2, 0)
    EndIf
    ReDim $aCredentialList[$iOldSize + 1][3] ; resize the array so it can hold one element more.By adding a new row the value of $iOldSize becomes the index of the new row   (0 based array)
    $aCredentialList[$iOldSize][0] = $sUsername ; username in the first column
    $aCredentialList[$iOldSize][1] = $aPWHash[0] ; passwordhash in the second column
    $aCredentialList[$iOldSize][2] = $aPWHash[1] ; salt in the third column
    $sEncryptedContent = __StringEncrypt(True, __Array2String($aCredentialList), $sEncryptionPW) ; encrypt the new array
    $aCredentialList = "" ; get rid of the credentials in plaintext in the memory, it is no longer needed.
    $hFile = FileOpen($sFileLocation, 18) ; open in binary overwritemode
    FileWrite($hFile, $sEncryptedContent) ; write to the file
    FileFlush($hFile) ; write to disk
    FileSetPos($hFile, 0, 0) ; set cursor at start of file
    Local $sEncryptedContent = FileRead($hFile) ; read the file
    FileClose($hFile) ; we are finished
    If Not StringInStr(__StringEncrypt(False, $sEncryptedContent, $sEncryptionPW), $sUsername & ";/;" & $aPWHash[0] & ";/;" & $aPWHash[1] & ";/\;") Then ; decrypt the file and check if the new credentials are added to it
        LogWrite("_Login_CreateUser", "Failure to write correctly to file, or file has been corrupted") ; put :"it came out wrong" in da log
        FileCopy($sFileLocation & ".bak", $sFileLocation, 1)
        FileDelete($sFileLocation & ".bak")
        Return SetError(4, 2, 0)
    Else
        FileDelete($sFileLocation & ".bak")
        Return 1 ; the new user is in the function so I guess its bye bye
    EndIf
EndFunc   ;==>_Login_CreateUser

; _Login_AskForUserList ====================================================================================================================
; Description ...: Retrieves an Userlist from a previous made credential file
; Syntax ........: _Login_Query_UserList ($sFileLocation, $sEncryptionPW,[$bUser = True])
; Parameters ....: $sFileLocation       - a string containing the location of the file
;                  $sEncryptionPW          - a string containing the encryption PW(Clear txt)
;                  $bUser               - if true then return userlist, if false return passwordlist, default is userlist
; Return values .: an array of usernames if succes, empty array or 0 at no succes
; Author ........: Ternal
;
;@error 1: - Path does not exist($sFileLocation)    -@extended 1 : Bool to make a new path was set to false and path does not exist.
;                                                                                           -@extended 2 : Could not open file.(In use or permissions?)
; ===============================================================================================================================
Func _Login_AskForList($sFileLocation, $sEncryptionPW, $bUser = Default)
    If Not (FileExists($sFileLocation)) Then Return SetError(1, 1, 0) ; inputchecking
    If $bUser = Default Then $bUser = True
    Local $aReturn[1] ; declare the return array
    If $bUser = True Then
        $bUser = 0 ; get the userlist
    Else
        $bUser = 1 ; get the passwordlist
    EndIf

    Local $hFile = FileOpen($sFileLocation, 16) ; open file in binary mode
    If $hFile = -1 Then Return SetError(1, 2, 0) ; inputchecking
    FileSetPos($hFile, 0, 0) ; set cursor at start of file
    Local $sEncryptedContent = FileRead($hFile) ; read the binary file
    Local $aTemp = __String2Array(__StringEncrypt(False, $sEncryptedContent, $sEncryptionPW)) ; put everything decrypted in an array
    If $bUser = 0 Then
        ReDim $aReturn[UBound($aTemp, 1)] ; correct the array size to 1D for usernames
        For $i = 0 To UBound($aTemp, 1) - 1
            $aReturn[$i] = $aTemp[$i][$bUser] ; copy the usernames to the returnarray
        Next
    Else
        ReDim $aReturn[UBound($aTemp, 1)][2] ; correct the array to 2D for pw and salt
        For $i = 0 To UBound($aTemp, 1) - 1
            $aReturn[$i][0] = $aTemp[$i][$bUser] ; copy the  password hashes to the returnarray
            $aReturn[$i][1] = $aTemp[$i][$bUser + 1] ; copy the  salt to the returnarray
        Next
    EndIf
    Return $aReturn
EndFunc   ;==>_Login_AskForList

; _Login_CheckUserCredentials ====================================================================================================================
; Description ...: Checks wether the given username and password are correct. Please do note this might malfunction when there are duplicate users so beware when creating users please.
; Syntax ........: _Login_CheckUserCredentials ($sFileLocation, $sUsername, $sPassword, $sEncryptionPW)
; Parameters ....: $sFileLocation       - a string containing the filelocation
;                  $sUsername           - a string containing the username to check
;                  $sPassword           - a string containing the password to check
;                  $sEncryptionPW           - a string containing the encryption PW(Clear txt)
; Return values .: An Array with at index 0 usercheck (true is correct , false is incorrect) and index 1 holds the password bool.If the encryption PW is wrong you will get 2x False as well
; Author ........: Ternal, Additional credits go to jchd for correcting me !!!
;
;@error 1: - Path does not exist($sFileLocation)    -@extended 1 : Bool to make a new path was set to false and path does not exist.
;                                                                                           -@extended 2 : Could not open file.(In use or permissions?)
; ===============================================================================================================================
Func _Login_CheckUserCredentials($sFileLocation, $sUsername, $sPassword, $sEncryptionPW)
    Local $aReturn[2] = [False, False] ; create return array and set it false
    Local $aUserlist = _Login_AskForList($sFileLocation, $sEncryptionPW, True) ; ask for a list of users
    If @error Then
        Local $error = @error
        Local $extended = @extended
        Return SetError($error, @extended, $aReturn)
    EndIf
    Local $iLocationUsername = _ArraySearch($aUserlist, $sUsername, 0, 0, 0, 0, 1, 0) ; search the first column(usernames) non-case sensitive.
    If @error Then Return $aReturn
    If $iLocationUsername > -1 Then ; function returns an integer thats 0 or above so it has found something.
        $aReturn[0] = True ; set username to be true(found it)
    Else ; better luck next time for a correct user :(
        Return $aReturn ; end of the function for this path
    EndIf
    Local $aPWList = _Login_AskForList($sFileLocation, $sEncryptionPW, False) ;still running so we are asking for the passwordhashlist...
    Local $sNewHash = _HashPW($sUsername, $sPassword, $aPWList[$iLocationUsername][1])
    If Not ($aPWList[$iLocationUsername][0] == $sNewHash[0]) Then ; check if the passwordhash at the location where we found the username is the same as the hash generated
        Return $aReturn ; not the same
    Else
        $aReturn[1] = True
        Return $aReturn
    EndIf
EndFunc   ;==>_Login_CheckUserCredentials

; _Login_DeleteUser ====================================================================================================================
; Description ...: Deletes an user from the file
; Syntax ........: _Login_DeleteUser($sFileLocation, $sUsername, $sEncryptionPW)
; Parameters ....: $sFileLocation       - a string containing the filepath
;                  $sUsername           - a string containing the user to delete
;                  $sEncryptionPW        - a string containing the encryption PW(Clear txt)
; Return values .: 1 if succes, 0 on error, 404 if the user is not found.
; Author ........: Ternal
;
;@error 1: - Path does not exist($sFileLocation)    -@extended 1 : Bool to make a new path was set to false and path does not exist.
;                                                                                           -@extended 2 : Could not open file.(In use or permissions?)
;
;@error2: -Failed to get userlist, encryption PW might be wrong or file might be corrupted
;
;@error3 / return 404 : -User to delete from userlist was NOT in the userlist.
; ===============================================================================================================================
Func _Login_DeleteUser($sFileLocation, $sUsername, $sEncryptionPW)
    Local $aUserlist = _Login_AskForList($sFileLocation, $sEncryptionPW, True) ; ask for a list of users
    If @error Then
        Local $error = @error
        Local $extended = @extended
        Return SetError($error, @extended, 0)
    EndIf
    Local $iSearch = _ArraySearch($aUserlist, $sUsername, 0, 0, 0, 0, 1, 0)
    If @error = 3 Then Return SetError(2, 0, 0)
    If $iSearch > -1 Then
        Local $hFile = FileOpen($sFileLocation, 16)
        Local $sEncryptedContent = FileRead($sFileLocation)
        FileClose($hFile)
        Local $aCredentialList = __String2Array(__StringEncrypt(False, $sEncryptedContent, $sEncryptionPW)) ;  convert the encrypted string to arrayformat for easier handling.(array is the standard format to be used).
        _ArrayDelete($aCredentialList, $iSearch)
        $hFile = FileOpen($sFileLocation, 18)
        FileWrite($hFile, __StringEncrypt(True, __Array2String($aCredentialList), $sEncryptionPW))
        FileClose($hFile)
    Else
        Return SetError(3, 0, 404)
    EndIf
    Return 1
EndFunc   ;==>_Login_DeleteUser

; _Login_ChangePW ====================================================================================================================
; Name ..........: _Login_ChangePW
; Description ...: Changes the PW for a user, in reality it checks the old credentials, if correct it deletes the old user and recreates a new user with the new password (CALL ME LAZY , Proud of it).
; Syntax ........: _Login_ChangePW($sFileLocation, $sUsername, $NewPW, $OldPW, $sEncryptionPW)
; Parameters ....: $sFileLocation       - a string containing the filepath
;                  $sUsername          - a string containing the user to change pw of
;                  $NewPW               - a string containing  the new pw in plaintext
;                  $OldPW               - a string containing  the old pw in plaintext
;                  $sEncryptionPW        - a string containing the encryption PW(Clear txt)
; Return values .: 1 if succes, 0 if no succes
; Author ........: Ternal
; ===============================================================================================================================
Func _Login_ChangePW($sFileLocation, $sUsername, $NewPW, $OldPW, $sEncryptionPW)
    Local $aCheck = _Login_CheckUserCredentials($sFileLocation, $sUsername, $OldPW, $sEncryptionPW)
    If $aCheck[0] = False Then Return 0
    If $aCheck[1] = False Then Return 0
    _Login_DeleteUser($sFileLocation, $sUsername, $sEncryptionPW)
    _Login_CreateUser($sFileLocation, $sUsername, $NewPW, $sEncryptionPW)
    Return 1
EndFunc   ;==>_Login_ChangePW

; _Login_Form_AskLogin ====================================================================================================================
; Name ..........: _Login_Form_AskLogin
; Description ...: Creates a loginform and returns the handles and description in a 2D array.
; Syntax ........: _Login_Form_AskLogin([$sLanguage = Default])
; Parameters ....: $sLanguage           - [optional] What language to use. Default is English.
;                  Possible options are "English", "French","Dutch",Default.. All other input will result in the function returning 0 and @error set to 1
; Return values .: If language is correct = array with formvariables, otherwise 0 and set @error to 1
; Author ........: Ternal
; return array layout:
;[Handle1,  Name of the handle] : FormHandle
;[Handle2,  Name of the handle] : Button OK
;[Handle3,  Name of the handle] : Button Cancel
;[Handle4,  Name of the handle] : Inputbox PW
;[Handle5,  Name of the handle] : Inputbox User
;[Handle6,  Name of the handle] : label pw
;[Handle7,  Name of the handle] : Label user
; ===============================================================================================================================
Func _Login_Form_AskLogin($sLanguage = Default)
    If $sLanguage = Default Then $sLanguage = "English"
    Local $TXT_UserInput, $TXT_LabelPW, $TXT_LabelUser, $TXT_FormTitle, $TXT_BtnOk, $TXT_BtnCncl
    Select
        Case $sLanguage = "English"
            $TXT_FormTitle = "Login"
            $TXT_LabelPW = "Password"
            $TXT_LabelUser = "Username"
            $TXT_BtnOk = "Login"
            $TXT_BtnCncl = "Cancel"

        Case $sLanguage = "Dutch"
            $TXT_FormTitle = "Login"
            $TXT_LabelPW = "Wachtwoord"
            $TXT_LabelUser = "Gebruikersnaam"
            $TXT_BtnOk = "Login"
            $TXT_BtnCncl = "Annuleren"

        Case $sLanguage = "French"
            $TXT_FormTitle = "Login"
            $TXT_LabelPW = "mot de passe"
            $TXT_LabelUser = "Nom d'utilisateur"
            $TXT_BtnOk = "s'Identifier"
            $TXT_BtnCncl = "Annuler"

        Case Else
            Return SetError(1, 0, 0)
    EndSelect

    Local $aFormVars[7][2]
    $aFormVars[0][0] = GUICreate($TXT_FormTitle, 275, 154, -1, -1)
    $aFormVars[0][1] = "LoginForm"
    $aFormVars[4][0] = GUICtrlCreateInput("", 14, 28, 233, 21, $GUI_SS_DEFAULT_INPUT)
    $aFormVars[4][1] = "UserInput"
    $aFormVars[3][0] =  GUICtrlCreateInput("", 14, 72, 233, 21, BitOR($GUI_SS_DEFAULT_INPUT,$ES_PASSWORD))
    $aFormVars[3][1] = "PWInput"
    $aFormVars[1][0] = GUICtrlCreateButton($TXT_BtnOk, 92, 108, 75, 25, $BS_NOTIFY)
    $aFormVars[1][1] = "BTNOk"
    $aFormVars[2][0] = GUICtrlCreateButton($TXT_BtnCncl, 173, 108, 75, 25, $BS_NOTIFY)
    $aFormVars[2][1] = "BTNCancel"
    $aFormVars[5][0] = GUICtrlCreateLabel($TXT_LabelPW, 14, 52, 90, 17, 0)
    $aFormVars[5][1] = "LabelPW"
    $aFormVars[6][0] = GUICtrlCreateLabel($TXT_LabelUser, 14, 8, 90, 17, 0)
    $aFormVars[6][1] = "LabelUser"
    Return $aFormVars
EndFunc


; LogWrite ====================================================================================================================
; Name ..........: LogWrite
; Description ...: Well , in case you were wondering it writes a log file....
; Syntax ........: LogWrite($sFunction, $sTxt)
; Parameters ....: $sFunction           - a string containing the function who called the logwrite
;                  $sTxt                - a string containing whatever you deem logworthy
; Author ........: Ternal
; ===============================================================================================================================
Func LogWrite($sFunction, $sTxt)
    Local $sFullString = @MDAY & "/" & @MON & "/" & @YEAR & " " & @HOUR & ":" & @MIN & ":" & @SEC & " " & "function " & $sFunction & " reports:  " & $sTxt ; create a string with a timestamp
    ConsoleWrite($sFullString & @CRLF) ; write it to console(because I am still to lazy to go to the actual map an read the txt file..
    Local $errorFile = @WorkingDir & "\" & @ScriptName & ".log" ; make a logfilepath string
    Local $hFileOpen = FileOpen($errorFile, 9) ; create path/ append to end of file params
    FileWriteLine($hFileOpen, $sFullString & @CRLF) ; write the line
    FileClose($hFileOpen) ; lets close it
EndFunc   ;==>LogWrite

; #INTERNAL_USE_ONLY# ====================================================================================================================
; Description ...: hashes a PW with salt( almost seems like this is cooking rather then programming ain't it?)
; Syntax ........: _HashPW($sUsername, $sPlainTextPW[, $sSalt = Default])
; Parameters ....: $sUsername          - a string containing the user
;                  $sPlainTextPW        - a string containing the pw
;                  $sSalt               - [optional] a string that contains the salt of the pw to has, Default is a new random salt of 20 chars.
; Return values .:  0 on error, array with hash and salt on succes
; Author ........: Ternal
; ===============================================================================================================================
Func _HashPW($sUsername, $sPlainTextPW, $sSalt = Default)
    If $sSalt = Default Then $sSalt = __Randomstring(20)
    If Not IsString($sPlainTextPW) Then Return SetError(1, 0, 0)
    If StringLen($sPlainTextPW) < 3 Then Return SetError(2, 0, 0)
    Local $sUserSalt = StringLower($sUsername); to avoid having case sensitive usernames.
    _Crypt_Startup()
    Local $sHash = _Crypt_HashData($sUserSalt & $sSalt & $sPlainTextPW, $CALG_SHA_512)
    _Crypt_Shutdown()
    Local $aReturn[2] = [$sHash, $sSalt]
    Return $aReturn
EndFunc   ;==>_HashPW

; #INTERNAL_USE_ONLY# ====================================================================================================================
; Description ...: generates a random string of $length
; Syntax ........: __Randomstring($length)
; Parameters ....: $length              - integer containing the length of the string to generate
; Return values .: a random string
; Author ........: PhilRip
; Modified ......: 29/03/2009
; ===============================================================================================================================
Func __Randomstring($length)
    Local $chars = StringSplit("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", "")
    Local $String = ""
    Local $i = 0
    Do
        If $length <= 0 Then ExitLoop
        $String &= $chars[Random(1, $chars[0])]
        $i += 1
    Until $i = $length
    Return $String
EndFunc   ;==>__Randomstring

; #INTERNAL_USE_ONLY# ====================================================================================================================
; Name ..........: __String2Array
; Description ...: Converts a decrypted string to array
; Syntax ........: __String2Array($sDecryptedString)
; Parameters ....: $sDecryptedString    - a string containing the decrypted file
; Return values .: an array of the string
; Author ........: Ternal
; ===============================================================================================================================
Func __String2Array($sDecryptedString)
    Local $aColums ; declare an array to hold each column value for each row
    Local $aRows = StringSplit($sDecryptedString, ";/\;", 1) ; ;/\; is the delimiter for rows, this splits up the rows in decrypted file string
    Local $aArray[$aRows[0]][3] ; declare an array big enough to hold all array vars.
    For $i = 1 To $aRows[0]
        $aColums = StringSplit($aRows[$i], ";/;", 1) ; ;/; is the delimiter for cells this splits up the colums per row
        For $j = 1 To $aColums[0]
            $aArray[$i - 1][$j - 1] = $aColums[$j] ; copy the array info, notice the - 1 , this moves the 1based array to a 0 based array
        Next
    Next
    ReDim $aArray[$aRows[0] - 1][3] ; resize to get rid of the 1-based array from stringsplit, this will now be at the end
    Return $aArray
EndFunc   ;==>__String2Array

; #INTERNAL_USE_ONLY# ====================================================================================================================
; Name ..........: __Array2String
; Description ...: preps an array to be put into encryption as a string.
; Syntax ........: __Array2String($aArray)
; Parameters ....: $aArray              - an array of credentials
; Return values .: a string of credentials
; Author ........: Ternal
; ===============================================================================================================================
Func __Array2String($aArray)
    Local $sReturn ; declare return string
    For $i = 0 To UBound($aArray, 1) - 1
        For $j = 0 To UBound($aArray, 2) - 1
            $sReturn = $sReturn & $aArray[$i][$j] & ";/;" ; add column delimiters
        Next
        $sReturn = StringTrimRight($sReturn, 3) ; delete the last delimiter
        $sReturn &= ";/\;" ; place a new row delimiter
    Next
    Return $sReturn
EndFunc   ;==>__Array2String

; #INTERNAL_USE_ONLY# ====================================================================================================================
; Name ..........: __StringEncrypt
; Description ...: function found on autoitForum
; Syntax ........: __StringEncrypt($bEncrypt, $sData, $sPassword)
; Parameters ....: $bEncrypt            - a boolean value.
;                  $sData               - a string value.
;                  $sPassword           - a string value.
; Return values .: None
; Author ........: perfaram ?? I forgot the user who made this function, AWFULLY SORRY :/ The person who wrote this deserves all the credits!!
; ===============================================================================================================================
Func __StringEncrypt($bEncrypt, $sData, $sPassword)
    _Crypt_Startup() ; Start the Crypt library.
    Local $vReturn = ''
    Local $hKey = _Crypt_DeriveKey(StringToBinary($sPassword), $CALG_AES_256)
    If $bEncrypt Then ; If the flag is set to True then encrypt, otherwise decrypt.
        $vReturn = _Crypt_EncryptData($sData, $hKey, $CALG_USERKEY) ; encrypt data
    Else
        $vReturn = BinaryToString(_Crypt_DecryptData($sData, $hKey, $CALG_USERKEY)) ; decrypt data
    EndIf
    _Crypt_DestroyKey($hKey)
    _Crypt_Shutdown() ; Shutdown the Crypt library.
    Return $vReturn
EndFunc   ;==>__StringEncrypt

#EndRegion ##Functions

 

Edited by ternal
update on script

Share this post


Link to post
Share on other sites

You should never ever store passphrases!

Just store the user name and the hash made from login name, passphrase and preferably some salt.

Validating input then means collecting login name and pass then checking the resulting hash is correct.


This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites
Posted (edited)

First thanks for taking the time to check my script!! 

So I will  alter my script  to take a hash of a combination  of user and pass and some  salt..  

And then encrypt the plaintxt user and the hash all together in a file? 

If I need to check credentials  then I would  decrypt to memory,  check  hash from input ,  compare it to decrypted  hash of a certain  user,  right? 

Any other remarks? 

 

 

Thanks  a lot!! 

Edited by ternal

Share this post


Link to post
Share on other sites
Posted (edited)

Yes, correct. Encryption of the file isn't mandatory, unless you insist on keeping names hidden in case some malvolent gets access to the file (users and logins may be distinct or not, depending on your use case).

In allmost all cases, this simple scheme is safe enough since you can't be held responsible for passphrase leaking, even if the AutoIt executable is somehow reverse-engineered and the file is copied. Even home-jacking you and your kids isn't an effective way to recover working access: all you can give is file decryption key and salt value, not enough to impersonate any user.

Obviously if the context requires very high robustness (keeping the number and identities/logins a secret) then extra measures can be taken, but then it's a completely different story. Yet you can do something to protect names and logins: encrypt them wih the user password just supplied. Your file then just contains a 2D table of meaningless binary data: hash(login & passphrase & salt), crypt(name), crypt(login). This way makes users protect their credentials by their own login/password.

That said, a powerful opponent will probably find it easier to compromise physical access to you PC (trojan, hardware) or intercept the network flow at some point in your organization.

Edited by jchd

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites
Posted (edited)

Hi again,

If anyone would like to check my script for security issues( no obligation to anyone!!) feel free.

I think this is secure enough for most applications that do not deal with finances.

edit = for the script see first post !!

Edited by ternal

Share this post


Link to post
Share on other sites

I have very little time for reviewing your code and I trust you to be careful. I think you're indeed on the right track, even more as it sin't a highly sensitive military top secret context and no life is threatened!


This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Share this post


Link to post
Share on other sites

So a little Bump.

 

I feel fairly confident that the script now is secure enough for offline purposes. I updated the script with some examples how you could use it as an Include.(as a library/header?)

First post contains the script, if there are any questions, errors or anything like it please let me know.

Share this post


Link to post
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

×
×
  • Create New...