Jump to content

CryptoNG UDF - Cryptography API: Next Gen


TheXman
 Share

Recommended Posts

A new version (v1.1.0) was just published to the Downloads section of the forum.

Link to comment
Share on other sites

  • 1 month later...
3 minutes ago, Network_Guy said:

thanks for this awesome UDF,
can u provide an example of using Asymmetric RSA ?

 

You're welcome.  :thumbsup:

Currently, the UDF library only implements the following Cryptographic Primitives:

  • Hashing (i.e. SHA/MD5/PBKDF2)
  • Symmetric Encryption (i.e.  RC4/DES/3DES/AES)

I will certainly add your request to extend the library's functionality to have the ability to do Asymmetric (public key) Encryption, using RSA, to the UDF library's To Do list. 

Link to comment
Share on other sites

On 1/23/2020 at 9:29 AM, Network_Guy said:

thanks for this awesome UDF,
can u provide an example of using Asymmetric RSA ?

 

I have just uploaded a new version of the CryptoNG UDF library that includes the ability to create RSA public/private key pairs.  The UDF is _CryptoNG_CreateRSAKeyPair.  An example of how to use the new function was added the the examples file.  Please refer to the functions header to get more information related to the parameters.

There are a few things to keep in mind about this incremental new UDF functionality.  The output of the new function is a public/private key blob pair that is CryptoAPI-compatible.  Key blobs are what are used internally by Microsoft's Asymmetric Crypto NG APIs.  As I detailed in the example file, these key blob files can be easily converted to PEM or DER encoded files using tools like OpenSSL.  The addition of this new function does not add much value by itself other than showing how RSA keys can be generated using Microsoft's CryptoNG APIs because you still need some other tool to convert the file to PEM or DER.  In other words, if you need a tool like OpenSSL to convert the key blob to PEM or DER, you might as well use OpenSSL to create the key pair to begin with.  However, having the ability to create RSA key pair blobs will lend itself to being able to use the CryptoNG APIs to do asymmetric encryption/decryption/signing in the future when that functionality is added to the library.  Also, in the future, I may add the ability to convert the key blobs to DER and PEM internally, so that the UDF library doesn't rely on external tools to do the conversions.

Edited by TheXman
Link to comment
Share on other sites

  • 5 weeks later...

Hi,

Thanks for that! It looks great. That must have been a lot of work!!

 

Is it possible to encrypt data similar to the "Web Crypto Api"? In my specific case I am interested in AES CBC with PKCS7 padding. Here is an example

https://cryptii.com/pipes/aes-encryption

If it is possible, could you please post a code example (which uses the same result as the web example)?

---

PS It is not possible with the functions in Crypt.au3 unfortunately.

Edited by PeterPE
typo
Link to comment
Share on other sites

8 hours ago, PeterPE said:

Thanks for that! It looks great.

Thanks!  :)

8 hours ago, PeterPE said:

Is it possible to encrypt data similar to the "Web Crypto Api"? In my specific case I am interested in AEC CBC with PKCS7 padding.

I don't quite understand your question.  If you are asking whether the CryptoNG UDF can encrypt/decrypt data using AES with CBC chaining mode, then the answer is yes.  I don't know what your reference to "AEC" is.  I can only assume that it may have been a typo and that you meant AES.

 

8 hours ago, PeterPE said:

If it is possible, could you please post a code example

The AES example provided with the CryptoNG UDF would have provided the same results as on cryptii if it had been provided with the correct values.  The only real difference is the IV value.  The IV value used by the CryptoNG UDF is all null values (0x00 ... 0x00) instead of (0x00 0x01 0x02 ... 0x0f), which you wouldn't have known unless you looked at the __CryptoNG_BCryptEncrypt function in the UDF file.  IV is an arbitrary value and can be anything.  I just decided to use all 0x00's.  The example below has been modified to match your cryptii example:

image.thumb.png.bb6b3a6f1baaad748662531d8e5a2f77.png

#include <Constants.au3>
#include "CryptoNG.au3"

aes_encryption_example()

