Jump to content

Hashing + KeyStretching [New Focus]


IanN1990
 Share

Recommended Posts

Hi All, 

So here is what i have learnt from a weeks worth of research. 

It is IMPOSSIBLE to keep information safe from someone who is dedicated to getting it and the only tool is causing it more effort then it is worth.

Hashing a password in itself means nothing, as if an attacker has a table of every hashed word (rainbowtable) it is as simple as "copy hash & Ctrl + F".

That's why we add a salt. So now an attacker must have a table made with every word + salt, this means he needs to know the algorithm of where the salt goes and what the salt is.

Assuming he has access to this information, it doesn't make how clever the algorithm is because a new table could be generated. The salt also needs to be unique for each person.

This does not protect it verse Brute forcing. As you may think a 7 digit combination with a 5 digit salt = 1,000,000,000,000 combinations (excluding where the salt could go) but when most good gaming PCs could perform 17042497.3 guesses per second that "could" less then 20 hours to brute force (assuming they got it on the absolutely last guess). Scary right!!

This leaves one last tool in the trade (from what i can see) called key-stretching. This is where, the process to generate a key would take at lest (x) second. So that brute force above turns from 17042497.3 guesses per second to 17042.4973 (assuming my maths is right) and now you are looking at 679 days with a key stretch delay of 1 second.

The two big programs regarding this are PBKDF2 and bcrypt (despite my searching on the forum nether are supported within auto it and / or free to commercial use)

So this in mind, is this a correct implementation and understand of key stretching 

#include <Crypt.au3>
Global Const $CALG_SHA_512 = 0x0000800e ;128
$ALG = $CALG_SHA_512

local $NewPassword
$Password = "1234567"
$Salt = "12345"
For $I = 1 to 9999
$PasswordHash = StringTrimLeft(_Crypt_HashData($NewPassword&$Password, $ALG), 2)
$NewPassword = StringTrimLeft(_Crypt_HashData($Password&$Salt, $ALG), 2)
Next

ConsoleWrite($NewPassword & @crlf)

As the finial hash, would of only been obtained by hashing. the password 9999 times.

This takes 5.41 seconds vs 0.07196 making it take 750% longer to brute force. Taking 1 day in 75 and 1 year into 75.

This also goes into the idea of, by the time they get this information would that information useful. Even if they did find out the name of your super-top secret bank account, 75 years down the line would that bank even be around?

So whats everyone's thoughts?

Ian

 

 

Edited by IanN1990
Link to comment
Share on other sites

The problem is not the hash, the problem is AutoIt is a scripting language and very easy reversed to source. After having source, just eliminating the check if password ist true is all what must be done and protected code can be excecuted.

But also MS has secutity problems:

found on https://room362.com/post/2016/snagging-creds-from-locked-machines/

Edited by AutoBert
Link to comment
Share on other sites

I would separate the GUI for first level from the execution of the commands (altering AD etc.).
Create a virtual machine with a service account with all the needed permissions (stripped down as far as possible), do not allow interactive logon for this account.

The GUI part would send a command to the virtual service machine to be executed, the service machine validates it (is command OK, is sender allowed etc.) and if OK executes and logs the command as well as the result.

That's the way our service tool works here.

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

42 minutes ago, water said:

I would separate the GUI for first level from the execution of the commands (altering AD etc.).
Create a virtual machine with a service account with all the needed permissions (stripped down as far as possible), do not allow interactive logon for this account.

The GUI part would send a command to the virtual service machine to be executed, the service machine validates it (is command OK, is sender allowed etc.) and if OK executes and logs the command as well as the result.

That's the way our service tool works here.

i suspect your referring one of my older question about storing passwords inside scripts. I took your advice and dropped that idea, opting for the same thing you suggested. 

In this question however i am just generally learning about key stretching with autoit :) To find out if it is even possible

Link to comment
Share on other sites

Post #2 provides the final answer.
This has been discussed many, many times on the forum - the answer was always the same.
Youd can't securely store a password in AutoIt nor call an internal security function because a malicious user could decrypt the password or remove the security function in just a few minutes.

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

but i am not worried about that! :)

In this example, the autoit code would be stored in a part of windows that users permissions wouldn't have access to and task scheduler (set using the admin account) is what would run the program

1. This prevents them accessing the source exe and for the most their own stored hash (which is only a check)

The tool does nothing important, it only adds a layer of security when they have none. So even if someone is clever enough to "for this example" install something to read and understand the program from memory and or edit it from memory it wouldn't mater :)

 

All i want to know is, does my example demonstrate a good example of key stretching or is my understanding of key stretching wrong?

*Though, in different circumstances, i do fully take on both of your points :)  

Edited by IanN1990
Link to comment
Share on other sites

Following advice from users on the forum, i have dropped a lot of my previous ideas.

I will opt for a unique salt with each password and hash that. To increase the time it would take brute-forcing this must be stretched. 

Writing a unique function to do this though is a bad idea, as to many things can go wrong and its just not tested.

Looking online some well know functions are bcrypt, scrypt and many others. Interestingly the one recommended by NIST is PBKDF2, which is a windows function.

I have searched on the forums, but cant find anything written for it. 

This is my first time writing a DllCall, naturally it has gone wrong :)

https://msdn.microsoft.com/en-us/library/windows/desktop/dd433795(v=vs.85).aspx <-- Function

#NoTrayIcon
#include "crypt.au3"

_Crypt_Startup()

PBKDF2("Password", "Salt", 100, 128)

