CNG (Cryptography API: Next Generation)

Post your working scripts, libraries and tools for AHK v1.1 and older
serzh82saratov
Posts: 137
Joined: 01 Jul 2017, 03:04

Re: CNG (Cryptography API: Next Generation)

Post by serzh82saratov » 06 Jan 2021, 13:56

Thank you. That is, it complicates hacking. But how reliable is a CBC 256 bit and an empty IV?

kyuuuri
Posts: 340
Joined: 09 Jan 2016, 19:20

Re: CNG (Cryptography API: Next Generation)

Post by kyuuuri » 07 Jan 2021, 04:25

serzh82saratov wrote:
06 Jan 2021, 13:56
Thank you. That is, it complicates hacking. But how reliable is a CBC 256 bit and an empty IV?
That question is more related to cryptography than to this thread, remember that knowing how to use a function doesn't mean you know exactly how it works. Cryptography is very complex and requires a lot of time to learn why things are implemented the way they are, instead of copy pasting an answer from other site I will link you directly to it: https://crypto.stackexchange.com/questions/8600/why-should-i-use-an-initialization-vector-iv-when-i-have-unique-keys

Don't get me wrong, I'm not saying "you can't ask that here", I'm just saying that while there might be people here with good knowledge in cryptography this forum/thread is not dedicated to cryptography.
The cryptography stackexchange site is a good place to search that kind of questions.

Hope that helps

serzh82saratov
Posts: 137
Joined: 01 Jul 2017, 03:04

Re: CNG (Cryptography API: Next Generation)

Post by serzh82saratov » 07 Jan 2021, 06:23

Thanks for the good answer. I understand that cryptography is difficult, I would even say very much, so I am not looking for a truth here that I cannot understand. I just want to get public opinion.

DefrostedChemist
Posts: 2
Joined: 02 Feb 2021, 15:22

Re: CNG (Cryptography API: Next Generation)

Post by DefrostedChemist » 02 Feb 2021, 16:08

Hello jNizM,

First and foremost, thank you for your effort putting Class_CNG together for use with AHK.

I have not gotten the examples to work, but I believe its due to something simple caused by my inexperience.

I'm running AHK version 1.1.32.00 and Win10. I'm using what I believe is the latest version of your Class_CNG.ahk code updated 04-Jan-2021 from github. (Though your September 2020 version gave me the same result.)

I attempted to run your String with AES + CBC and with Key + IV and Base64 encode/decode examples.
Quoted Examples

My test script was as follows:

Code: Select all

#Include Class_CNG_Jan2021.ahk
;Examples:
;;;;Encrypt a String with AES + CBC and with Key + IV and Base64 Output
MsgBox % Crypt.Encrypt.String("AES", "CBC", "abcdefghijklmnop", "1234567890123456", "1234567890123456")
;;;; -> Nn9CFFuC+/O84cV1NiwLYoyd25Z9nmWv16dIFKzf2b4=

;;;;Decrypt a String with AES + CBC and with Key + IV and Base64 Input
MsgBox % Crypt.Decrypt.String("AES", "CBC", "Nn9CFFuC+/O84cV1NiwLYoyd25Z9nmWv16dIFKzf2b4=", "1234567890123456", "1234567890123456")
;;;; -> abcdefghijklmnop
When running this, the encode works and gives the expected result, but the decode throws the following error.
Specifically:

Code: Select all

