CNG (Cryptography API: Next Generation)

Post your working scripts, libraries and tools for AHK v1.1 and older
pneumatic
Posts: 338
Joined: 05 Dec 2016, 01:51

Re: CNG (Cryptography API: Next Generation)

22 Feb 2019, 06:43

Thank you jNizM for providing these very useful functions.

I plan on using them to encrypt a hash of my script's executable so it won't run if it's tampered with.

I am interested in using the encryption AES + CBC posted on page 1.

I see the encrypt function takes an Initialisation Vector and a Key as its parameters.

I notice in the example you have set these to some numeric strings with a predictable pattern. Would this be a problem for security and should I use random characters instead? Can I use any alphanumerical characters for these parameters or will it break the function if I use an illegal character? What range of characters are legal and valid?

Thanks
TheHacker
Posts: 29
Joined: 24 Apr 2017, 07:53

Re: CNG (Cryptography API: Next Generation)

22 Feb 2019, 07:27

I actually wanted to ask a similar question to pneumatic's - if I want the same string (plaintext) encrypted using the same password to result in a different ciphertext each time, should I change the IV each time or should I salt the string each time (using some random salt)?

Thank you.
pneumatic
Posts: 338
Joined: 05 Dec 2016, 01:51

Re: CNG (Cryptography API: Next Generation)

22 Feb 2019, 10:01

Because the encryption functions use crypt32.dll and does not explicitly load it with DllCall("LoadLibrary") I wanted to add it to the static variables in the class definition like so:

Code: Select all

static hBCRYPT := DllCall("LoadLibrary", "str", "bcrypt.dll", "ptr")
static hCRYPT32 := DllCall("LoadLibrary", "str", "crypt32.dll", "ptr")
However I found that this causes autohotkey 1.1.24.03 to crash under certain circumstances when encrypt() is called. Strangely if I display a MsgBox immediately before calling the encrypt() function, it prevents the crash. If I call encrypt() from a hotkey it also does not crash. SetBatchlines and Critical don't affect it. Moving the LoadLibrary calls to inside the encrypt() function prevents the crash, but still crashes if Reload is used. Reversing the order of loading the dll's prevents it from crashing on Reload. If I convert all of the code from a class to just 2 functions not inside any class, it doesn't crash, regardless of order. Note: LoadLibrary can be called many times as Windows keeps track of what modules the process has already loaded and won't keep reloading it https://stackoverflow.com/questions/3497516/does-loadlibrary-create-distinct-instances.
Last edited by pneumatic on 22 Feb 2019, 12:25, edited 5 times in total.
pneumatic
Posts: 338
Joined: 05 Dec 2016, 01:51

Re: CNG (Cryptography API: Next Generation)

22 Feb 2019, 11:03

jNizM wrote:
15 Sep 2016, 07:26

Code: Select all

    encrypt(string, iv, key)
    {
        this.CloseAlgorithmProvider(ALG_HANDLE)   
    }

    decrypt(string, iv, key)
    { 
        this.CloseAlgorithmProvider(ALG_HANDLE)    
    }

Should these be this.BCryptCloseAlgorithmProvider?

After changing the above, my encrypted strings are longer and are not case sensitive.
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: CNG (Cryptography API: Next Generation)

13 Mar 2019, 09:39