Func aes_encryption_example()

    Const $MESSAGE      = Binary("0x6bc1bee22e409f96e93d7e117393172a")
    Const $KEY          = Binary("0x2b7e151628aed2a6abf7158809cf4f3c")

    Local $sAlgId = ""
    Local $xEncryptedMessage = ""

    ;AES Example
    $sAlgId = $CNG_BCRYPT_AES_ALGORITHM

    ;Encrypt message
    $xEncryptedMessage = _CryptoNG_EncryptData($sAlgId, $MESSAGE, $KEY)
    If @error Then
        ConsoleWrite("ERROR: " & _CryptoNG_LastErrorMessage() & @CRLF)
        Exit 1
    EndIf

    ConsoleWrite(@CRLF)
    ConsoleWrite(StringFormat("CryptoNG UDF Version %s", _CryptoNG_Version()) & @CRLF)
    ConsoleWrite(StringFormat("%s Message           = %s", $sAlgId, $MESSAGE) & @CRLF)
    ConsoleWrite(StringFormat("%s Encryption Key    = %s", $sAlgId, $KEY) & @CRLF)
    ConsoleWrite(StringFormat("%s Encrypted Message = %s", $sAlgId, $xEncryptedMessage) & @CRLF)

EndFunc

Output

CryptoNG UDF Version 1.2.0
AES Message           = 0x6BC1BEE22E409F96E93D7E117393172A
AES Encryption Key    = 0x2B7E151628AED2A6ABF7158809CF4F3C
AES Encrypted Message = 0x3AD77BB40D7A3660A89ECAF32466EF974B0673D23DA20679744AFA8E3D589236

 

8 hours ago, PeterPE said:

PS It is not possible with the functions in Crypt.au3 unfortunately.

Although I haven't tried it, I'm pretty sure that the crypt.au3 UDF would provide the exact same results as my UDF when given the correct/same values.  Again, although I haven't looked to see what the crypt.au3 UDF function uses for it's IV, it is probably null values (just like my CryptoNG UDF).   For the record, both the CryptoNG and Crypt UDFs use CBC for AES chaining mode. 

Edited by TheXman
Link to comment
Share on other sites

Thanks for your prompt response!
 

Quote

The only real difference is the IV value.  The IV value used by the CryptoNG UDF is all null values (0x00 ... 0x00) instead of (0x00 0x01 0x02 ... 0x0f), which you wouldn't have known unless you looked at the __CryptoNG_BCryptEncrypt function in the UDF file.  IV is an arbitrary value and can be anything.  I just decided to use all 0x00's

 

Yes, that is basically the issue.

The old API (used in crypt.au3) allows to pass an IV using KP_IV in a CryptSetKeyParam call. I don't know how to pass an IV to your function?

