Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

[AHK_L] Crypt - ahk cryptography class (Encryption, Hashing)


  • Please log in to reply
83 replies to this topic
Deo
  • Members
  • 199 posts
  • Last active: Jan 31 2014 03:19 PM
  • Joined: 16 May 2010
Hello
I've created a small piece of Cryptography API, implementing basic functions for Encryption and Hashing.

Require:
[*:zvn4n35m] AHK_L Unicode x32
[*:zvn4n35m] AHK_L Unicode x64
Download:
Crypt.zip

Here is list of current features:
[*:zvn4n35m]Encrypt/Decrypt file
[*:zvn4n35m]Encrypt/Decrypt string using transferable hash
[*:zvn4n35m]Calculating hash of file and any string
[*:zvn4n35m]Supported encryption algorithms - RC4, RC2, 3DES, 3DES_112, AES_128, AES_192, AES_256
[*:zvn4n35m]Supported HASH algorithms - MD5, MD2, SHA1, SHA_256, SHA_384, SHA_512 and HMACI've tried to make all things easy to use as possible.
Here is a list of methods
Crypt.Encrypt.FileEncrypt(pFileIn,pFileOut,password,CryptAlg = 1, HashAlg = 1)
Crypt.Encrypt.FileDecrypt(pFileIn,pFileOut,password,CryptAlg = 1, HashAlg = 1)
Crypt.Encrypt.StrEncrypt(string,password,CryptAlg = 1, HashAlg = 1)
Crypt.Encrypt.StrDecrypt(EncryptedHash,password,CryptAlg = 1, HashAlg = 1)
Crypt.Hash.FileHash(pFile,HashAlg = 1,pwd = "",hmac_alg = 1)
Crypt.Hash.StrHash(string,HashAlg = 1,pwd = "",hmac_alg = 1)
StrDecryptToFile(EncryptedHash,pFileOut,password,CryptAlg = 1, HashAlg = 1)
FileEncryptToStr(pFileIn,password,CryptAlg = 1, HashAlg = 1)
You can find more info about each parameter inside Crypt.ahk

Example:
#Include Crypt.ahk

bytes := Crypt.Encrypt.FileEncrypt("WinError.h","WinError.cr","IwantAcake")	; encrypts file using RC4 encryption and MD5 hash
msgbox % "Bytes writen: " bytes
bytes := Crypt.Encrypt.FileDecrypt("WinError.cr","WinError2.h","IwantAcake") ; decrypts file encrypted with RC4 and MD5
msgbox % "Bytes writen: " bytes

bytes := Crypt.Encrypt.FileEncrypt("WinError.h","WinError.cr","IwantAcake",7,6)	; encrypts file using AES_256 encryption and SHA_512 hash
msgbox % "Bytes writen: " bytes
bytes := Crypt.Encrypt.FileDecrypt("WinError.cr","WinError2.h","IwantAcake",7,6) ; decrypts file encrypted with AES_256 and SHA_512
msgbox % "Bytes writen: " bytes

hash := Crypt.Encrypt.StrEncrypt("MS encryption works in that way","007",5,1) ; encrypts string using AES_128 encryption and MD5 hash
msgbox % hash
decrypted_string := Crypt.Encrypt.StrDecrypt(hash,"007",5,1)				  ; decrypts the string using previously generated hash,AES_128 and MD5
msgbox % decrypted_string

hash := Crypt.Hash.FileHash("WinError.h") ; get a MD5 HASH of file, its 55EEE971C6357584B4F0EDB6194E2987
msgbox % hash
hash := Crypt.Hash.FileHash("WinError.h",3) ; get a SHA1 HASH of file, B65C8825FB47B72A8A15EF85E48C0C8BD5C50D51
msgbox % hash
hash := Crypt.Hash.FileHash("WinError.h",6,"Hello,World!",7) ; get a HMAC SHA_512 HASH of file using password "Hello,World!" and AES_256 encryption key
msgbox % hash

hash := Crypt.Hash.StrHash("RabbidsGoHome",2) ; gets a MD2 HASH of string and result is A81FE29CEA80104F9D6DB0615F805B79
msgbox % hash