---------------------------
Encrypt_Test.ahk
---------------------------
Error in #include file "U:\AHK\EncodeDecode\Class_CNG_Jan2021.ahk":
     A12

	Line#
	411: DllCall("bcrypt\BCryptDestroyHash", "ptr", hHash)  
	412: }
	416: {
	417: DllCall("bcrypt\BCryptDestroyKey", "ptr", hKey)  
	418: }
	422: {
	423: VarSetCapacity(pbInput, cbInput, 0)  
--->	424: DllCall("msvcrt\memcpy", "ptr", &pbInput, "ptr", &String, "ptr", cbInput)  
	426: if (IV != "")  
	427: {
	428: cbIV := VarSetCapacity(pbIV, BCRYPT_BLOCK_LENGTH, 0)
	429: StrPut(IV, &pbIV, BCRYPT_BLOCK_LENGTH, Encoding)  
	430: }
	432: NT_STATUS := DllCall("bcrypt\BCryptDecrypt", "ptr",   hKey, "ptr",   &pbInput, "uint",  cbInput, "ptr",   0, "ptr",   (pbIV ? &pbIV : 0), "uint",  (cbIV ? &cbIV : 0), "ptr",   0, "uint",  0, "uint*", cbOutput, "uint",  dwFlags)
	442: if (NT_STATUS = this.STATUS_SUCCESS)  

The current thread will exit.
---------------------------
OK   
---------------------------
And below is the entirety of the lines run by my test script.

Code: Select all

---- U:\AHK\EncodeDecode\Class_CNG_Jan2021.ahk
364: Crypt.BCrypt.hBCRYPT := DllCall("LoadLibrary", "str", "bcrypt.dll", "ptr")  
365: Crypt.BCrypt.STATUS_SUCCESS := 0  
645: Crypt.Helper.hCRYPT32 := DllCall("LoadLibrary", "str", "crypt32.dll", "ptr")   (0.03)
649: CRYPT_STRING := { "BASE64": 0x1, "BINARY": 0x2, "HEX": 0x4, "HEXRAW": 0xc }
650: CRYPT_STRING_NOCRLF := 0x40000000
674: CRYPT_STRING := { "BASE64": 0x1, "BINARY": 0x2, "HEX": 0x4, "HEXRAW": 0xc }
771: Crypt.Constants.BCRYPT_ALG_HANDLE_HMAC_FLAG := 0x00000008  
772: Crypt.Constants.BCRYPT_BLOCK_PADDING := 0x00000001  
776: Crypt.Constants.BCRYPT_CIPHER_OPERATION := 0x00000001  
777: Crypt.Constants.BCRYPT_HASH_OPERATION := 0x00000002  
778: Crypt.Constants.BCRYPT_ASYMMETRIC_ENCRYPTION_OPERATION := 0x00000004  
779: Crypt.Constants.BCRYPT_SECRET_AGREEMENT_OPERATION := 0x00000008  
780: Crypt.Constants.BCRYPT_SIGNATURE_OPERATION := 0x00000010  
781: Crypt.Constants.BCRYPT_RNG_OPERATION := 0x00000020  
782: Crypt.Constants.BCRYPT_KEY_DERIVATION_OPERATION := 0x00000040  
786: Crypt.Constants.BCRYPT_3DES_ALGORITHM := "3DES"  
787: Crypt.Constants.BCRYPT_3DES_112_ALGORITHM := "3DES_112"  
788: Crypt.Constants.BCRYPT_AES_ALGORITHM := "AES"  
789: Crypt.Constants.BCRYPT_AES_CMAC_ALGORITHM := "AES-CMAC"  
790: Crypt.Constants.BCRYPT_AES_GMAC_ALGORITHM := "AES-GMAC"  
791: Crypt.Constants.BCRYPT_DES_ALGORITHM := "DES"  
792: Crypt.Constants.BCRYPT_DESX_ALGORITHM := "DESX"  
793: Crypt.Constants.BCRYPT_MD2_ALGORITHM := "MD2"  
794: Crypt.Constants.BCRYPT_MD4_ALGORITHM := "MD4"  
795: Crypt.Constants.BCRYPT_MD5_ALGORITHM := "MD5"  
796: Crypt.Constants.BCRYPT_RC2_ALGORITHM := "RC2"  
797: Crypt.Constants.BCRYPT_RC4_ALGORITHM := "RC4"  
798: Crypt.Constants.BCRYPT_RNG_ALGORITHM := "RNG"  
799: Crypt.Constants.BCRYPT_SHA1_ALGORITHM := "SHA1"  
800: Crypt.Constants.BCRYPT_SHA256_ALGORITHM := "SHA256"  
801: Crypt.Constants.BCRYPT_SHA384_ALGORITHM := "SHA384"  
802: Crypt.Constants.BCRYPT_SHA512_ALGORITHM := "SHA512"  
803: Crypt.Constants.BCRYPT_PBKDF2_ALGORITHM := "PBKDF2"  
804: Crypt.Constants.BCRYPT_XTS_AES_ALGORITHM := "XTS-AES"  
808: Crypt.Constants.BCRYPT_BLOCK_LENGTH := "BlockLength"  
809: Crypt.Constants.BCRYPT_CHAINING_MODE := "ChainingMode"  
810: Crypt.Constants.BCRYPT_CHAIN_MODE_CBC := "ChainingModeCBC"  
811: Crypt.Constants.BCRYPT_CHAIN_MODE_CCM := "ChainingModeCCM"  
812: Crypt.Constants.BCRYPT_CHAIN_MODE_CFB := "ChainingModeCFB"  
813: Crypt.Constants.BCRYPT_CHAIN_MODE_ECB := "ChainingModeECB"  
814: Crypt.Constants.BCRYPT_CHAIN_MODE_GCM := "ChainingModeGCM"  
815: Crypt.Constants.BCRYPT_HASH_LENGTH := "HashDigestLength"  
816: Crypt.Constants.BCRYPT_OBJECT_LENGTH := "ObjectLength"  
029: {
086: {
146: {
197: {
267: {
318: {
369: {
375: {
393: {
415: {
421: {
427: {
470: {
512: {
535: {
556: {
570: {
587: {
602: {
615: {
628: {
648: {
673: {
701: {
724: {
736: {
749: {
---- U:\AHK\EncodeDecode\Encrypt_Test.ahk
004: MsgBox,Crypt.Encrypt.String("AES", "CBC", "abcdefghijklmnop", "1234567890123456", "1234567890123456")
---- U:\AHK\EncodeDecode\Class_CNG_Jan2021.ahk
030: Try
033: if !(ALGORITHM_IDENTIFIER := Crypt.Verify.EncryptionAlgorithm(AlgId))  
737: Switch Algorithm
739: Return,Crypt.Constants.BCRYPT_AES_ALGORITHM
037: if !(ALG_HANDLE := Crypt.BCrypt.OpenAlgorithmProvider(ALGORITHM_IDENTIFIER))  
616: NT_STATUS := DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", phAlgorithm, "ptr",  &pszAlgId, "ptr",  pszImplementation, "uint", dwFlags)
621: if (NT_STATUS = this.STATUS_SUCCESS)  
622: Return,phAlgorithm
041: if (CHAINING_MODE := Crypt.Verify.ChainingMode(Mode))  
725: Switch ChainMode
727: Return,Crypt.Constants.BCRYPT_CHAIN_MODE_CBC
043: if !(Crypt.BCrypt.SetProperty(ALG_HANDLE, Crypt.Constants.BCRYPT_CHAINING_MODE, CHAINING_MODE))  
629: bInput := StrLen(pbInput)
630: NT_STATUS := DllCall("bcrypt\BCryptSetProperty", "ptr",   hObject, "ptr",   &pszProperty, "ptr",   &pbInput, "uint",  bInput, "uint",  dwFlags := 0)
636: if (NT_STATUS = this.STATUS_SUCCESS)  
637: Return,true
047: if !(KEY_HANDLE := Crypt.BCrypt.GenerateSymmetricKey(ALG_HANDLE, Key, Encoding))  
571: cbSecret := Crypt.Helper.StrPutVar(Key, pbSecret, Encoding)
702: if (Encoding = "hex")  
712: VarSetCapacity(Data, Length := StrPut(String, Encoding) * ((Encoding = "utf-16" || Encoding = "cp1200") ? 2 : 1) - 1)  
713: Return,StrPut(String, &Data, Length, Encoding)
572: NT_STATUS := DllCall("bcrypt\BCryptGenerateSymmetricKey", "ptr",  hAlgorithm, "ptr*", phKey, "ptr",  0, "uint", 0, "ptr",  &pbSecret, "uint", cbSecret, "uint", dwFlags := 0)
580: if (NT_STATUS = this.STATUS_SUCCESS)  
581: Return,phKey
051: if !(BLOCK_LENGTH := Crypt.BCrypt.GetProperty(ALG_HANDLE, Crypt.Constants.BCRYPT_BLOCK_LENGTH, 4))  
588: NT_STATUS := DllCall("bcrypt\BCryptGetProperty", "ptr",   hObject, "ptr",   &pszProperty, "uint*", pbOutput, "uint",  cbOutput, "uint*", pcbResult, "uint",  dwFlags := 0)
595: if (NT_STATUS = this.STATUS_SUCCESS)  
596: Return,pbOutput
055: cbInput := Crypt.Helper.StrPutVar(String, pbInput, Encoding)
702: if (Encoding = "hex")  
712: VarSetCapacity(Data, Length := StrPut(String, Encoding) * ((Encoding = "utf-16" || Encoding = "cp1200") ? 2 : 1) - 1)  
713: Return,StrPut(String, &Data, Length, Encoding)
056: if !(CIPHER_LENGTH := Crypt.BCrypt.Encrypt(KEY_HANDLE, pbInput, cbInput, IV, BLOCK_LENGTH, CIPHER_DATA, Crypt.Constants.BCRYPT_BLOCK_PADDING))  
473: if (IV != "")  
475: cbIV := VarSetCapacity(pbIV, BCRYPT_BLOCK_LENGTH, 0)
476: StrPut(IV, &pbIV, BCRYPT_BLOCK_LENGTH, Encoding)  
477: }
479: NT_STATUS := DllCall("bcrypt\BCryptEncrypt", "ptr",   hKey, "ptr",   &pbInput, "uint",  cbInput, "ptr",   0, "ptr",   (pbIV ? &pbIV : 0), "uint",  (cbIV ? &cbIV : 0), "ptr",   0, "uint",  0, "
489: if (NT_STATUS = this.STATUS_SUCCESS)  
491: VarSetCapacity(pbOutput, cbOutput, 0)  
492: NT_STATUS := DllCall("bcrypt\BCryptEncrypt", "ptr",   hKey, "ptr",   &pbInput, "uint",  cbInput, "ptr",   0, "ptr",   (pbIV ? &pbIV : 0), "uint",  (cbIV ? &cbIV : 0), "ptr",   &pbOutput, "uint
502: if (NT_STATUS = this.STATUS_SUCCESS)  
504: Return,cbOutput
060: if !(ENCRYPT := Crypt.Helper.CryptBinaryToString(CIPHER_DATA, CIPHER_LENGTH, Output))  
652: if (DllCall("crypt32\CryptBinaryToString", "ptr",   &pbBinary, "uint",  cbBinary, "uint",  (CRYPT_STRING[dwFlags] | CRYPT_STRING_NOCRLF), "ptr",   0, "uint*", pcchString))  
658: VarSetCapacity(pszString, pcchString << !!A_IsUnicode, 0)  
659: if (DllCall("crypt32\CryptBinaryToString", "ptr",   &pbBinary, "uint",  cbBinary, "uint",  (CRYPT_STRING[dwFlags] | CRYPT_STRING_NOCRLF), "ptr",   &pszString, "uint*", pcchString))  
665: Return,StrGet(&pszString)
062: }
068: Finally
069: {
071: if (KEY_HANDLE)  
072: Crypt.BCrypt.DestroyKey(KEY_HANDLE)  
422: DllCall("bcrypt\BCryptDestroyKey", "ptr", hKey)  
423: }
074: if (ALG_HANDLE)  
075: Crypt.BCrypt.CloseAlgorithmProvider(ALG_HANDLE)  
370: DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hAlgorithm, "uint", 0)  
371: }
076: }
077: Return,ENCRYPT (1.51)
---- U:\AHK\EncodeDecode\Encrypt_Test.ahk
008: MsgBox,Crypt.Decrypt.String("AES", "CBC", "Nn9CFFuC+/O84cV1NiwLYoyd25Z9nmWv16dIFKzf2b4=", "1234567890123456", "1234567890123456")
---- U:\AHK\EncodeDecode\Class_CNG_Jan2021.ahk
087: Try
090: if !(ALGORITHM_IDENTIFIER := Crypt.Verify.EncryptionAlgorithm(AlgId))  
737: Switch Algorithm
739: Return,Crypt.Constants.BCRYPT_AES_ALGORITHM
094: if !(ALG_HANDLE := Crypt.BCrypt.OpenAlgorithmProvider(ALGORITHM_IDENTIFIER))  
616: NT_STATUS := DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", phAlgorithm, "ptr",  &pszAlgId, "ptr",  pszImplementation, "uint", dwFlags)
621: if (NT_STATUS = this.STATUS_SUCCESS)  
622: Return,phAlgorithm
098: if (CHAINING_MODE := Crypt.Verify.ChainingMode(Mode))  
725: Switch ChainMode
727: Return,Crypt.Constants.BCRYPT_CHAIN_MODE_CBC
100: if !(Crypt.BCrypt.SetProperty(ALG_HANDLE, Crypt.Constants.BCRYPT_CHAINING_MODE, CHAINING_MODE))  
629: bInput := StrLen(pbInput)
630: NT_STATUS := DllCall("bcrypt\BCryptSetProperty", "ptr",   hObject, "ptr",   &pszProperty, "ptr",   &pbInput, "uint",  bInput, "uint",  dwFlags := 0)
636: if (NT_STATUS = this.STATUS_SUCCESS)  
637: Return,true
104: if !(KEY_HANDLE := Crypt.BCrypt.GenerateSymmetricKey(ALG_HANDLE, Key, Encoding))  
571: cbSecret := Crypt.Helper.StrPutVar(Key, pbSecret, Encoding)
702: if (Encoding = "hex")  
712: VarSetCapacity(Data, Length := StrPut(String, Encoding) * ((Encoding = "utf-16" || Encoding = "cp1200") ? 2 : 1) - 1)  
713: Return,StrPut(String, &Data, Length, Encoding)
572: NT_STATUS := DllCall("bcrypt\BCryptGenerateSymmetricKey", "ptr",  hAlgorithm, "ptr*", phKey, "ptr",  0, "uint", 0, "ptr",  &pbSecret, "uint", cbSecret, "uint", dwFlags := 0)
580: if (NT_STATUS = this.STATUS_SUCCESS)  
581: Return,phKey
108: if !(CIPHER_LENGTH := Crypt.Helper.CryptStringToBinary(String, CIPHER_DATA, Input))  
676: if (DllCall("crypt32\CryptStringToBinary", "ptr",   &pszString, "uint",  0, "uint",  CRYPT_STRING[dwFlags], "ptr",   0, "uint*", pcbBinary, "ptr",   0, "ptr",   0))  
684: VarSetCapacity(pbBinary, pcbBinary, 0)  
685: if (DllCall("crypt32\CryptStringToBinary", "ptr",   &pszString, "uint",  0, "uint",  CRYPT_STRING[dwFlags], "ptr",   &pbBinary, "uint*", pcbBinary, "ptr",   0, "ptr",   0))  
693: Return,pcbBinary
112: if !(BLOCK_LENGTH := Crypt.BCrypt.GetProperty(ALG_HANDLE, Crypt.Constants.BCRYPT_BLOCK_LENGTH, 4))  
588: NT_STATUS := DllCall("bcrypt\BCryptGetProperty", "ptr",   hObject, "ptr",   &pszProperty, "uint*", pbOutput, "uint",  cbOutput, "uint*", pcbResult, "uint",  dwFlags := 0)
595: if (NT_STATUS = this.STATUS_SUCCESS)  
596: Return,pbOutput
116: if !(DECRYPT_LENGTH := Crypt.BCrypt.Decrypt(KEY_HANDLE, CIPHER_DATA, CIPHER_LENGTH, IV, BLOCK_LENGTH, DECRYPT_DATA, Crypt.Constants.BCRYPT_BLOCK_PADDING))  
428: VarSetCapacity(pbInput, cbInput, 0)  
429: DllCall("msvcrt\memcpy", "ptr", &pbInput, "ptr", &String, "ptr", cbInput)  
122: Catch,Exception
125: Throw,Exception (4.80)
Given this information, I'm hoping you can help me sort out what I'm doing wrong.

Many thanks in advance!

Edit: Corrected the "entirety of the lines run by my test script" section.

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

Re: CNG (Cryptography API: Next Generation)

Post by jNizM » 03 Feb 2021, 03:00

Your example works for me
Image
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile

DefrostedChemist
Posts: 2
Joined: 02 Feb 2021, 15:22

Re: CNG (Cryptography API: Next Generation)

Post by DefrostedChemist » 04 Feb 2021, 13:05

Hi jNizM,

Thanks for your response. It must be something about my setup then.

To try and sort this out, I made one script that I could test on multiple machines. It consists of your decode example line followed by your 04-Jan-2021 Class_CGN code.

Code: Select all

MsgBox % Crypt.Decrypt.String("AES", "CBC", "Nn9CFFuC+/O84cV1NiwLYoyd25Z9nmWv16dIFKzf2b4=", "1234567890123456", "1234567890123456")
; ===============================================================================================================================
; AutoHotkey wrapper for Cryptography API: Next Generation
;
; Author ....: jNizM
; Released ..: 2016-09-15
; Modified ..: 2021-01-04
; Github ....: https://github.com/jNizM/AHK_CNG
; Forum .....: https://www.autohotkey.com/boards/viewtopic.php?f=6&t=23413
; ===============================================================================================================================


class Crypt
{

	; ===== PUBLIC CLASS / METHODS ==============================================================================================

	class Encrypt
	{

		String(AlgId, Mode := "", String := "", Key := "", IV := "", Encoding := "utf-8", Output := "BASE64")
		{
			try
			{
				; verify the encryption algorithm
				if !(ALGORITHM_IDENTIFIER := Crypt.Verify.EncryptionAlgorithm(AlgId))
					throw Exception("Wrong ALGORITHM_IDENTIFIER", -1)

				; open an algorithm handle.
				if !(ALG_HANDLE := Crypt.BCrypt.OpenAlgorithmProvider(ALGORITHM_IDENTIFIER))
					throw Exception("BCryptOpenAlgorithmProvider failed", -1)

				; verify the chaining mode
				if (CHAINING_MODE := Crypt.Verify.ChainingMode(Mode))
					; set chaining mode property.
					if !(Crypt.BCrypt.SetProperty(ALG_HANDLE, Crypt.Constants.BCRYPT_CHAINING_MODE, CHAINING_MODE))
						throw Exception("SetProperty failed", -1)

				; generate the key from supplied input key bytes.
				if !(KEY_HANDLE := Crypt.BCrypt.GenerateSymmetricKey(ALG_HANDLE, Key, Encoding))
					throw Exception("GenerateSymmetricKey failed", -1)

				; calculate the block length for the IV.
				if !(BLOCK_LENGTH := Crypt.BCrypt.GetProperty(ALG_HANDLE, Crypt.Constants.BCRYPT_BLOCK_LENGTH, 4))
					throw Exception("GetProperty failed", -1)

				; use the key to encrypt the plaintext buffer. for block sized messages, block padding will add an extra block.
				cbInput := Crypt.Helper.StrPutVar(String, pbInput, Encoding)
				if !(CIPHER_LENGTH := Crypt.BCrypt.Encrypt(KEY_HANDLE, pbInput, cbInput, IV, BLOCK_LENGTH, CIPHER_DATA, Crypt.Constants.BCRYPT_BLOCK_PADDING))
					throw Exception("Encrypt failed", -1)

				; convert binary data to string (base64 / hex / hexraw)
				if !(ENCRYPT := Crypt.Helper.CryptBinaryToString(CIPHER_DATA, CIPHER_LENGTH, Output))
					throw Exception("CryptBinaryToString failed", -1)
			}
			catch Exception
			{
				; represents errors that occur during application execution
				throw Exception
			}
			finally
			{
				; cleaning up resources
				if (KEY_HANDLE)
					Crypt.BCrypt.DestroyKey(KEY_HANDLE)

				if (ALG_HANDLE)
					Crypt.BCrypt.CloseAlgorithmProvider(ALG_HANDLE)
			}
			return ENCRYPT
		}
	}


	class Decrypt
	{

		String(AlgId, Mode := "", String := "", Key := "", IV := "", Encoding := "utf-8", Input := "BASE64")
		{
			try
			{
				; verify the encryption algorithm
				if !(ALGORITHM_IDENTIFIER := Crypt.Verify.EncryptionAlgorithm(AlgId))
					throw Exception("Wrong ALGORITHM_IDENTIFIER", -1)

				; open an algorithm handle.
				if !(ALG_HANDLE := Crypt.BCrypt.OpenAlgorithmProvider(ALGORITHM_IDENTIFIER))
					throw Exception("BCryptOpenAlgorithmProvider failed", -1)

				; verify the chaining mode
				if (CHAINING_MODE := Crypt.Verify.ChainingMode(Mode))
					; set chaining mode property.
					if !(Crypt.BCrypt.SetProperty(ALG_HANDLE, Crypt.Constants.BCRYPT_CHAINING_MODE, CHAINING_MODE))
						throw Exception("SetProperty failed", -1)

				; generate the key from supplied input key bytes.
				if !(KEY_HANDLE := Crypt.BCrypt.GenerateSymmetricKey(ALG_HANDLE, Key, Encoding))
					throw Exception("GenerateSymmetricKey failed", -1)

				; convert encrypted string (base64 / hex / hexraw) to binary data
				if !(CIPHER_LENGTH := Crypt.Helper.CryptStringToBinary(String, CIPHER_DATA, Input))
					throw Exception("CryptStringToBinary failed", -1)

				; calculate the block length for the IV.
				if !(BLOCK_LENGTH := Crypt.BCrypt.GetProperty(ALG_HANDLE, Crypt.Constants.BCRYPT_BLOCK_LENGTH, 4))
					throw Exception("GetProperty failed", -1)

				; use the key to decrypt the data to plaintext buffer
				if !(DECRYPT_LENGTH := Crypt.BCrypt.Decrypt(KEY_HANDLE, CIPHER_DATA, CIPHER_LENGTH, IV, BLOCK_LENGTH, DECRYPT_DATA, Crypt.Constants.BCRYPT_BLOCK_PADDING))
					throw Exception("Decrypt failed", -1)

				; receive the decrypted plaintext
				DECRYPT := StrGet(&DECRYPT_DATA, DECRYPT_LENGTH, Encoding)
			}
			catch Exception
			{
				; represents errors that occur during application execution
				throw Exception
			}
			finally
			{
				; cleaning up resources
				if (KEY_HANDLE)
					Crypt.BCrypt.DestroyKey(KEY_HANDLE)

				if (ALG_HANDLE)
					Crypt.BCrypt.CloseAlgorithmProvider(ALG_HANDLE)
			}
			return DECRYPT
		}

	}


	class Hash
	{

		String(AlgId, String, Encoding := "utf-8", Output := "HEXRAW")
		{
			try
			{
				; verify the hash algorithm
				if !(ALGORITHM_IDENTIFIER := Crypt.Verify.HashAlgorithm(AlgId))
					throw Exception("Wrong ALGORITHM_IDENTIFIER", -1)

				; open an algorithm handle
				if !(ALG_HANDLE := Crypt.BCrypt.OpenAlgorithmProvider(ALGORITHM_IDENTIFIER))
					throw Exception("BCryptOpenAlgorithmProvider failed", -1)

				; create a hash
				if !(HASH_HANDLE := Crypt.BCrypt.CreateHash(ALG_HANDLE))
					throw Exception("CreateHash failed", -1)

				; hash some data
				cbInput := Crypt.Helper.StrPutVar(String, pbInput, Encoding)
				if !(Crypt.BCrypt.HashData(HASH_HANDLE, pbInput, cbInput))
					throw Exception("HashData failed", -1)

				; calculate the length of the hash
				if !(HASH_LENGTH := Crypt.BCrypt.GetProperty(ALG_HANDLE, Crypt.Constants.BCRYPT_HASH_LENGTH, 4))
					throw Exception("GetProperty failed", -1)

				; close the hash
				if !(Crypt.BCrypt.FinishHash(HASH_HANDLE, HASH_DATA, HASH_LENGTH))
					throw Exception("FinishHash failed", -1)

				; convert bin to string (base64 / hex)
				if !(HASH := Crypt.Helper.CryptBinaryToString(HASH_DATA, HASH_LENGTH, Output))
					throw Exception("CryptBinaryToString failed", -1)
			}
			catch Exception
			{
				; represents errors that occur during application execution
				throw Exception
			}
			finally
			{
				; cleaning up resources
				if (HASH_HANDLE)
					Crypt.BCrypt.DestroyHash(HASH_HANDLE)

				if (ALG_HANDLE)
					Crypt.BCrypt.CloseAlgorithmProvider(ALG_HANDLE)
			}
			return HASH
		}


		File(AlgId, FileName, Bytes := 1048576, Offset := 0, Length := -1, Encoding := "utf-8", Output := "HEXRAW")
		{
			try
			{
				; verify the hash algorithm
				if !(ALGORITHM_IDENTIFIER := Crypt.Verify.HashAlgorithm(AlgId))
					throw Exception("Wrong ALGORITHM_IDENTIFIER", -1)

				; open an algorithm handle
				if !(ALG_HANDLE := Crypt.BCrypt.OpenAlgorithmProvider(ALGORITHM_IDENTIFIER))
					throw Exception("BCryptOpenAlgorithmProvider failed", -1)

				; create a hash
				if !(HASH_HANDLE := Crypt.BCrypt.CreateHash(ALG_HANDLE))
					throw Exception("CreateHash failed", -1)

				; hash some data
				if !(IsObject(File := FileOpen(FileName, "r", Encoding)))
					throw Exception("Failed to open file: " FileName, -1)
				Length := Length < 0 ? File.Length - Offset : Length
				if ((Offset + Length) > File.Length)
					throw Exception("Invalid parameters offset / length!", -1)
				while (Length > Bytes) && (Dataread := File.RawRead(Data, Bytes))
				{
					if !(Crypt.BCrypt.HashData(HASH_HANDLE, Data, Dataread))
						throw Exception("HashData failed", -1)
					Length -= Dataread
				}
				if (Length > 0)
				{
					if (Dataread := File.RawRead(Data, Length))
					{
						if !(Crypt.BCrypt.HashData(HASH_HANDLE, Data, Dataread))
							throw Exception("HashData failed", -1)
					}
				}

				; calculate the length of the hash
				if !(HASH_LENGTH := Crypt.BCrypt.GetProperty(ALG_HANDLE, Crypt.Constants.BCRYPT_HASH_LENGTH, 4))
					throw Exception("GetProperty failed", -1)

				; close the hash
				if !(Crypt.BCrypt.FinishHash(HASH_HANDLE, HASH_DATA, HASH_LENGTH))
					throw Exception("FinishHash failed", -1)

				; convert bin to string (base64 / hex)
				if !(HASH := Crypt.Helper.CryptBinaryToString(HASH_DATA, HASH_LENGTH, Output))
					throw Exception("CryptBinaryToString failed", -1)
			}
			catch Exception
			{
				; represents errors that occur during application execution
				throw Exception
			}
			finally
			{
				; cleaning up resources
				if (File)
					File.Close()

				if (HASH_HANDLE)
					Crypt.BCrypt.DestroyHash(HASH_HANDLE)

				if (ALG_HANDLE)
					Crypt.BCrypt.CloseAlgorithmProvider(ALG_HANDLE)
			}
			return HASH
		}


		HMAC(AlgId, String, Hmac, Encoding := "utf-8", Output := "HEXRAW")
		{
			try
			{
				; verify the hash algorithm
				if !(ALGORITHM_IDENTIFIER := Crypt.Verify.HashAlgorithm(AlgId))
					throw Exception("Wrong ALGORITHM_IDENTIFIER", -1)

				; open an algorithm handle
				if !(ALG_HANDLE := Crypt.BCrypt.OpenAlgorithmProvider(ALGORITHM_IDENTIFIER, Crypt.Constants.BCRYPT_ALG_HANDLE_HMAC_FLAG))
					throw Exception("BCryptOpenAlgorithmProvider failed", -1)

				; create a hash
				if !(HASH_HANDLE := Crypt.BCrypt.CreateHash(ALG_HANDLE, Hmac, Encoding))
					throw Exception("CreateHash failed", -1)

				; hash some data
				cbInput := Crypt.helper.StrPutVar(String, pbInput, Encoding)
				if !(Crypt.BCrypt.HashData(HASH_HANDLE, pbInput, cbInput))
					throw Exception("HashData failed", -1)

				; calculate the length of the hash
				if !(HASH_LENGTH := Crypt.BCrypt.GetProperty(ALG_HANDLE, Crypt.Constants.BCRYPT_HASH_LENGTH, 4))
					throw Exception("GetProperty failed", -1)

				; close the hash
				if !(Crypt.BCrypt.FinishHash(HASH_HANDLE, HASH_DATA, HASH_LENGTH))
					throw Exception("FinishHash failed", -1)

				; convert bin to string (base64 / hex)
				if !(HMAC := Crypt.Helper.CryptBinaryToString(HASH_DATA, HASH_LENGTH, Output))
					throw Exception("CryptBinaryToString failed", -1)
			}
			catch Exception
			{
				; represents errors that occur during application execution
				throw Exception
			}
			finally
			{
				; cleaning up resources
				if (HASH_HANDLE)
					Crypt.BCrypt.DestroyHash(HASH_HANDLE)

				if (ALG_HANDLE)
					Crypt.BCrypt.CloseAlgorithmProvider(ALG_HANDLE)
			}
			return HMAC
		}


		PBKDF2(AlgId, Password, Salt, Iterations := 4096, KeySize := 256, Encoding := "utf-8", Output := "HEXRAW")
		{
			try
			{
				; verify the hash algorithm
				if !(ALGORITHM_IDENTIFIER := Crypt.Verify.HashAlgorithm(AlgId))
					throw Exception("Wrong ALGORITHM_IDENTIFIER", -1)

				; open an algorithm handle
				if !(ALG_HANDLE := Crypt.BCrypt.OpenAlgorithmProvider(ALGORITHM_IDENTIFIER, Crypt.Constants.BCRYPT_ALG_HANDLE_HMAC_FLAG))
					throw Exception("BCryptOpenAlgorithmProvider failed", -1)

				; derives a key from a hash value
				if !(Crypt.BCrypt.DeriveKeyPBKDF2(ALG_HANDLE, Password, Salt, Iterations, PBKDF2_DATA, KeySize / 8, Encoding))
					throw Exception("CreateHash failed", -1)

				; convert bin to string (base64 / hex)
				if !(PBKDF2 := Crypt.Helper.CryptBinaryToString(PBKDF2_DATA , KeySize / 8, Output))
					throw Exception("CryptBinaryToString failed", -1)
			}
			catch Exception
			{
				; represents errors that occur during application execution
				throw Exception
			}
			finally
			{
				; cleaning up resources
				if (ALG_HANDLE)
					Crypt.BCrypt.CloseAlgorithmProvider(ALG_HANDLE)
			}
			return PBKDF2
		}

	}



	; ===== PRIVATE CLASS / METHODS =============================================================================================


	/*
		CNG BCrypt Functions
		https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/
	*/
	class BCrypt
	{
		static hBCRYPT := DllCall("LoadLibrary", "str", "bcrypt.dll", "ptr")
		static STATUS_SUCCESS := 0


		CloseAlgorithmProvider(hAlgorithm)
		{
			DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hAlgorithm, "uint", 0)
		}


		CreateHash(hAlgorithm, hmac := 0, encoding := "utf-8")
		{
			if (hmac)
				cbSecret := Crypt.helper.StrPutVar(hmac, pbSecret, encoding)
			NT_STATUS := DllCall("bcrypt\BCryptCreateHash", "ptr",  hAlgorithm
			                                              , "ptr*", phHash
			                                              , "ptr",  pbHashObject := 0
			                                              , "uint", cbHashObject := 0
			                                              , "ptr",  (pbSecret ? &pbSecret : 0)
			                                              , "uint", (cbSecret ? cbSecret : 0)
			                                              , "uint", dwFlags := 0)

			if (NT_STATUS = this.STATUS_SUCCESS)
				return phHash
			return false
		}


		DeriveKeyPBKDF2(hPrf, Password, Salt, cIterations, ByRef pbDerivedKey, cbDerivedKey, Encoding := "utf-8")
		{
			cbPassword := Crypt.Helper.StrPutVar(Password, pbPassword, Encoding)
			cbSalt := Crypt.Helper.StrPutVar(Salt, pbSalt, Encoding)
		
			VarSetCapacity(pbDerivedKey, cbDerivedKey, 0)
			NT_STATUS := DllCall("bcrypt\BCryptDeriveKeyPBKDF2", "ptr",   hPrf
			                                                   , "ptr",   &pbPassword
			                                                   , "uint",  cbPassword
			                                                   , "ptr",   &pbSalt
			                                                   , "uint",  cbSalt
			                                                   , "int64", cIterations
			                                                   , "ptr",   &pbDerivedKey
			                                                   , "uint",  cbDerivedKey
			                                                   , "uint",  dwFlags := 0)

			if (NT_STATUS = this.STATUS_SUCCESS)
				return true
			return false
		}


		DestroyHash(hHash)
		{
			DllCall("bcrypt\BCryptDestroyHash", "ptr", hHash)
		}


		DestroyKey(hKey)
		{
			DllCall("bcrypt\BCryptDestroyKey", "ptr", hKey)
		}


		Decrypt(hKey, ByRef String, cbInput, IV, BCRYPT_BLOCK_LENGTH, ByRef pbOutput, dwFlags)
		{
			VarSetCapacity(pbInput, cbInput, 0)
			DllCall("msvcrt\memcpy", "ptr", &pbInput, "ptr", &String, "ptr", cbInput)

			if (IV != "")
			{
				cbIV := VarSetCapacity(pbIV, BCRYPT_BLOCK_LENGTH, 0)
				StrPut(IV, &pbIV, BCRYPT_BLOCK_LENGTH, Encoding)
			}

			NT_STATUS := DllCall("bcrypt\BCryptDecrypt", "ptr",   hKey
			                                           , "ptr",   &pbInput
			                                           , "uint",  cbInput
			                                           , "ptr",   0
			                                           , "ptr",   (pbIV ? &pbIV : 0)
			                                           , "uint",  (cbIV ? &cbIV : 0)
			                                           , "ptr",   0
			                                           , "uint",  0
			                                           , "uint*", cbOutput
			                                           , "uint",  dwFlags)
			if (NT_STATUS = this.STATUS_SUCCESS)
			{
				VarSetCapacity(pbOutput, cbOutput, 0)
				NT_STATUS := DllCall("bcrypt\BCryptDecrypt", "ptr",   hKey
			                                               , "ptr",   &pbInput
			                                               , "uint",  cbInput
			                                               , "ptr",   0
			                                               , "ptr",   (pbIV ? &pbIV : 0)
			                                               , "uint",  (cbIV ? &cbIV : 0)
			                                               , "ptr",   &pbOutput
			                                               , "uint",  cbOutput
			                                               , "uint*", cbOutput
			                                               , "uint",  dwFlags)
				if (NT_STATUS = this.STATUS_SUCCESS)
				{
					return cbOutput
				}
			}
			return false
		}


		Encrypt(hKey, ByRef pbInput, cbInput, IV, BCRYPT_BLOCK_LENGTH, ByRef pbOutput, dwFlags := 0)
		{
			;cbInput := Crypt.Helper.StrPutVar(String, pbInput, Encoding)

			if (IV != "")
			{
				cbIV := VarSetCapacity(pbIV, BCRYPT_BLOCK_LENGTH, 0)
				StrPut(IV, &pbIV, BCRYPT_BLOCK_LENGTH, Encoding)
			}

			NT_STATUS := DllCall("bcrypt\BCryptEncrypt", "ptr",   hKey
			                                           , "ptr",   &pbInput
			                                           , "uint",  cbInput
			                                           , "ptr",   0
			                                           , "ptr",   (pbIV ? &pbIV : 0)
			                                           , "uint",  (cbIV ? &cbIV : 0)
			                                           , "ptr",   0
			                                           , "uint",  0
			                                           , "uint*", cbOutput
			                                           , "uint",  dwFlags)
			if (NT_STATUS = this.STATUS_SUCCESS)
			{
				VarSetCapacity(pbOutput, cbOutput, 0)
				NT_STATUS := DllCall("bcrypt\BCryptEncrypt", "ptr",   hKey
			                                               , "ptr",   &pbInput
			                                               , "uint",  cbInput
			                                               , "ptr",   0
			                                               , "ptr",   (pbIV ? &pbIV : 0)
			                                               , "uint",  (cbIV ? &cbIV : 0)
			                                               , "ptr",   &pbOutput
			                                               , "uint",  cbOutput
			                                               , "uint*", cbOutput
			                                               , "uint",  dwFlags)
				if (NT_STATUS = this.STATUS_SUCCESS)
				{
					return cbOutput
				}
			}
			return false
		}


		EnumAlgorithms(dwAlgOperations)
		{
			NT_STATUS := DllCall("bcrypt\BCryptEnumAlgorithms", "uint",  dwAlgOperations
			                                                  , "uint*", pAlgCount
			                                                  , "ptr*",  ppAlgList
			                                                  , "uint",  dwFlags := 0)

			if (NT_STATUS = this.STATUS_SUCCESS)
			{
				addr := ppAlgList, BCRYPT_ALGORITHM_IDENTIFIER := []
				loop % pAlgCount
				{
					BCRYPT_ALGORITHM_IDENTIFIER[A_Index, "Name"]  := StrGet(NumGet(addr + A_PtrSize * 0, "uptr"), "utf-16")
					BCRYPT_ALGORITHM_IDENTIFIER[A_Index, "Class"] := NumGet(addr + A_PtrSize * 1, "uint")
					BCRYPT_ALGORITHM_IDENTIFIER[A_Index, "Flags"] := NumGet(addr + A_PtrSize * 1 + 4, "uint")
					addr += A_PtrSize * 2
				}
				return BCRYPT_ALGORITHM_IDENTIFIER
			}
			return false
		}


		EnumProviders(pszAlgId)
		{
			NT_STATUS := DllCall("bcrypt\BCryptEnumProviders", "ptr",   pszAlgId
			                                                 , "uint*", pImplCount
			                                                 , "ptr*",  ppImplList
			                                                 , "uint",  dwFlags := 0)

			if (NT_STATUS = this.STATUS_SUCCESS)
			{
				addr := ppImplList, BCRYPT_PROVIDER_NAME := []
				loop % pImplCount
				{
					BCRYPT_PROVIDER_NAME.Push(StrGet(NumGet(addr + A_PtrSize * 0, "uptr"), "utf-16"))
					addr += A_PtrSize
				}
				return BCRYPT_PROVIDER_NAME
			}
			return false
		}


		FinishHash(hHash, ByRef pbOutput, cbOutput)
		{
			VarSetCapacity(pbOutput, cbOutput, 0)
			NT_STATUS := DllCall("bcrypt\BCryptFinishHash", "ptr",  hHash
			                                              , "ptr",  &pbOutput
			                                              , "uint", cbOutput
			                                              , "uint", dwFlags := 0)

			if (NT_STATUS = this.STATUS_SUCCESS)
				return cbOutput
			return false
		}


		GenerateSymmetricKey(hAlgorithm, Key, Encoding := "utf-8")
		{
			cbSecret := Crypt.Helper.StrPutVar(Key, pbSecret, Encoding)
			NT_STATUS := DllCall("bcrypt\BCryptGenerateSymmetricKey", "ptr",  hAlgorithm
			                                                        , "ptr*", phKey
			                                                        , "ptr",  0
			                                                        , "uint", 0
			                                                        , "ptr",  &pbSecret
			                                                        , "uint", cbSecret
			                                                        , "uint", dwFlags := 0)

			if (NT_STATUS = this.STATUS_SUCCESS)
				return phKey
			return false
		}


		GetProperty(hObject, pszProperty, cbOutput)
		{
			NT_STATUS := DllCall("bcrypt\BCryptGetProperty", "ptr",   hObject
			                                               , "ptr",   &pszProperty
			                                               , "uint*", pbOutput
			                                               , "uint",  cbOutput
			                                               , "uint*", pcbResult
			                                               , "uint",  dwFlags := 0)

			if (NT_STATUS = this.STATUS_SUCCESS)
				return pbOutput
			return false
		}


		HashData(hHash, ByRef pbInput, cbInput)
		{
			NT_STATUS := DllCall("bcrypt\BCryptHashData", "ptr",  hHash
			                                            , "ptr",  &pbInput
			                                            , "uint", cbInput
			                                            , "uint", dwFlags := 0)

			if (NT_STATUS = this.STATUS_SUCCESS)
				return true
			return false
		}


		OpenAlgorithmProvider(pszAlgId, dwFlags := 0, pszImplementation := 0)
		{
			NT_STATUS := DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", phAlgorithm
			                                                         , "ptr",  &pszAlgId
			                                                         , "ptr",  pszImplementation
			                                                         , "uint", dwFlags)

			if (NT_STATUS = this.STATUS_SUCCESS)
				return phAlgorithm
			return false
		}


		SetProperty(hObject, pszProperty, pbInput)
		{
			bInput := StrLen(pbInput)
			NT_STATUS := DllCall("bcrypt\BCryptSetProperty", "ptr",   hObject
			                                               , "ptr",   &pszProperty
			                                               , "ptr",   &pbInput
			                                               , "uint",  bInput
			                                               , "uint",  dwFlags := 0)

			if (NT_STATUS = this.STATUS_SUCCESS)
				return true
			return false
		}
	}


	class Helper
	{
		static hCRYPT32 := DllCall("LoadLibrary", "str", "crypt32.dll", "ptr")

		CryptBinaryToString(ByRef pbBinary, cbBinary, dwFlags := "BASE64")
		{
			static CRYPT_STRING := { "BASE64": 0x1, "BINARY": 0x2, "HEX": 0x4, "HEXRAW": 0xc }
			static CRYPT_STRING_NOCRLF := 0x40000000

			if (DllCall("crypt32\CryptBinaryToString", "ptr",   &pbBinary
			                                         , "uint",  cbBinary
			                                         , "uint",  (CRYPT_STRING[dwFlags] | CRYPT_STRING_NOCRLF)
			                                         , "ptr",   0
			                                         , "uint*", pcchString))
			{
				VarSetCapacity(pszString, pcchString << !!A_IsUnicode, 0)
				if (DllCall("crypt32\CryptBinaryToString", "ptr",   &pbBinary
			                                             , "uint",  cbBinary
			                                             , "uint",  (CRYPT_STRING[dwFlags] | CRYPT_STRING_NOCRLF)
			                                             , "ptr",   &pszString
			                                             , "uint*", pcchString))
				{
					return StrGet(&pszString)
				}
			}
			return false
		}


		CryptStringToBinary(pszString, ByRef pbBinary, dwFlags := "BASE64")
		{
			static CRYPT_STRING := { "BASE64": 0x1, "BINARY": 0x2, "HEX": 0x4, "HEXRAW": 0xc }

			if (DllCall("crypt32\CryptStringToBinary", "ptr",   &pszString
			                                         , "uint",  0
			                                         , "uint",  CRYPT_STRING[dwFlags]
			                                         , "ptr",   0
			                                         , "uint*", pcbBinary
			                                         , "ptr",   0
			                                         , "ptr",   0))
			{
				VarSetCapacity(pbBinary, pcbBinary, 0)
				if (DllCall("crypt32\CryptStringToBinary", "ptr",   &pszString
				                                         , "uint",  0
				                                         , "uint",  CRYPT_STRING[dwFlags]
				                                         , "ptr",   &pbBinary
				                                         , "uint*", pcbBinary
				                                         , "ptr",   0
				                                         , "ptr",   0))
				{
					return pcbBinary
				}
			}
			return false
		}


		StrPutVar(String, ByRef Data, Encoding)
		{
			if (Encoding = "hex")
			{
				String := InStr(String, "0x") ? SubStr(String, 3) : String
				VarSetCapacity(Data, (Length := StrLen(String) // 2), 0)
				loop % Length
					NumPut("0x" SubStr(String, 2 * A_Index - 1, 2), Data, A_Index - 1, "char")
				return Length
			}
			else
			{
				VarSetCapacity(Data, Length := StrPut(String, Encoding) * ((Encoding = "utf-16" || Encoding = "cp1200") ? 2 : 1) - 1)
				return StrPut(String, &Data, Length, Encoding)
			}
		}

	}


	class Verify
	{

		ChainingMode(ChainMode)
		{
			switch ChainMode
			{
				case "CBC", "ChainingModeCBC": return Crypt.Constants.BCRYPT_CHAIN_MODE_CBC
				case "CFB", "ChainingModeCFB": return Crypt.Constants.BCRYPT_CHAIN_MODE_CFB
				case "ECB", "ChainingModeECB": return Crypt.Constants.BCRYPT_CHAIN_MODE_ECB
				default: return ""
			}
		}


		EncryptionAlgorithm(Algorithm)
		{
			switch Algorithm
			{
				case "AES":                return Crypt.Constants.BCRYPT_AES_ALGORITHM
				case "DES":                return Crypt.Constants.BCRYPT_DES_ALGORITHM
				case "RC2":                return Crypt.Constants.BCRYPT_RC2_ALGORITHM
				case "RC4":                return Crypt.Constants.BCRYPT_RC4_ALGORITHM
				default: return ""
			}
		}


		HashAlgorithm(Algorithm)
		{
			switch Algorithm
			{
				case "MD2":               return Crypt.Constants.BCRYPT_MD2_ALGORITHM
				case "MD4":               return Crypt.Constants.BCRYPT_MD4_ALGORITHM
				case "MD5":               return Crypt.Constants.BCRYPT_MD5_ALGORITHM
				case "SHA1", "SHA-1":     return Crypt.Constants.BCRYPT_SHA1_ALGORITHM
				case "SHA256", "SHA-256": return Crypt.Constants.BCRYPT_SHA256_ALGORITHM
				case "SHA384", "SHA-384": return Crypt.Constants.BCRYPT_SHA384_ALGORITHM
				case "SHA512", "SHA-512": return Crypt.Constants.BCRYPT_SHA512_ALGORITHM
				default: return ""
			}
		}

	}



	; ===== CONSTANTS ===========================================================================================================

	class Constants
	{
		static BCRYPT_ALG_HANDLE_HMAC_FLAG            := 0x00000008
		static BCRYPT_BLOCK_PADDING                   := 0x00000001


		; AlgOperations flags for use with BCryptEnumAlgorithms()
		static BCRYPT_CIPHER_OPERATION                := 0x00000001
		static BCRYPT_HASH_OPERATION                  := 0x00000002
		static BCRYPT_ASYMMETRIC_ENCRYPTION_OPERATION := 0x00000004
		static BCRYPT_SECRET_AGREEMENT_OPERATION      := 0x00000008
		static BCRYPT_SIGNATURE_OPERATION             := 0x00000010
		static BCRYPT_RNG_OPERATION                   := 0x00000020
		static BCRYPT_KEY_DERIVATION_OPERATION        := 0x00000040


		; https://docs.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-identifiers
		static BCRYPT_3DES_ALGORITHM                  := "3DES"
		static BCRYPT_3DES_112_ALGORITHM              := "3DES_112"
		static BCRYPT_AES_ALGORITHM                   := "AES"
		static BCRYPT_AES_CMAC_ALGORITHM              := "AES-CMAC"
		static BCRYPT_AES_GMAC_ALGORITHM              := "AES-GMAC"
		static BCRYPT_DES_ALGORITHM                   := "DES"
		static BCRYPT_DESX_ALGORITHM                  := "DESX"
		static BCRYPT_MD2_ALGORITHM                   := "MD2"
		static BCRYPT_MD4_ALGORITHM                   := "MD4"
		static BCRYPT_MD5_ALGORITHM                   := "MD5"
		static BCRYPT_RC2_ALGORITHM                   := "RC2"
		static BCRYPT_RC4_ALGORITHM                   := "RC4"
		static BCRYPT_RNG_ALGORITHM                   := "RNG"
		static BCRYPT_SHA1_ALGORITHM                  := "SHA1"
		static BCRYPT_SHA256_ALGORITHM                := "SHA256"
		static BCRYPT_SHA384_ALGORITHM                := "SHA384"
		static BCRYPT_SHA512_ALGORITHM                := "SHA512"
		static BCRYPT_PBKDF2_ALGORITHM                := "PBKDF2"
		static BCRYPT_XTS_AES_ALGORITHM               := "XTS-AES"


		; https://docs.microsoft.com/en-us/windows/win32/seccng/cng-property-identifiers
		static BCRYPT_BLOCK_LENGTH                    := "BlockLength"
		static BCRYPT_CHAINING_MODE                   := "ChainingMode"
		static BCRYPT_CHAIN_MODE_CBC                  := "ChainingModeCBC"
		static BCRYPT_CHAIN_MODE_CCM                  := "ChainingModeCCM"
		static BCRYPT_CHAIN_MODE_CFB                  := "ChainingModeCFB"
		static BCRYPT_CHAIN_MODE_ECB                  := "ChainingModeECB"
		static BCRYPT_CHAIN_MODE_GCM                  := "ChainingModeGCM"
		static BCRYPT_HASH_LENGTH                     := "HashDigestLength"
		static BCRYPT_OBJECT_LENGTH                   := "ObjectLength"
	}
}
I get the following results on a couple different systems:
A 64-bit Win7 Ultimate install (Service Pack 1) on Intel i7-4770k with AHK version 1.1.30.01 (11-Nov-2018). ChainMode error likley due to older version of AHK
A 64-bit Win7 Ultimate install (Service Pack 1) on Intel i7-4770k with AHK version 1.1.33.02 (17-Jul-2020, Current). Same DLL error from previous post.
A 64-bit install of Win10 Enterprise (Up to date) on AMD Ryzen 7 Pro 3700U with AHK version 1.1.32.00 (23-Nov-2019). Same DLL error from previous post.
A 64-bit install of Win10 Enterprise LTSC (Up to date) on Intel Xeon W-2123 with AHK version 1.1.33.02 (17-Jul-2020, Current). Same DLL error from previous post.

After switching around to a couple software and hardware configurations and getting the same error, I'm back to having no idea what is going wrong.

I'm copying your Class_CNG.ahk directly from https raw.githubusercontent.com /jNizM/AHK_CNG/master/src/Class_CNG.ahk and your example directly from https://www.autohotkey.com/boards/viewtopic.php?p=109959#p109959 to generate the script in the above code block.
I tried generating the script by pasting into Notepad as well as Notepad++. Same error result for both cases.

Any ideas on what else I could try?
Also, could you please try the code in my codeblock above to rule out any issues with my test script?

Thank you for your patience and assistance with this issue!

murataygun
Posts: 104
Joined: 07 Aug 2015, 15:53

Re: CNG (Cryptography API: Next Generation)

Post by murataygun » 22 Jul 2021, 06:42

File encryption example?
Last edited by murataygun on 22 Jul 2021, 07:20, edited 1 time in total.

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

Re: CNG (Cryptography API: Next Generation)

Post by TheHacker » 22 Jul 2021, 07:13

DefrostedChemist wrote:
04 Feb 2021, 13:05
I get the following results on a couple different systems:
---------------------------
Decode_Test.ahk
---------------------------
Error at line 718.

Line Text: switch ChainMode
Error: This line does not contain a recognized action.

The program will exit.
---------------------------
OK
---------------------------
Have you tried updating AHK?

elmo
Posts: 113
Joined: 09 Oct 2013, 09:08

CNG Encrypt/Decrypt an Object

Post by elmo » 17 Aug 2021, 13:29

Hello @jNizM,

First, thank you for this most excellent library.

In the [Encrypting Data with CNG] section of your original post you noted:

Possible Inputs / Outputs
* Base64
* Hex / Hexraw
* Binary

Does this mean that an AutoHotkey Object could be encrypted/decrypted ?

I tried the test below and wondering if it is architecturally impossible for it to work because the object is actually a memory construct:

Code: Select all

#SingleInstance , Force
#Include Class_CNG.ahk
#Include <array_lib>

; >>>>> Encryption works | Decryption works <<<<<
testString                                        = [ "a" , "b" , "c" ]

cryptInput                                       := Crypt.Encrypt.String("AES", "CBC", testString , "1234567890123456", "1234567890123456")
MsgBox , 4096 , cryptInput  , % cryptInput

cryptOutput                                      := Crypt.Decrypt.String("AES", "CBC", cryptInput , "1234567890123456", "1234567890123456")
MsgBox , 4096 , cryptOutput , % cryptOutput

; >>>>> Encryption works | Decryption fails <<<<<
testObject                                       := [ "a" , "b" , "c" ]

cryptInput                                       := Crypt.Encrypt.String("AES", "CBC", testObject , "1234567890123456", "1234567890123456")
MsgBox , 4096 , cryptInput  , % cryptInput

cryptOutput                                      := Crypt.Decrypt.String("AES", "CBC", cryptInput , "1234567890123456", "1234567890123456")
Array_Gui( cryptOutput , "" ,, "cryptOutput" )

ExitApp

malcev
Posts: 1769
Joined: 12 Aug 2014, 12:37

Re: CNG (Cryptography API: Next Generation)

Post by malcev » 26 Sep 2021, 16:27

jNizM, You have error in functions.
This

Code: Select all

VarSetCapacity(pbInput, (StrPut(string, encoding) - 1) * ((encoding = "utf-16" || encoding = "cp1200") ? 2 : 1), 0) && cbInput := StrPut(string, &pbInput, encoding) - 1
Should be like this

Code: Select all

VarSetCapacity(pbInput, (StrPut(string, encoding) - 1) * ((encoding = "utf-16" || encoding = "cp1200") ? 2 : 1), 0) && cbInput := (StrPut(string, &pbInput, encoding) - 1) * ((encoding = "utf-16" || encoding = "cp1200") ? 2 : 1)
https://github.com/jNizM/AHK_CNG/blob/master/src/functions/bcrypt_md5.ahk#L43

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

Re: CNG (Cryptography API: Next Generation)

Post by jNizM » 30 Oct 2021, 04:17

@elmo im not sure, but I dont think this works like this. you need to loop throw the array and encrypt the array items itself. later you loop again and decrypt all the array items
@malcev fixed
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile

ZizzyZizzy
Posts: 3
Joined: 27 Jan 2022, 22:29

Re: CNG (Cryptography API: Next Generation)

Post by ZizzyZizzy » 27 Jan 2022, 22:33

"BCryptOpenAlgorithmProvider failed" for every hash and encryption algorithm I've tried.

Runs fine on my home Windows 10. On my work computer, it fails with the above message. bcrypt.dll is in the expected location and has the same permissions as my home computer.

Any idea what could be preventing it from being able to use bcrypt.dll? I ran it as Administrator too, but that didn't help.

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

Re: CNG (Cryptography API: Next Generation)

Post by jNizM » 28 Jan 2022, 02:35

@ZizzyZizzy can you link to the one you tried?
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile

ZizzyZizzy
Posts: 3
Joined: 27 Jan 2022, 22:29

Re: CNG (Cryptography API: Next Generation)

Post by ZizzyZizzy » 28 Jan 2022, 10:35

jNizM wrote:
28 Jan 2022, 02:35
@ZizzyZizzy can you link to the one you tried?
I tried the one attached to the very first post here, I also tried this one:
https://github.com/jNizM/AHK_CNG/tree/master/src/v1.1_deprecated

It's just odd that it works perfectly on my home Windows 10 and not my Work laptop running the same version.

Oh, and I also tried copying bcrypt.dll to the same working dir as the script. That didn't work either.

ZizzyZizzy
Posts: 3
Joined: 27 Jan 2022, 22:29

Re: CNG (Cryptography API: Next Generation)

Post by ZizzyZizzy » 28 Jan 2022, 12:20

ZizzyZizzy wrote:
28 Jan 2022, 10:35
jNizM wrote:
28 Jan 2022, 02:35
@ZizzyZizzy can you link to the one you tried?
I tried the one attached to the very first post here, I also tried this one:
https://github.com/jNizM/AHK_CNG/tree/master/src/v1.1_deprecated

It's just odd that it works perfectly on my home Windows 10 and not my Work laptop running the same version.

Oh, and I also tried copying bcrypt.dll to the same working dir as the script. That didn't work either.
Well clearly I didn't READ the instructions, so I never ran Installer.ahk in the installed folder.

Once I replaced the AuotHotkey.exe with AutoHotkeyU64.exe, the problem was solved.

lwx228
Posts: 49
Joined: 24 Apr 2022, 08:52

Re: CNG (Cryptography API: Next Generation)

Post by lwx228 » 09 Aug 2022, 00:30

Masonjar13 wrote:
05 Oct 2016, 04:34
Ah, alright. Thanks for clearing that up. In that case, however, you still call BCryptDestroyHash() in the W10 versions, making it redundant, yes?

My operating system is Windows 7 64-bit.AHK is to install V1.1.34.02
I want to use the AES CBC for decryption.

Code: Select all

t:= Decrypt.String("AES", "CBC", "Nn9CFFuC+/O84cV1NiwLYoyd25Z9nmWv16dIFKzf2b4=", "1234567890123456", "1234567890123456")
How would write AHK to implement the functionality of this Github example?
Do want to run this code separately as AHK?
Or do want to put this into "class_cng.ahk"?


Thanks!
Attachments
2022-08-09_13-22-47.png
2022-08-09_13-22-47.png (49.47 KiB) Viewed 2619 times

guest3456
Posts: 3462
Joined: 09 Oct 2013, 10:31

Re: CNG (Cryptography API: Next Generation)

Post by guest3456 » 09 Aug 2022, 09:05

lwx228 wrote:
09 Aug 2022, 00:30
Masonjar13 wrote:
05 Oct 2016, 04:34
Ah, alright. Thanks for clearing that up. In that case, however, you still call BCryptDestroyHash() in the W10 versions, making it redundant, yes?

My operating system is Windows 7 64-bit.AHK is to install V1.1.34.02
I want to use the AES CBC for decryption.

Code: Select all

t:= Decrypt.String("AES", "CBC", "Nn9CFFuC+/O84cV1NiwLYoyd25Z9nmWv16dIFKzf2b4=", "1234567890123456", "1234567890123456")
How would write AHK to implement the functionality of this Github example?
Do want to run this code separately as AHK?
Or do want to put this into "class_cng.ahk"?


Thanks!
according to your error message, you are trying to use the v2 version of the CNG library, but your installed AHK version is 1.1.34.02

so you should use this version of the library instead:

https://github.com/jNizM/AHK_CNG/blob/master/src/v1.1_deprecated/Class_CNG.ahk


lwx228
Posts: 49
Joined: 24 Apr 2022, 08:52

Re: CNG (Cryptography API: Next Generation)

Post by lwx228 » 10 Aug 2022, 08:34

guest3456 wrote:
09 Aug 2022, 09:05
lwx228 wrote:
09 Aug 2022, 00:30
Masonjar13 wrote:
05 Oct 2016, 04:34
Ah, alright. Thanks for clearing that up. In that case, however, you still call BCryptDestroyHash() in the W10 versions, making it redundant, yes?

My operating system is Windows 7 64-bit.AHK is to install V1.1.34.02
I want to use the AES CBC for decryption.

Code: Select all

t:= Decrypt.String("AES", "CBC", "Nn9CFFuC+/O84cV1NiwLYoyd25Z9nmWv16dIFKzf2b4=", "1234567890123456", "1234567890123456")
How would write AHK to implement the functionality of this Github example?
Do want to run this code separately as AHK?
Or do want to put this into "class_cng.ahk"?


Thanks!
according to your error message, you are trying to use the v2 version of the CNG library, but your installed AHK version is 1.1.34.02

so you should use this version of the library instead:

https://github.com/jNizM/AHK_CNG/blob/master/src/v1.1_deprecated/Class_CNG.ahk

Yes, I'm already writing code and running it using version V1.
The V2 version above is just to show that I am currently using V 1.1.34.2.

I know how to code and run code using version V1.
But is it correct to code and this way?I just added a line on the AHK of V1 version you provided. Is that all right?
Thank you very much!I mainly don't understand here (Win 7 64-bit)

guest3456
Posts: 3462
Joined: 09 Oct 2013, 10:31

Re: CNG (Cryptography API: Next Generation)

Post by guest3456 » 10 Aug 2022, 11:27

lwx228 wrote:
10 Aug 2022, 08:34
But is it correct to code and this way?I just added a line on the AHK of V1 version you provided. Is that all right?
Thank you very much!I mainly don't understand here (Win 7 64-bit)
its not correct or incorrect. its your choice

typically the standard procedure would be to write your code in a separate file, and have an #include statement either at the top or bottom, which would include the library file. you'd have to take care to either put your new script file in the same folder as the library file, or put the library file in a proper include directory. see here:

https://www.autohotkey.com/docs/commands/_Include.htm

if you scroll up early in the thread you will see people utilizing #include in their test scripts like here:

viewtopic.php?p=379770#p379770


lwx228
Posts: 49
Joined: 24 Apr 2022, 08:52

Re: CNG (Cryptography API: Next Generation)

Post by lwx228 » 11 Aug 2022, 08:35

its not correct or incorrect. its your choice

typically the standard procedure would be to write your code in a separate file, and have an #include statement either at the top or bottom, which would include the library file. you'd have to take care to either put your new script file in the same folder as the library file, or put the library file in a proper include directory. see here:

https://www.autohotkey.com/docs/commands/_Include.htm

if you scroll up early in the thread you will see people utilizing #include in their test scripts like here:

viewtopic.php?p=379770#p379770
OK!
Thanks!
Attachments
2022-08-11_21-35-03.png
2022-08-11_21-35-03.png (15.33 KiB) Viewed 2389 times

Post Reply

Return to “Scripts and Functions (v1)”