Search code examples
encryptionautoit3des

_Crypt_EncryptData() and _Crypt_DecryptData() confusion


I'm running into problems with _Crypt_EncryptData(). I want to encrypt data, store it, then read it back decrypted.

It seems _Crypt_EncryptData() and _Crypt_DecryptData() are not symmetric; the former does an implicit hexadecimal encoding on the output value. But the latter does an implicit binary conversion on the input (so far so good), but then does an implicit hexadecimal conversion on its output! Hence within a single file:

$ciphertext=_Crypt_EncryptData($cleartext, $g_hKey, $CALG_3DES)
$cleartext=_HexToString(_Crypt_DecryptData($ciphertext, $g_hKey, $CALG_3DES))

(erk!) will give me back the original cleartext. I was unable to recover the cleartext from a file across invocations. The ciphertext was changing each time, e.g. with the string "This is a test", on subsequent executions I got:

 0x0B656F9BCC35B73A6EA9D08701E78713
 0xEBE1E744668C379CE74480C3A56303A2
 0x25F50D6B833B3CEF60FCFAF8AE673CF3

I would expect this if due to different initialization vectors, however looking at "Crypt.au3" I see no way to set or get the IV (I know DES3 is insecure - that's a different battle). Is it me or is it AutoIt?

Here is the full source of a script to reproduce the issue:

#include <StringConstants.au3>
#include <Crypt.au3>
#include <String.au3>

_Crypt_Startup() 
$inifile="C:\test_au_enc.ini"
$g_hKey = _Crypt_DeriveKey("s3cr3t.S4uce", $CALG_3DES)

; test previous invocation
$readback=IniRead($inifile, "main", "pass", "Failed")
if ("Failed"=$readback) Then
   MsgBox(0, "Enc Dec", "Failed to read ini file")
Else
   $dec=_HexToString(_Crypt_DecryptData($readback, $g_hKey, $CALG_3DES))
   MsgBox(0,"Enc Dec", "Read from previous: " & $dec)
   ; this fails to recover the cleartext
EndIf


$subj=InputBox("Enc Dec", "Please supply a string to encrypt", "This is a test");

; encrypt the string and write it to a file...
$enc=_Crypt_EncryptData($subj, $g_hKey, $CALG_3DES)
IniWrite($inifile, "main", "pass", $enc)

; now read back the value and decrypt
$readback=IniRead($inifile, "main", "pass", "Failed")
$dec=_HexToString(_Crypt_DecryptData($readback, $g_hKey, $CALG_3DES))
InputBox("Enc Dec", "Encrypted:" & $enc & @CRLF & "decrypted:" & $dec, $enc)
; here the decrypted text matches the cleartext 

Solution

  • As per help file; use of _Crypt_DeriveKey() is correct, but you are supposed to call _Crypt_EncryptData() and _Crypt_DecryptData() like this when using your own derived key:

    $enc = _Crypt_EncryptData($subj, $g_hKey, $CALG_USERKEY)
    $dec = _HexToString(_Crypt_DecryptData($readback, $g_hKey, $CALG_USERKEY))
    

    Difference being $CALG_USERKEY for the $iAlgID parameter, which tells to treat the $vCryptKey parameter as a handle to a key instead of a password. This appears to work as intended.

    Here is the full code:

    #include <StringConstants.au3>
    #include <Crypt.au3>
    #include <String.au3>
    
    _Crypt_Startup()
    $inifile="C:\test_au_enc.ini"
    $g_hKey = _Crypt_DeriveKey("s3cr3t.S4uce", $CALG_3DES)
    
    ; test previous invocation
    $readback=IniRead($inifile, "main", "pass", "Failed")
    if ("Failed"=$readback) Then
       MsgBox(0, "Enc Dec", "Failed to read ini file")
    Else
       $dec=_HexToString(_Crypt_DecryptData($readback, $g_hKey, $CALG_USERKEY))
       MsgBox(0,"Enc Dec", "Read from previous: " & $dec)
       ; this fails to recover the cleartext
    EndIf
    
    
    $subj=InputBox("Enc Dec", "Please supply a string to encrypt", "This is a test");
    
    ; encrypt the string and write it to a file...
    $enc=_Crypt_EncryptData($subj, $g_hKey, $CALG_USERKEY)
    IniWrite($inifile, "main", "pass", $enc)
    
    ; now read back the value and decrypt
    $readback=IniRead($inifile, "main", "pass", "Failed")
    $dec=_HexToString(_Crypt_DecryptData($readback, $g_hKey, $CALG_USERKEY))
    InputBox("Enc Dec", "Encrypted:" & $enc & @CRLF & "decrypted:" & $dec, $enc)
    ; here the decrypted text matches the cleartext