I believe using a "hardcoded value" as IV is not a good choice. At least it should be possible to pass an IV to your function (my opinion is based on source https://crypto.stackexchange.com/questions/3965/what-is-the-main-difference-between-a-key-an-iv-and-a-nonce).

 

Quote

I haven't tried it, I'm pretty sure that the crypt.au3 UDF would provide the exact same results as my UDF when given the correct/same values.

Possible. When I tried it, it seemed the results were not the same because of different padding algorithms.

Edited by PeterPE
Link to comment
Share on other sites

2 hours ago, PeterPE said:

The old API (used in crypt.au3) allows to pass an IV using KP_IV in a CryptSetKeyParam call. I don't know how to pass an IV to your function?

I believe using a "hardcoded value" as IV is not a good choice. At least it should be possible to pass an IV to your function (my opinion is based on source https://crypto.stackexchange.com/questions/3965/what-is-the-main-difference-between-a-key-an-iv-and-a-nonce).

The Crypt.au3 UDF does not provide a function that allows you to set the IV and neither does the CryptoNG.au3 UDF.  Since the CryptSetKeyParam API function does not exist in the Crypt.au3 UDF, that means you must have had to do a little research into the deprecated API to figure that out.  So if you know enough to find the CryptSetKeyParam function in the deprecated API (and implement it), I'm sure that you should be able to figure out the correct way to do it using the CryptoNG API. 😉  Otherwise, in my previous response, I have pointed you to the function in the CryptoNG.au3 UDF where the IV is set for encryption.  If you have the skills, you can set the IV to whatever appropriate value that you would like.  If modifying the function to set the IV is too daunting a task, you could always prepend your own pseudo-IV to your message instead of specifying and actual IV or just use a different or SALTed key if you are sending multiple messages.

If you are using an Autoit script to do both the encryption and decryption of your own messages, then specifying an IV seems to be a non-issue.  The only time that I can see a need to have a user-specified IV would be if you need to decrypt a message that you have not generated and the sender has given you the IV value.  To me, given that we are talking about AutoIt scripts, that would seem to be a rare, edge case.  If you are doing a lot of low-level cryptography, then there are probably better solutions.

In any case, I will take your comments as a suggestion to add a feature that would allow a user-specified IV for block cipher encryption/decryption, where appropriate.

Thanks @PeterPE

Edited by TheXman
Link to comment
Share on other sites

Quote

 The only time that I can see a need to have a user-specified IV would be if you need to decrypt a message that you have not generated and the sender has given you the IV value.

This does not seem correct. In fact the IV becomes part of the "message" and is not secret.

"A random IV ensures that each message encrypts differently, such that seeing multiple messages encrypted with the same key doesn't give the attacker any more information than just seeing a single long message. In particular, it ensures that encrypting the same message twice yields two completely different ciphertexts, which is necessary in order for the encryption scheme to be semantically secure. "

Here is an "non edge case" example. There is a file encryption function in your UDF. Let's say a user wants to encrypt a bunch of similar files (music, video, etc). Then using the same IV can leak information about the meta data of the file. If the files have a common prefix, then this will be leaked in the common prefix of the encrypted file.

It is insecure to reuse an IV with AES-CBC. The need for an IV is not an edge case.

The "venerable Ward UDF" for example adds an additional parameter IV, and the IV is returned together with the Ciphertext. The Default is a random IV.

Func _AesEncrypt($Key, $Data, $Mode = $AES_CBC_MODE, $IV = Default)

 

In any case, I am happy that you created this great UDF! And I am happy that you consider this as a feature request.

And may I add another feature request? A function for random data would be nice too (something like BCryptGenRandom).

 

Thanks again for your great work!

 

 

Link to comment
Share on other sites

@PeterPE

Thanks!

I have added both of your requests to the CryptoNG todo list.  :)

Link to comment
Share on other sites

42 minutes ago, PeterPE said:

I definitely not only consider this is as a feature request, but also as "security vulnerability report".

I strongly disagree!  If you think that it is such a vulnerability, you are more than welcome to use a different solution or write your own.

:naughty:

Edited by TheXman
Link to comment
Share on other sites

A new version (v1.3.0) was just published to the Downloads section of the forum.

  • Added _CryptoNG_GenerateRandom and supporting internal function.
  • Added an example of how to implement the new function to the examples file.
Link to comment
Share on other sites

  • 1 month later...

A new version (v1.4.0) was just published to the Downloads section of the forum.

  • Added a Help file that includes all of the functions, with examples.  The look & feel of the help file matches the standard AutoIt help files.
  • Updated the _CryptoNG_DecryptFile function to create the output file's path if it doesn't exist.
  • Updated the _CryptoNG_EncryptFile function to create the output file's path if it doesn't exist.
  • Cleaned up several of the function headers.

All of the HTML files in the new Help file were created without the help of any automation tools.  Therefore, there may be some typos, errors, or omissions.  I tried very hard to make sure that all of the information is correct and that all of the links work.  If you happen to come across any issues in the help file, please let me know so that I can get them corrected.

:ILA:

Link to comment
Share on other sites

39 minutes ago, Colduction said:

can you add AES-256-GCM

That is an oddly specific request.  Why just AES-256-GCM?  What about AES-128-GCM?   :)

I will definitely add your request to my "Requested Features List.  Although I'm not entirely opposed to adding AES-GCM encryption & decryption, I'm not sure that it is worth the effort.  Since there are other tools available that can easily be incorporated into an AutoIt script that will encrypt & decrypt data using AES-GCM, the addition of that feature in the CryptoNG UDF would be a very low priority.  It would also have a very low priority because you are first person in this forum to ever request AES-GCM.  So it doesn't seem to be a very big need for that cryptographic algorithm.  But who knows, given the fact that I have a bit of extra time on my hands due the shelter-in-place orders related to the COVID-19 virus, I might get bored enough to work on it.  :)