Updates:
28.06.2012
Fixed Hash/Encrypting of files with UTF-16 encoding

07.05.2012
StrEncrypt/StrDecrypt uses base64 to encode/decode strings

9.12.2011
Fixed "var" to "static" var definition
Fix for bad password len calculating

21.06.2011:
added following functions:
Crypt.Encrypt.FileEncryptToStr()
Crypt.Encrypt.StrDecryptToFile()
fixed return values - "" instead of 0 in case of errors
few checks added

15.06.2011:
-Added fileds to set string or password encoding
-changed getlasterror() function
-few changes & fixes

06.06.2011:
-Encryption now work correctly with x64 build
-hashable password string changed to unicode from ansi
-no msgbox will appear in case of any errors if script is compiled



shajul
  • Members
  • 571 posts
  • Last active: Aug 01 2015 03:45 PM
  • Joined: 15 Sep 2006
This was very much required!! Wonderful work.
Btw, why is GetLastError function used, is it not the same as A_LastError?
If i've seen further it is by standing on the shoulders of giants

my site | ~shajul | WYSIWYG BBCode Editor

Deo
  • Members
  • 199 posts
  • Last active: Jan 31 2014 03:19 PM
  • Joined: 16 May 2010
a small update were made so encryption now works with x64 build

guest3456
  • Members
  • 1704 posts
  • Last active: Nov 19 2015 11:58 AM
  • Joined: 10 Mar 2011
didnt have time to check, but does this wrap the windows crypto api?
edit: i see it does. thanks

IsNull
  • Moderators
  • 990 posts
  • Last active: May 15 2014 11:56 AM
  • Joined: 10 May 2007
This looks pretty cool. I didn't seen any library yet which is as equaly comprehensive. Thank you.

Qriist
  • Members
  • 11 posts
  • Last active: Dec 30 2011 01:28 PM
  • Joined: 28 Jun 2009
This looks very cool!

A question or two. :)
-Would you be able to implement CRC32 hashing? Please and thank you.
-Is it possible now or in the future to generate multiple hashes on one library call?

Deo
  • Members
  • 199 posts
  • Last active: Jan 31 2014 03:19 PM
  • Joined: 16 May 2010
i've found some sort of CRC-32 algorith here

if it works right, it can be easily implemented into crypt class

What do you mean under "generate multiple hashes on one library call"?

Qriist
  • Members
  • 11 posts
  • Last active: Dec 30 2011 01:28 PM
  • Joined: 28 Jun 2009
What I mean is, your library (awesomeness that it is) will be used to hash many very large files (anywhere from a few hundred megabytes to as large as a full Dual Layer DVD.) I would like to avoid making several passes over the data and instead use "branches" (lack of better term) of data to generate multiple hashes on the same file in one go. In particular, I am wanting CRC32, MD5, SHA1 for each and every file.

For a program that appears to do as I am asking, check out <!-- m -->http://www.slavasoft.../fsum/index.htm<!-- m --> ... This particular program appears to process multiple specified hash schemes in one pass over the physical data. When testing, adding multiple hashes takes a bit longer than a single hash, but not long as it would be if it hashed in sequence (read file, hash1 file, read file, hash2 file, etc) as opposed to hashing in parallel (read file, hash1 + hash2 + hash3 file)

Wall of text fears aside, I hope that made sense. Keep up the good work!

IsNull
  • Moderators
  • 990 posts
  • Last active: May 15 2014 11:56 AM
  • Joined: 10 May 2007
That would require a custom implementation of those algorythms in a single master algorythm, so that they can share some common file/array pointers. However, the time it takes to implement that is just justified in your specail case, as if you dont need one of the calculated algorythm there will be wasted cpu time.
Jm2c

Qriist
  • Members
  • 11 posts
  • Last active: Dec 30 2011 01:28 PM
  • Joined: 28 Jun 2009
Well, perhaps I can delve into making a custom command for the multi-hash bit. In the meantime, I would greatly like CRC32. Please and thank you. :)

Deo
  • Members
  • 199 posts
  • Last active: Jan 31 2014 03:19 PM
  • Joined: 16 May 2010
