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)

23 Nov 2019, 10:30

Since the library uses advapi32.dll to generate hashes, I am worried that maybe different Windows systems will have different versions of advapi32.dll in their System32 folder, which might use slightly different implementation, causing a different hash to be generated, which would break my entire app.

Is this a legitimate concern or am I being too OCD? Should I copy advapi32.dll into my A_ScriptDir to force it to use that version instead of the one in System32 which could be different between systems. edit: and is that even legal from a copyright point?
TheHacker
Posts: 29
Joined: 24 Apr 2017, 07:53

Re: CNG (Cryptography API: Next Generation)

23 Nov 2019, 15:33

pneumatic,
Every implementation of a given hash function (say, SHA256) must give the same hash, under any OS, under any circumstance. If it does not, the implementation is faulty.
pneumatic
Posts: 338
Joined: 05 Dec 2016, 01:51

Re: CNG (Cryptography API: Next Generation)

23 Nov 2019, 17:11

TheHacker wrote:
23 Nov 2019, 15:33
pneumatic,
Every implementation of a given hash function (say, SHA256) must give the same hash, under any OS, under any circumstance. If it does not, the implementation is faulty.
Yes, that does make sense.

I guess one other worry I have is that different versions of that dll might use different format parameters to the functions, like maybe an Int64 instead of an Int, or return an address instead of a Ptr to an address, and then my whole app breaks on that system.

But I doubt it, because Microsoft would know that doing stuff like that would break so many apps!

I think it should be fine. My goal is to prevent download aggregator sites from packing their own malware into my compiled ahk exe (or vice versa) by verifying the hash of the exe.
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: CNG (Cryptography API: Next Generation)

25 Nov 2019, 03:34

1. The lib uses bcrypt.dll and not advapi32.dll
2. Every correct implementation of a hash function gives the same results on every OS / WEB
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
pneumatic
Posts: 338
Joined: 05 Dec 2016, 01:51

Re: CNG (Cryptography API: Next Generation)

25 Nov 2019, 15:56

jNizM wrote:
25 Nov 2019, 03:34
The lib uses bcrypt.dll and not advapi32.dll
Sorry my mistake. For some reason I'm still using your older HashCalc library for the hashing and your new CNG for the encrypting. Not sure why I ended up doing it that way tbh :lol:
kyuuuri
Posts: 340
Joined: 09 Jan 2016, 19:20

Re: CNG (Cryptography API: Next Generation)

11 Jan 2020, 01:20

Hello, I'm trying to use your AES encryption / decryption class.
I want to move it to only 2 functions, 1 for decryption and 1 for encryption but I encountered an error I couldn't fix:

Code 1:

Code: Select all

hash := "f1461877468516263ea376f8588c8bc0c1413ca7712f9d4d5e624b95efda69c5"
VarSetCapacity(str, 128)
StrPut(hash, &str)
str := encrypt(hash, "1234567890123456", "431GddAtuifssBogjCkgdoswMasegvsA5fkd8/*4-fa@#d")
msgbox % decrypt(str, "1234567890123456", "431GddAtuifssBogjCkgdoswMasegvsA5fkd8/*4-fa@#d", 128)
return