Update
- Removed the "Win10" part (-> https://www.autohotkey.com/boards/viewtopic.php?p=263180#p263180)
- Whole hash code is rewritten.
- Added error handling from Helgef
- Added file handling from just me

todo:
- Rewrite the Class

Thanks to all tester. Please report any other bugs you find.
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: CNG (Cryptography API: Next Generation)

13 Mar 2019, 11:38

Hello jNizM, thanks again for these functions. Is it so important to have separate functions for every algorithm? Is that for performance? I've combined all of my hashing needs into 4 functions. These functions are working but I intend to tidy them further. Thanks.

JEE_FileGetHashBCrypt(vPath, vAlg, vDoLoadFree:=1)
JEE_BinGetHashBCrypt(vAddr, vSize, vAlg, vDoLoadFree:=1)
JEE_FileGetHashCRC32(vPath)
JEE_BinGetHashCRC32(vAddr, vSize)

Code: Select all

;==================================================

;based on bcrypt_sha1_file() by jNizM
;AHK_CNG/src/hash/win7 at master · jNizM/AHK_CNG · GitHub
;https://github.com/jNizM/AHK_CNG/tree/master/src/hash/win7

;vAlg e.g. MD2,MD4,MD5,SHA1,SHA256,SHA384,SHA512
;note: doesn't handle CRC-32
;CNG Algorithm Identifiers - Windows applications | Microsoft Docs
;https://docs.microsoft.com/en-gb/windows/desktop/SecCNG/cng-algorithm-identifiers

JEE_FileGetHashBCrypt(vPath, vAlg, vDoLoadFree:=1)
{
	local
	static BCRYPT_OBJECT_LENGTH := "ObjectLength"
	static BCRYPT_HASH_LENGTH := "HashDigestLength"

	if InStr(vAlg, "-")
		vAlg := StrReplace(vAlg, "-")

	hAlgo := cbHashObject := cbResult := cbHash := hHash := 0

	if vDoLoadFree && !(hBCRYPT := DllCall("LoadLibrary", "str", "bcrypt.dll", "ptr"))
		return
	if (NT_STATUS := DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hAlgo, "ptr", &vAlg, "ptr", 0, "uint", 0) != 0)
		return
	if (NT_STATUS := DllCall("bcrypt\BCryptGetProperty", "ptr", hAlgo, "ptr", &BCRYPT_OBJECT_LENGTH, "uint*", cbHashObject, "uint", 4, "uint*", cbResult, "uint", 0) != 0)
		return
	if (NT_STATUS := DllCall("bcrypt\BCryptGetProperty", "ptr", hAlgo, "ptr", &BCRYPT_HASH_LENGTH, "uint*", cbHash, "uint", 4, "uint*", cbResult, "uint", 0) != 0)
		return

	VarSetCapacity(pbHashObject, cbHashObject, 0)
	if (NT_STATUS := DllCall("bcrypt\BCryptCreateHash", "ptr", hAlgo, "ptr*", hHash, "ptr", &pbHashObject, "uint", cbHashObject, "ptr", 0, "uint", 0, "uint", 0) != 0)
		return

	if !(oFile := FileOpen(vPath, "r", "UTF-8"))
		return
	oFile.Seek(0)
	while (vBytesRead := oFile.RawRead(vData, 0x40000))
		if (NT_STATUS := DllCall("bcrypt\BCryptHashData", "ptr", hHash, "ptr", &vData, "uint", vBytesRead, "uint", 0) != 0)
			return
	oFile.Close()

	VarSetCapacity(pbHash, cbHash, 0)
	if (NT_STATUS := DllCall("bcrypt\BCryptFinishHash", "ptr", hHash, "ptr", &pbHash, "uint", cbHash, "uint", 0) != 0)
		return

	hash := ""
	Loop, % cbHash
		hash .= Format("{:02x}", NumGet(pbHash, A_Index - 1, "uchar"))

	DllCall("bcrypt\BCryptDestroyHash", "ptr", hHash)
	DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hAlgo, "uint", 0)
	if vDoLoadFree
		DllCall("FreeLibrary", "ptr", hBCRYPT)

	return hash
}

;==================================================

JEE_BinGetHashBCrypt(vAddr, vSize, vAlg, vDoLoadFree:=1)
{
	local
	static BCRYPT_OBJECT_LENGTH := "ObjectLength"
	static BCRYPT_HASH_LENGTH := "HashDigestLength"

	if InStr(vAlg, "-")
		vAlg := StrReplace(vAlg, "-")

	hAlgo := cbHashObject := cbResult := cbHash := hHash := 0

	if vDoLoadFree && !(hBCRYPT := DllCall("LoadLibrary", "str", "bcrypt.dll", "ptr"))
		return
	if (NT_STATUS := DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hAlgo, "ptr", &vAlg, "ptr", 0, "uint", 0) != 0)
		return
	if (NT_STATUS := DllCall("bcrypt\BCryptGetProperty", "ptr", hAlgo, "ptr", &BCRYPT_OBJECT_LENGTH, "uint*", cbHashObject, "uint", 4, "uint*", cbResult, "uint", 0) != 0)
		return
	if (NT_STATUS := DllCall("bcrypt\BCryptGetProperty", "ptr", hAlgo, "ptr", &BCRYPT_HASH_LENGTH, "uint*", cbHash, "uint", 4, "uint*", cbResult, "uint", 0) != 0)
		return

	VarSetCapacity(pbHashObject, cbHashObject, 0)
	if (NT_STATUS := DllCall("bcrypt\BCryptCreateHash", "ptr", hAlgo, "ptr*", hHash, "ptr", &pbHashObject, "uint", cbHashObject, "ptr", 0, "uint", 0, "uint", 0) != 0)
		return

	if (NT_STATUS := DllCall("bcrypt\BCryptHashData", "ptr", hHash, "ptr", vAddr, "uint", vSize, "uint", 0) != 0)
		return

	VarSetCapacity(pbHash, cbHash, 0)
	if (NT_STATUS := DllCall("bcrypt\BCryptFinishHash", "ptr", hHash, "ptr", &pbHash, "uint", cbHash, "uint", 0) != 0)
		return

	hash := ""
	Loop, % cbHash
		hash .= Format("{:02x}", NumGet(pbHash, A_Index - 1, "uchar"))

	DllCall("bcrypt\BCryptDestroyHash", "ptr", hHash)
	DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hAlgo, "uint", 0)
	if vDoLoadFree
		DllCall("FreeLibrary", "ptr", hBCRYPT)

	return hash
}