Link to comment
Share on other sites

8 hours ago, TheXman said:

That is an oddly specific request.  Why just AES-256-GCM?

Because some of my sensitive datas are crypted in AES-256-GCM, i have Secret Key and other informations such as IV, but i have not a decrypter to do this :(

Link to comment
Share on other sites

A new version (v1.5.0) was just published to the Downloads section of the forum.

 

What's new in v1.5.0

  • Begun adding algorithm-specific encryption/decryption functions starting with:
    • _CryptoNG_3DES_CBC_DecryptData
    • _CryptoNG_3DES_CBC_DecryptFile
    • _CryptoNG_3DES_CBC_EncryptData
    • _CryptoNG_3DES_CBC_EncryptFile
    • _CryptoNG_AES_CBC_DecryptData
    • _CryptoNG_AES_CBC_DecryptFile
    • _CryptoNG_AES_CBC_EncryptData
    • _CryptoNG_AES_CBC_EncryptFile
  • Updated the compiled Help file with the new functions and a new page that lists common named-value constants in the appendix.
  • Added new internal functions to support the new algorithm-specific functions above.
  • Cleaned up a few function headers.
  • Added new examples, for the new functions, to the examples file.
  • Fixed a small bug in how the size of the IV buffer was being determined when doing block cipher encryption and decryption. The length of the IV should match the algorithm's block size, not its key size.  NOTE: The bug did NOT affect the accuracy of the results, just the size of the buffer.
  • Corrected $CNG_KEY_BIT_LENGTH_3DES constant value.  The value was changed from 168 to 192.  168 was the usable/logical bit length but the actual bit length is 192.
Edited by TheXman
Link to comment
Share on other sites

  • 2 months later...

A praise-sandwich ;) for CryptoNG:

Top bread slice: Great work; thorough, methodical, consistent, clean code, and well-documented; an excellent contribution all-round.

The filling: At the moment, the library does not handle UTF-8 strings correctly. Just adding

If $bResultIsText Then $vDecryptedData = BinaryToString($vDecryptedData, $SB_UTF8)

in __CryptoNG_BCryptDecrypt is not enough; you need to take wide chars into account at the encryption stage too! For example, in __CryptoNG_BCryptEncrypt, you need to do something like this:

;Create input buffer and move input to the buffer
    $tInputBuffer = DllStructCreate(StringFormat("byte data[%i]", BinaryLen(StringToBinary($vData,$SB_UTF8))))
    DllStructSetData($tInputBuffer,"data",StringToBinary($vData,$SB_UTF8))

Of course, this also affects passwords and salts, and anything else that relies on string inputs. Imagine what would happen if a user changes locale between encryption and decryption...

Furthermore, you cannot properly test this using your current example suite, as you use Consolewrite for examining output, which would require a registry hack each time to select the appropriate code page(s) to render non-English UTF8 characters correctly. MsgBox does this out of the box:D (at least in my tests). For example, replace your test input string in your aes example by this (grabbed from  Help's StringToBinary example):

Func aes_encrypt_decrypt_example()

    Const $MESSAGE      = "Hello - 你好", _
          $SECRET       = "Secret Password!", _
          $SECRET_SALT  = "Secret Salt"

and watch it fail (both to encrypt correctly and (when patched) to represent correctly in console output).

BTW, your recent "upgrade" of filling struct members using dot notation causes my scripts to error out (on every dot-based struct access) with:

"<path>\CryptoNG.v1.5.5.au3" (2743) : ==> Variable must be of type "Object".:
$tInputBuffer.data = Binary($vData)

Haven't got a reproducer for you to test (and your examples run okay), but I've also read that access using dot notation is slower than using DllstructSetData (again, not tested myself (yet)), so you may want to look into that as well. Personally, I just restore dllstructSet/getData everywhere (neeeeed speeeeed!), but your code of course looks cleaner. Your call.

Bottom bread slice: As you know, I've gratefully incorporated your library into my own CodeCrypter environment, and it's proving a real asset, so many, many thanks for your continuing efforts, and I hope you'll keep maintaining it.

Edited by RTFC
typo
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...