decrypt(string, iv, key, len)
{
	global
	static BCRYPT_AES_ALGORITHM   := "AES"
    static BCRYPT_OBJECT_LENGTH   := "ObjectLength"
    static BCRYPT_BLOCK_LENGTH    := "BlockLength"
    static BCRYPT_CHAINING_MODE   := "ChainingMode"
    static BCRYPT_CHAIN_MODE_CBC  := "ChainingModeCBC"
    static BCRYPT_OPAQUE_KEY_BLOB := "OpaqueKeyBlob"
    static BCRYPT_BLOCK_PADDING   := 0x00000001
	static hBCRYPT := DllCall("LoadLibrary", "str", "bcrypt.dll", "ptr")
	
	DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", ALG_HANDLE, "ptr",  &BCRYPT_AES_ALGORITHM, "ptr",  0, "uint", 0)
	DllCall("bcrypt\BCryptGetProperty", "ptr", ALG_HANDLE, "ptr", &BCRYPT_OBJECT_LENGTH, "uint*", OBJECT_LENGTH, "uint", 4, "uint*", cbResult, "uint",  0)
	DllCall("bcrypt\BCryptGetProperty", "ptr", ALG_HANDLE, "ptr", &BCRYPT_BLOCK_LENGTH, "uint*", BLOCK_LENGTH, "uint", 4, "uint*", cbResult, "uint",  0)
	
	DllCall("bcrypt\BCryptSetProperty", "ptr", ALG_HANDLE, "ptr", &BCRYPT_CHAINING_MODE, "ptr", &BCRYPT_CHAIN_MODE_CBC, "uint", StrLen(BCRYPT_CHAIN_MODE_CBC), "uint", 0)
	VarSetCapacity(KEY_OBJECT, OBJECT_LENGTH, 0)
	VarSetCapacity(pbSecret, cbSecret := StrPut(KEY, "UTF-8"), 0) && StrPut(KEY, &pbSecret, "UTF-8"), cbSecret--
	DllCall("bcrypt\BCryptGenerateSymmetricKey", "ptr", ALG_HANDLE, "ptr*", KEY_HANDLE, "ptr", &KEY_OBJECT, "uint", OBJECT_LENGTH, "ptr", &pbSecret, "uint", cbSecret, "uint", 0)
	VarSetCapacity(pbInput, len, 0)
	DllCall("msvcrt\memcpy", "ptr", &pbInput, "ptr", &string, "ptr", len)
	VarSetCapacity(pbIV, BLOCK_LENGTH, 0)
	DllCall("msvcrt\memcpy", "ptr", &pbIV, "ptr", &iv, "ptr", BLOCK_LENGTH)
	DllCall("bcrypt\BCryptDecrypt", "ptr", KEY_HANDLE, "ptr", &pbInput, "uint", len, "ptr", 0, "ptr", &pbIV, "uint", BLOCK_LENGTH, "ptr", 0, "uint", 0, "uint*", CIPHER_LENGTH, "uint", BCRYPT_BLOCK_PADDING)
	VarSetCapacity(CIPHER_DATA, CIPHER_LENGTH, 0)
	
	; The next line is the only one that differs from Code2
	DllCall("bcrypt\BCryptDecrypt", "ptr", KEY_HANDLE, "ptr", &pbInput, "uint", len, "ptr", 0, "ptr", &pbIV, "uint", BLOCK_LENGTH, "ptr", &CIPHER_DATA, "uint", CIPHER_LENGTH, "uint*", CIPHER_LENGTH, "uint", BCRYPT_BLOCK_PADDING)

	DllCall("bcrypt.dll\BCryptDestroyKey", "ptr", KEY_HANDLE)
	DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr",  ALG_HANDLE, "uint", 0)
	return StrGet(&CIPHER_DATA, CIPHER_LENGTH /= 2, "utf-16")
}
Output: f1461877468516263ea376f8588c8bc0c1413ca7712f9d4d5e624b95 Incorrect
Expected: f1461877468516263ea376f8588c8bc0c1413ca7712f9d4d5e624b95efda69c5
Code 2:

Code: Select all

hash := "f1461877468516263ea376f8588c8bc0c1413ca7712f9d4d5e624b95efda69c5"
VarSetCapacity(str, 128)
StrPut(hash, &str)
str := encrypt(hash, "1234567890123456", "431GddAtuifssBogjCkgdoswMasegvsA5fkd8/*4-fa@#d")
msgbox % decrypt(str, "1234567890123456", "431GddAtuifssBogjCkgdoswMasegvsA5fkd8/*4-fa@#d", 128)
return