;==================================================

;based on CRC32_File() by jNizM
;however, the output is uppercase/no '0x'/always 8 characters
;AHK_Scripts/src/hash_checksum at master · jNizM/AHK_Scripts · GitHub
;https://github.com/jNizM/AHK_Scripts/tree/master/src/hash_checksum
;get CRC-32 hash value, read file in chunks - AutoHotkey Community
;https://autohotkey.com/boards/viewtopic.php?f=5&t=31329

;Wine API: RtlComputeCrc32
;https://source.winehq.org/WineAPI/RtlComputeCrc32.html

JEE_FileGetHashCRC32(vPath)
{
	local
	if !(oFile := FileOpen(vPath, "r", "UTF-8"))
		return
	oFile.Seek(0)
	vHash := 0
	while (vBytesRead := oFile.RawRead(vData, 0x40000))
		vHash := DllCall("ntdll\RtlComputeCrc32", UInt,vHash, Ptr,&vData, Int,vBytesRead, UInt)
	oFile.Close()
	return Format("{:08X}", vHash)
}

;==================================================

JEE_BinGetHashCRC32(vAddr, vSize, vDoLoadFree:=1)
{
	local
	vHash := 0
	vHash := DllCall("ntdll\RtlComputeCrc32", UInt,vHash, Ptr,vAddr, Int,vSize, UInt)
	return Format("{:08X}", vHash)
}

;==================================================
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: CNG (Cryptography API: Next Generation)

14 Mar 2019, 05:06

Hey jeeswg,

I make the individual functions available so that people can only use the functions they need, for example, for their work. (e.g. just SHA2/512)

I will also provide 3 functions where users can select the hash function. (Data / HMAC / File).

After the rewrite, the one class is also usable for everything.
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: CNG (Cryptography API: Next Generation)

27 Mar 2019, 01:55

Thanks for the info. Is there any reason you chose to use chunks of 0x40000 bytes? Could using bigger chunks make it faster? Can it be any number, or are there some restrictions? Thanks.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: CNG (Cryptography API: Next Generation)

27 Mar 2019, 04:40

Hey. Atm I use 262144 bytes (256 kb), but I plan to make the bytes as function parameter, so everyone can easy change them. Will also change them to 1024 kb (1 mb)

Sure you can use any higher number, as soon you has enough memory.