Func PBKDF2($sPassword, $sSalt, $nIterations = 10000, $nLength = 0, $sAlgo = "SHA1")
   Local $Buffer
   $sPasswordlength = StringLen($sPassword)
   $sSaltlength = StringLen($sSalt)

   DllCall(__Crypt_DllHandle(), "bool", "BCryptDeriveKeyPBKDF2", "handle", "PUCHAR", $sPassword, "ULONG", $sPasswordlength, "PUCHAR", $sSalt, "ULONG", $sSaltlength, "ULONGLONG", $nIterations, "PUCHAR", $Buffer, "ULong", $sAlgo, "Ulong", 0)

   Return $Buffer
EndFunc

Things i know are wrong are;

1.  cbPassword [in] & cbSalt [in] needs the length to be in "bytes" but i think that is different from stringlen()

2. Looking at DLLCall in the helpfile, i cant find PUCHAR as a valid data type

3. I suspect i have called BCRYPT_ALG_HANDLE wrong, i did my best to look at Crypt.au3 for guidance

I was hoping for some guidance from my experienced members?

 

Edited by IanN1990
Link to comment
Share on other sites

Hello. You did not set a working code to check.  As far I see most of the Dllcall's parameters are wrong. Check out DllCall's Conversions WINAPI Types.

 

Saludos

 

 

 

 

Link to comment
Share on other sites

Hi DanyFirex, 

Your quite correct. I have never written a API :)

 

#NoTrayIcon
#include "crypt.au3"
_Crypt_Startup()

PBKDF2("Password", "Salt", 100, 128)

Func PBKDF2($Password, $Salt, $Iterations = 10000, $Algo = "SHA1")
   Dim $pbPassword = $Password
   Dim $cbPassword = StringLen($Password)
   Dim $pbSalt = $Salt
   Dim $cbSalt = StringLen($Salt)
   Dim $cIterations = $Iterations
   Dim $pbDerivedKey
   Dim $cbDerivedKey = $Algo
   Dim $dwFlags = 0

   DllCall(__Crypt_DllHandle(), "bool", "BCryptDeriveKeyPBKDF2", "handle*", 0, _
   "BYTE*", $pbPassword, "ULONG", $cbPassword, "BYTE*", $pbSalt, "ULONG", $cbSalt, "UINT64", $cIterations, "BYTE*", $pbDerivedKey, "ULong", $cbDerivedKey, "Ulong", $dwFlags)

   Return $pbDerivedKey
EndFunc

I have separated it into two lines. The handle call and the rest. (To help in troubleshooting)

1. I changed handle, ulonglong and Puchar based off the code i found here 

2. I also changed the variables names to match those in the Microsoft documentation (to make it easier to understand )

3. I also changed __Crypt_DllHandle(), "bool", "BCryptDeriveKeyPBKDF2", "handle*", 0, from __Crypt_DllHandle(), "bool", "BCryptDeriveKeyPBKDF2", "handle", 
To closer match what is in the crypt.au3

4. According to, should be Handle* infact be ptr ?

Though the code is sill isn't working

Edited by IanN1990
Link to comment
Share on other sites

You're code is wrong. 

 

First  __Crypt_DllHandle() returns a handle to Advapi32 .

then before  use BCryptDeriveKeyPBKDF2 you need to get a BCRYPT_ALG_HANDLE using  BCryptOpenAlgorithmProvider.

Saludos

Link to comment
Share on other sites

My heart sank when i read, without fully understanding one dllcall i need to call another :(

https://msdn.microsoft.com/en-us/library/windows/desktop/aa375479(v=vs.85).aspx <-- Function

#NoTrayIcon
#include "crypt.au3"
_Crypt_Startup()

PBKDF2("Password", "Salt", 100, 128)

Func PBKDF2($Password, $Salt, $Iterations = 10000, $Algo = "SHA1")
   Dim $pbPassword = $Password
   Dim $cbPassword = StringLen($Password)
   Dim $pbSalt = $Salt
   Dim $cbSalt = StringLen($Salt)
   Dim $cIterations = $Iterations
   Dim $pbDerivedKey
   Dim $cbDerivedKey = $Algo
   Dim $dwFlags = 0

   Dim $Handle = CryptOpenAlgorithmProvider($Algo)

   DllCall(__Crypt_DllHandle(), "bool", "BCryptDeriveKeyPBKDF2", "handle*", $Handle, _
   "BYTE*", $pbPassword, "ULONG", $cbPassword, "BYTE*", $pbSalt, "ULONG", $cbSalt, "UINT64", $cIterations, "BYTE*", $pbDerivedKey, "ULong", $cbDerivedKey, "Ulong", $dwFlags)

   Return $pbDerivedKey
EndFunc

Func CryptOpenAlgorithmProvider($Algo)
   Dim $BCRYPT_ALG_HANDLE
   Dim $pszAlgId = $Algo
   Dim $pszImplementation = Null ;??
   Dim $dwFlags = 0

   DllCall(__Crypt_DllHandle(), "bool", "BCryptOpenAlgorithmProvider", "handle*", $BCRYPT_ALG_HANDLE, "wstr", $pszAlgId, "wstr", $pszImplementation, "DWORD", $dwFlags)

   Return $BCRYPT_ALG_HANDLE
EndFunc

How far am i off the mark now?

Edited by IanN1990
Link to comment
Share on other sites

You're close. So __Crypt_DllHandle is no the handle of the dll. simply  BcryptHandle=dllopen( "Bcrypt.dll ")

 

If you going to pass the parameter as byte array you need to create a structure. Or just past as string(str) the out need to be a ptr to a buffer.

 

Saludos

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...