CNG (Cryptography API: Next Generation)

Post your working scripts, libraries and tools
pneumatic
Posts: 299
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: 28
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: 299
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: 2665
Joined: 30 Sep 2013, 01:33
GitHub: jNizM
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] 1.1.32.00 x64 Unicode | [WIN] 10 Pro (Version 2004) x64 | [GitHub] Profile
Donations are appreciated if I could help you
pneumatic
Posts: 299
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: 329
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/*[email protected]#d")
msgbox % decrypt(str, "1234567890123456", "431GddAtuifssBogjCkgdoswMasegvsA5fkd8/*[email protected]#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/*[email protected]#d")
msgbox % decrypt(str, "1234567890123456", "431GddAtuifssBogjCkgdoswMasegvsA5fkd8/*[email protected]#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: 3150
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: 2665
Joined: 30 Sep 2013, 01:33
GitHub: jNizM
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] 1.1.32.00 x64 Unicode | [WIN] 10 Pro (Version 2004) x64 | [GitHub] Profile
Donations are appreciated if I could help you
User avatar
jNizM
Posts: 2665
Joined: 30 Sep 2013, 01:33
GitHub: jNizM
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] 1.1.32.00 x64 Unicode | [WIN] 10 Pro (Version 2004) x64 | [GitHub] Profile
Donations are appreciated if I could help you
User avatar
TheArkive
Posts: 391
Joined: 05 Aug 2016, 08:06
GitHub: TheArkive

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?

Return to “Scripts and Functions”

Who is online

Users browsing this forum: mikeyww and 23 guests