I prefer the JEDEC memory standards (https://en.wikipedia.org/wiki/JEDEC_memory_standards#Unit_prefixes_for_semiconductor_storage_capacity) and the steps 64 / 128 / 256 / 512 / 1024 / 2048 /...
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: CNG (Cryptography API: Next Generation)

28 Mar 2019, 06:07

Update:
- Added variable chunk size for file hashing (default is now 1048576 bytes [1024 kb / 1 mb])
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
iPhilip
Posts: 799
Joined: 02 Oct 2013, 12:21

Re: CNG (Cryptography API: Next Generation)

11 Apr 2019, 20:41

jNizM wrote:
15 Sep 2016, 07:26

Code: Select all

class bcrypt
{
    ...
    static BCRYPT_OPAQUE_KEY_BLOB := "OpaqueKeyBlob"  ; <<< This static variable is not used in the class. It can be deleted.
    ...
    
    encrypt(string, iv, key)
    {
        ...
        this.CloseAlgorithmProvider(ALG_HANDLE)  ; <<< This should be this.BCryptCloseAlgorithmProvider(ALG_HANDLE)
        ...
    }

    decrypt(string, iv, key)
    {
        ...
        this.CloseAlgorithmProvider(ALG_HANDLE)  ; <<< This should be this.BCryptCloseAlgorithmProvider(ALG_HANDLE)
        return StrGet(&CIPHER_DATA, CIPHER_LENGTH /= 2, "utf-16")  ; <<< Should this be ..., CIPHER_LENGTH // 2, ... ?
    }

    BCryptEncrypt(BCRYPT_KEY_HANDLE, STRING, IV, cbIV, ByRef pbOutput)
    {
        ...
        if (NT_STATUS := DllCall("bcrypt\BCryptEncrypt", "ptr",   BCRYPT_KEY_HANDLE
                                                       , "ptr",   &pbInput
                                                       , "uint",  cbInput
                                                       , "ptr",   0
                                                       , "ptr",   &pbIV
                                                       , "uint",  cbIV
                                                       , "ptr",   0
                                                       , "uint",  0
                                                       , "uint*", cbOutput
                                                       , "uint",  BCRYPT_BLOCK_PADDING) != 0)  ; <<< BCRYPT_BLOCK_PADDING should be this.BCRYPT_BLOCK_PADDING
        ...
        if (NT_STATUS := DllCall("bcrypt\BCryptEncrypt", "ptr",   BCRYPT_KEY_HANDLE
                                                       , "ptr",   &pbInput
                                                       , "uint",  cbInput
                                                       , "ptr",   0
                                                       , "ptr",   &pbIV
                                                       , "uint",  cbIV
                                                       , "ptr",   &pbOutput
                                                       , "uint",  cbOutput
                                                       , "uint*", cbOutput
                                                       , "uint",  BCRYPT_BLOCK_PADDING) != 0)  ; <<< BCRYPT_BLOCK_PADDING should be this.BCRYPT_BLOCK_PADDING
        ...
    }

    BCryptDecrypt(BCRYPT_KEY_HANDLE, ByRef STRING, cbInput, IV, cbIV, ByRef pbOutput)
    {
        ...
        if (NT_STATUS := DllCall("bcrypt\BCryptDecrypt", "ptr",   BCRYPT_KEY_HANDLE
                                                       , "ptr",   &pbInput
                                                       , "uint",  cbInput
                                                       , "ptr",   0
                                                       , "ptr",   &pbIV
                                                       , "uint",  cbIV
                                                       , "ptr",   0
                                                       , "uint",  0
                                                       , "uint*", cbOutput
                                                       , "uint",  BCRYPT_BLOCK_PADDING) != 0)  ; <<< BCRYPT_BLOCK_PADDING should be this.BCRYPT_BLOCK_PADDING
        ...
        if (NT_STATUS := DllCall("bcrypt\BCryptDecrypt", "ptr",   BCRYPT_KEY_HANDLE
                                                       , "ptr",   &pbInput
                                                       , "uint",  cbInput
                                                       , "ptr",   0
                                                       , "ptr",   &pbIV
                                                       , "uint",  cbIV
                                                       , "ptr",   &pbOutput
                                                       , "uint",  cbOutput
                                                       , "uint*", cbOutput
                                                       , "uint",  BCRYPT_BLOCK_PADDING) != 0)  ; <<< BCRYPT_BLOCK_PADDING should be this.BCRYPT_BLOCK_PADDING
        ...
    }
}
Hi jNizM,

Thank you for the bcrypt class. I wanted to let you know about a few issues I found that you might want to correct in the original post. I marked them above with <<<.

Cheers!

- iPhilip
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: CNG (Cryptography API: Next Generation)

12 Apr 2019, 00:34

Hi iPhilip,

thanks for the reported issues. The class is still in development and will be updated soon.

As long as you can use the already rewritten functions.
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
iPhilip
Posts: 799
Joined: 02 Oct 2013, 12:21

Re: CNG (Cryptography API: Next Generation)

12 Apr 2019, 00:53

Hi jNizM,

Thank you for your great work. I am looking forward to the updated class. :thumbup:
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
iPhilip
Posts: 799
Joined: 02 Oct 2013, 12:21

Re: CNG (Cryptography API: Next Generation)

12 Apr 2019, 01:35

Hi jNizM,

I noticed some behavior that I don't understand. See the code below:

Code: Select all

MsgBox % crypt := bcrypt.encrypt("abcdefghijklmnop", "1234567890123456", "1234567890123456")
MsgBox % bcrypt.decrypt(crypt, "1234567890123456", "1234567890123456")

try
   MsgBox % crypt := bcrypt.encrypt("abcdefghijklmnop", "1234567890123456", "1234567890123456")
catch
   MsgBox I tried to encrypt...
try
   MsgBox % bcrypt.decrypt(crypt, "1234567890123456", "1234567890123456")
catch
   MsgBox I tried to decrypt...
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: CNG (Cryptography API: Next Generation)

06 Oct 2019, 08:52

Hey this is VERY nice and wanted to say thanks!!

How are you supposed to use a hash?
lets say i do this:

Code: Select all

;				  pbkdf2(Password, 		Salt, AlgID	  , Iterations, KeySize)
Clipboard:=bcrypt.pbkdf2("alexandreD7", "salt", "SHA256", 4096	  , 32)
; ==> dc00a73bc4a27f794dbca49c5870498e53e7e8489728c7888045ddd88e7330c2
Am I supposed to be able to reverse the hash like you decrypt a crypted message ??
If not, then how do we know what was the original string from a hash?

More details on my question:
Lets say I want to store my password in a Word doc and use AHK to login to a website with the password thats now stocked in the hash.
How do I get the hash data back so its back to the usable password?
TheHacker
Posts: 29
Joined: 24 Apr 2017, 07:53

Re: CNG (Cryptography API: Next Generation)

06 Oct 2019, 15:39

DRocks,
By definition, you cannot get the original string back from a hash. That's exactly what a hash is supposed to do - make it impossible to get the original data.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: CNG (Cryptography API: Next Generation)

06 Oct 2019, 17:39

- I think of a hash as a *summary* of data.
- It can be used in security: if I download a file, and generate a hash, does it match the hash stated on the website. If they don't match, I may have just downloaded a different (malicious) file with the same name.
- ... One problem is that it may be possible to create a malicious file, with a desired hash. If that is possible then the type of hash is said to be 'broken'.
- It can also be used to help identify duplicate files. If two files have the same hash (and file size), they *may* be the same file (there's a high likelihood, we can confirm this by comparing every byte). If two files have a different hash (or file size), they are different files.
- Any other uses, anyone? Cheers.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: CNG (Cryptography API: Next Generation)

06 Oct 2019, 19:04

Hey guys thanks for your replies.
I have spent the day on this topic and indeed after a while I came to what you said @TheHacker .

@jeeswg this is interesting as its a completly different way of using hashes and I didnt know about that. So if i get it, the source (if not salted), would always be the same output when hashed by the same algorithm and produce that kind of signature which u mentioned right?

Following this, I am questioning myself even more then on the part of Encrypt and Decrypt class made by JNizm..
How can we use hashing and AES for encryption and decryption then? I just dont get how the two can work together in light of the fact a hash cant be reversed??
TheHacker
Posts: 29
Joined: 24 Apr 2017, 07:53

Re: CNG (Cryptography API: Next Generation)

07 Oct 2019, 15:21

DRocks,
There are two separate functions of the class. One function is hashing (not used for encryption) and the other function is encryption (used for encryption).
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: CNG (Cryptography API: Next Generation)

07 Oct 2019, 15:35

In JNizm's there's no confusion about this, I am sorry I mistakenly interpreted it was his class but I am actually using another person's encryption class and there is this wierd concept which I quote here:
Crypt.Encrypt.StrEncrypt(string,password,CryptAlg = 1, HashAlg = 1)
Encrypts the string
Parameters:
string - UTF string, means any string you use in AHK_L Unicode
password - no way, it's just a password...
(optional) CryptAlg - Encryption algorithm ID, for details see below
(optional) HashAlg - hashing algorithm ID, for details see below
Return:
on success, - HASH representaion of encrypted buffer, which is easily transferable.
You can get actual encrypted buffer from HASH by using function HashToByte()
on fail, - ""
I mean this seems like he is combining hashing and encryption in the same function call but I guess we should not waste more time on this. Thanks for all your pointers :)

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 129 guests