i see what you mean
i'll think about how to make this easy-to-use

muriloq
  • Members
  • 6 posts
  • Last active: Jun 17 2011 12:11 PM
  • Joined: 14 Jun 2011
I'm using AutoHotKeyU and your library works fine.

The problem is that the password and the message to be encrypted uses UTF-16.

I need to encrypt the data using a Linux application, aespipe, which only supports UTF-8.

So I can't encrypt using Linux and decrypt using Crypt.hk, and vice-versa.

Is it possible to force your library to submit UTF-8 strings to the native DLL? I tried to convert them before the DLLCalls to CryptHashData and CryptEncrypt, without success (I've started using AHK today so I'm not very good at this).

An alternative would be to encrypt in Linux using a Java library that supports UTF-16; that's what I'm trying next.

Thanks a lot!

Deo
  • Members
  • 199 posts
  • Last active: Jan 31 2014 03:19 PM
  • Joined: 16 May 2010
muriloq
you can find a possibility to set string/password encoding in new version, works like that:
c := Crypt.Encrypt
hash1 := c.StrEncrypt("MS","007",5,1)
c.StrEncoding := "UTF-8"
hash2 := c.StrEncrypt("MS","007",5,1)
c.PassEncoding := "UTF-8"
hash3 := c.StrEncrypt("MS","007",5,1)
c.StrEncoding := "UTF-16"
c.PassEncoding := "UTF-16"
hash4 := c.StrEncrypt("MS","007",5,1)
msgbox % hash1 "`n" hash2 "`n" hash3 "`n" hash4
default values for Encrypt class
StrEncoding = "UTF-16"
PassEncoding = "UTF-16"
for Hash class
StrEncoding = "CP0" (ANSI)
PassEncoding = "UTF-16"

muriloq
  • Members
  • 6 posts
  • Last active: Jun 17 2011 12:11 PM
  • Joined: 14 Jun 2011
Deo

Thanks a lot for your attention!

Unfortunately your suggestion doesn't seem to work.

The problem occurs when the string is converted to a byte array.

I've added a debug message after line 117 (it's the last line below):

VarSetCapacity(str_buf,len+100,0)
strput(string,&str_buf)
msgbox % ByteToHash(str_buf, len+100)

It shows that a 00 byte is put after each character in the string, even if it's set to UTF-8. That's the problem I'm facing.

In your example the message "MS" becomes 4D 00 53 00 and not 4D 53 as expected (4D is the code for "M" and 53 is the code for "S", but in UTF-16 "M" is 4D 00, not just 4D).

Using aespipe in Linux I can't have a 00 inside the message or password strings, so I can't encode it using UTF-16.

It seems that instead of calling of passing "WStr" in the dllcall to CryptHashData (and others) you should use just "Str", or maybe specify the type as an actual byte array, not a string.

Besides that, why you add 100 to the length of the String? I understand you multiply the length by 2 because you are converting to UTF-16, but simply adding 100 is strange. If I understand correctly you must pad the block size to 16 bytes (since AES block size is 128bits), not simply add 100 to it.

If you have a Linux machine available you can try it yourself:

The hash produced by calling your code with

c.StrEncrypt("MS","12345678901234567890",7,6)
should be identical to the one produced by

echo -n MS | aespipe -e AES256 -H SHA512 | hexdump -e '/1 "%2x "'

(entering the same password in the command-line; aespipe requires password with at least 20 characters that's why I used 12345678901234567890 )

The output is different because your code doesn't encrypt the byte array

4D 53 00 00 00 00 00 00 00 00 00 00 00 00 00 00

as aespipe does, it encrypts the byte array

4D 00 53 00 (plus 96 bytes with value 00).

Does't it make sense?

Thanks again for your time and effort.

Deo
  • Members
  • 199 posts
  • Last active: Jan 31 2014 03:19 PM
  • Joined: 16 May 2010
hi, muriloq
forgot to say, - i've changed a few things in crypt.ahk so it could be possible to use different encoding for password/string, and you need to download a new version and try to do this things again
seems like you just tried this with the old version of this lib
let me know about your progress