decrypt(string, iv, key, len)
{
	global
	static BCRYPT_AES_ALGORITHM   := "AES"
        static BCRYPT_OBJECT_LENGTH   := "ObjectLength"
        static BCRYPT_BLOCK_LENGTH    := "BlockLength"
        static BCRYPT_CHAINING_MODE   := "ChainingMode"
        static BCRYPT_CHAIN_MODE_CBC  := "ChainingModeCBC"
        static BCRYPT_OPAQUE_KEY_BLOB := "OpaqueKeyBlob"
        static BCRYPT_BLOCK_PADDING   := 0x00000001
	static hBCRYPT := DllCall("LoadLibrary", "str", "bcrypt.dll", "ptr")
	
	DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", ALG_HANDLE, "ptr",  &BCRYPT_AES_ALGORITHM, "ptr",  0, "uint", 0)
	DllCall("bcrypt\BCryptGetProperty", "ptr", ALG_HANDLE, "ptr", &BCRYPT_OBJECT_LENGTH, "uint*", OBJECT_LENGTH, "uint", 4, "uint*", cbResult, "uint",  0)
	DllCall("bcrypt\BCryptGetProperty", "ptr", ALG_HANDLE, "ptr", &BCRYPT_BLOCK_LENGTH, "uint*", BLOCK_LENGTH, "uint", 4, "uint*", cbResult, "uint",  0)
	
	DllCall("bcrypt\BCryptSetProperty", "ptr", ALG_HANDLE, "ptr", &BCRYPT_CHAINING_MODE, "ptr", &BCRYPT_CHAIN_MODE_CBC, "uint", StrLen(BCRYPT_CHAIN_MODE_CBC), "uint", 0)
	VarSetCapacity(KEY_OBJECT, OBJECT_LENGTH, 0)
	VarSetCapacity(pbSecret, cbSecret := StrPut(KEY, "UTF-8"), 0) && StrPut(KEY, &pbSecret, "UTF-8"), cbSecret--
	DllCall("bcrypt\BCryptGenerateSymmetricKey", "ptr", ALG_HANDLE, "ptr*", KEY_HANDLE, "ptr", &KEY_OBJECT, "uint", OBJECT_LENGTH, "ptr", &pbSecret, "uint", cbSecret, "uint", 0)
	VarSetCapacity(pbInput, len, 0)
	DllCall("msvcrt\memcpy", "ptr", &pbInput, "ptr", &string, "ptr", len)
	VarSetCapacity(pbIV, BLOCK_LENGTH, 0)
	DllCall("msvcrt\memcpy", "ptr", &pbIV, "ptr", &iv, "ptr", BLOCK_LENGTH)
	DllCall("bcrypt\BCryptDecrypt", "ptr", KEY_HANDLE, "ptr", &pbInput, "uint", len, "ptr", 0, "ptr", &pbIV, "uint", BLOCK_LENGTH, "ptr", 0, "uint", 0, "uint*", CIPHER_LENGTH, "uint", BCRYPT_BLOCK_PADDING)
	VarSetCapacity(CIPHER_DATA, CIPHER_LENGTH, 0)
	CIPHER_LENGTH := BCryptDecrypt(KEY_HANDLE, string, len, IV, BLOCK_LENGTH, CIPHER_DATA)
	
	

	DllCall("bcrypt.dll\BCryptDestroyKey", "ptr", KEY_HANDLE)

	DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr",  ALG_HANDLE, "uint", 0)
	return StrGet(&CIPHER_DATA, CIPHER_LENGTH /= 2, "utf-16")
}

BCryptDecrypt(BCRYPT_KEY_HANDLE, ByRef STRING, cbInput, IV, cbIV, ByRef pbOutput)
{
	global
	if (NT_STATUS := DllCall("bcrypt\BCryptDecrypt", "ptr",   BCRYPT_KEY_HANDLE
												   , "ptr",   &pbInput
												   , "uint",  cbInput
												   , "ptr",   0
												   , "ptr",   &pbIV
												   , "uint",  cbIV
												   , "ptr",   &pbOutput
												   , "uint",  CIPHER_LENGTH
												   , "uint*", CIPHER_LENGTH
												   , "uint",  BCRYPT_BLOCK_PADDING) != 0)
		throw Exception("BCryptDecrypt: " NT_STATUS, -1)
	return CIPHER_LENGTH
}
Output: f1461877468516263ea376f8588c8bc0c1413ca7712f9d4d5e624b95efda69c5 Correct
Expected: f1461877468516263ea376f8588c8bc0c1413ca7712f9d4d5e624b95efda69c5

For some reason in Code 1 the output is shorter, it's the same hash but with missing characters.
On Code 1: CIPHER_LENGTH = 112 Incorrect
On Code 2: CIPHER_LENGTH = 128 Correct

I don't know what's the problem there. I simply moved the DllCall inside the function and replaced the parameters with the real variables.

Thanks in advance.
guest3456
Posts: 3454
Joined: 09 Oct 2013, 10:31

Re: CNG (Cryptography API: Next Generation)

15 Jun 2020, 22:29

it looks like the hashes are returned as a string.. but if we want to extend this lib to support public/private key signatures, we need the raw pointer (pbHash) and length (cbHash) values.. wonder if those should be returned ByRef..

User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: CNG (Cryptography API: Next Generation)

14 Sep 2020, 08:45

Update:
Almost finished with the rewriting of the class.

String Encryption / Decryption works so far. Output and Input can be Base64, Hex and Hexraw. Will also add address as output.

Code: Select all

Tested Encryption Modes and compared to online tools:

String:				abcdefghijklmnop
Key:				1234567890123456
IV:					1234567890123456

AES:				/K1xW9c7XLBIj4QPO614iYgkP6qA8mq6P5BuTJlpxHY=
AES + ECB:			/K1xW9c7XLBIj4QPO614iQUBh6DN5amHLLqwkatz5VM=
AES + CBC:			/K1xW9c7XLBIj4QPO614iYgkP6qA8mq6P5BuTJlpxHY=
AES + CBC + IV:		Nn9CFFuC+/O84cV1NiwLYoyd25Z9nmWv16dIFKzf2b4=
AES + CFB:			ubiN18vgxzKBhLW8KTbOg+Q58WBFqUOIxJ7h4wM+rZo=
AES + CFB + IV:		FKUzKP7ugBs+5nsv1if+oOFtnUmtoktyxF+i+7qLxW8=

DES:				lNRDa8O1tpMGxRfbSbuOmWecXPe5GjQY
DES + ECB:			lNRDa8O1tpO7mzmIt78IUP65WbfUZC/L
DES + CBC:			lNRDa8O1tpMGxRfbSbuOmWecXPe5GjQY

RC2:				403xbnkYjoJLMcGIwOQJqhE4Mhc4HfkE

RC4:				QdLw1UGDq+F6q3SI5ZqwiQ==
[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)

15 Sep 2020, 05:13

Update:
Github updated
Initial Forum Post updated
2nd and 3rd Forum Post (examples) updated.


Feel free to test the rewritten post and report bugs or issues here.

Function I used to create Files with random bytes for testings

Code: Select all

CreateRandomBytesFile("test_2MB", 2097152)

CreateRandomBytesFile(file, bytes) {
	if (f := FileOpen(file, "w", "utf-8")) {
		f.Pos(0)
		while(f.Length < bytes) {
			Random, rand, 0, 255
			f.Write(Chr(rand))
		}
		f.Close()
		return true
	}
	return false
}

That might have cost me a few nerves (german saying) :D
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
User avatar
TheArkive
Posts: 1027
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

Re: CNG (Cryptography API: Next Generation)

01 Nov 2020, 05:00

Could this possibly be used to replicate TLS v1.2 or v1.3 protocol over socket connections?
user16749
Posts: 6
Joined: 15 Dec 2020, 18:40

Re: CNG (Cryptography API: Next Generation)

26 Dec 2020, 06:20

Hi!

I'm having issues trying to replicate a SHA1 value, what can be wrong? Thanks in advance

Code: Select all

key := "48656c6c6f21deadbeef"
data := "000000000273ef07"
hmac := bcrypt_sha1_hmac(data, key)
; -> 387da26a70023b017fa0e8f57999ef6cd1a818fb
Expected: 96b1be00bda9c81cfc4a58f0ad9ff12f5ece03ef

References:
  • https://caligatio.github.io/jsSHA/
  • https://i.imgur.com/eNxO5zR.png
Seems like board doesn't allows links or images
Last edited by user16749 on 02 Jan 2021, 07:25, edited 1 time in total.
kyuuuri
Posts: 340
Joined: 09 Jan 2016, 19:20

Re: CNG (Cryptography API: Next Generation)

26 Dec 2020, 06:37

Hello, the result matches for me. I get 387da26a70023b017fa0e8f57999ef6cd1a818fb on the script and the webpage, where did you get the expected value from?
Try this website: https://www.freeformatter.com/hmac-generator.html#ad-output
user16749
Posts: 6
Joined: 15 Dec 2020, 18:40

Re: CNG (Cryptography API: Next Generation)

02 Jan 2021, 07:29

Yes I get the same result as you but is wrong. Check the references I provided (just updated the image as imgur took it down). In the past I've used jsSHA and seems ok, never had an interoperability issue. Now the part I'm trying to do in AHK must match the one made with jsSHA (I didn't write the JS part, just consuming it).
kyuuuri
Posts: 340
Joined: 09 Jan 2016, 19:20

Re: CNG (Cryptography API: Next Generation)

02 Jan 2021, 20:20

user16749 wrote:
02 Jan 2021, 07:29
Yes I get the same result as you but is wrong. Check the references I provided (just updated the image as imgur took it down). In the past I've used jsSHA and seems ok, never had an interoperability issue. Now the part I'm trying to do in AHK must match the one made with jsSHA (I didn't write the JS part, just consuming it).
Hi, the result is not wrong. If you use hmac with sha1 the correct result is: 387da26a70023b017fa0e8f57999ef6cd1a818fb. Where did you get this "96b1be00bda9c81cfc4a58f0ad9ff12f5ece03ef" from?
https://caligatio.github.io/jsSHA/
https://www.freeformatter.com/hmac-generator.html
https://codebeautify.org/hmac-generator

All these sites, even the script output 387da26a70023b017fa0e8f57999ef6cd1a818fb which is the correct result.


Edit: Now I see your image, you selected "hex" and it's not hex input, it's text.
user16749
Posts: 6
Joined: 15 Dec 2020, 18:40

Re: CNG (Cryptography API: Next Generation)

03 Jan 2021, 15:32

Yes it has to be hex, those are bytes not text. And I guess that's the issue with AHK implementation.. I've tried all the possible combinations with `0x##` and I get different hashes but never the expected.
User avatar
jNizM
Posts: 3183
Joined: 30 Sep 2013, 01:33
Contact:

Re: CNG (Cryptography API: Next Generation)

04 Jan 2021, 06:05

updated the class

MsgBox % Crypt.Hash.HMAC("SHA1", "000000000273ef07", "48656c6c6f21deadbeef", "hex") returns now 96b1be00bda9c81cfc4a58f0ad9ff12f5ece03ef
MsgBox % Crypt.Hash.HMAC("SHA1", 0x000000000273ef07, 0x48656c6c6f21deadbeef, "hex") is also possible
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
serzh82saratov
Posts: 137
Joined: 01 Jul 2017, 03:04

Re: CNG (Cryptography API: Next Generation)

05 Jan 2021, 15:41

:xmas:

Code: Select all

Encrypt := Crypt.Encrypt.String("AES", "CBC", "abcdefghijklmnop abcdefghijklmnop", "1234567890123456", "1234567890123456")

MsgBox % Crypt.Decrypt.String("AES", "CBC", Encrypt, "1234567890123456", "123")
And what is IV needed for if it changes only the first characters in the entire line?
serzh82saratov
Posts: 137
Joined: 01 Jul 2017, 03:04

Re: CNG (Cryptography API: Next Generation)

06 Jan 2021, 08:00

I'll try to ask my question in a different way. Why do you need a second key if you can easily recover data without it?

Code: Select all

text = 
(
abcdefghijklmnop
abcdefghijklmnop
abcdefghijklmnop
abcdefghijklmnop
abcdefghijklmnop
abcdefghijklmnop
abcdefghijklmnop
abcdefghijklmnop
)
Encrypt := Crypt.Encrypt.String("AES", "CBC", text, "1234567890123456", "qwerty")

MsgBox % Crypt.Decrypt.String("AES", "CBC", Encrypt, "1234567890123456", "")
user16749
Posts: 6
Joined: 15 Dec 2020, 18:40

Re: CNG (Cryptography API: Next Generation)

06 Jan 2021, 09:00

jNizM wrote:
04 Jan 2021, 06:05
updated the class
Thank you so much, working as expected.
kyuuuri
Posts: 340
Joined: 09 Jan 2016, 19:20

Re: CNG (Cryptography API: Next Generation)

06 Jan 2021, 12:56

serzh82saratov wrote:
06 Jan 2021, 08:00
I'll try to ask my question in a different way. Why do you need a second key if you can easily recover data without it?

Code: Select all

text = 
(
abcdefghijklmnop
abcdefghijklmnop
abcdefghijklmnop
abcdefghijklmnop
abcdefghijklmnop
abcdefghijklmnop
abcdefghijklmnop
abcdefghijklmnop
)
Encrypt := Crypt.Encrypt.String("AES", "CBC", text, "1234567890123456", "qwerty")

MsgBox % Crypt.Decrypt.String("AES", "CBC", Encrypt, "1234567890123456", "")
Hello, it's not a second key, it's an Initialization vector. You can read more about it here: https://en.wikipedia.org/wiki/Initialization_vector

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: gwarble and 112 guests