This function was written to handle large files (several GB's).
If your data size measures a few MB's and you prefer to handle things in memory, try: VarV
The function along with an example:
Code: Select all
FileCryptFile(Mode, Src, Trg, sKey) { ; v0.66 By SKAN on D442/D44H @ tiny.cc/filecryptfile
Local ;
; File Format: .aea
; Offset Size Type Description
; 0 4 UTF-8 ".aea"
; 4 4 UInt Block size. Max value 524,288 bytes.
; 8 32 Bytes IV (Initialization vector), RNG values.
; 40 Bytes Encrypted data in single/multiple blocks.
;
; Data encryption method: AES-256-CBC
; KeyPhrase (sKey parameter) is hashed with SHA256 using IV as salt.
If !Strlen(sKey)
Return (0, ErrorLevel := "Key required")
Mode := (Mode != "Encrypt" ? "Decrypt" : "Encrypt"), Encrypt := (Mode = "Encrypt"), Decrypt := (Mode = "Decrypt")
VarSetCapacity(Head, 40, 0), pIni := &Head+8, nIni := 32
FileSrc := FileOpen(Src, "r -rwd"), FileSrc.Pos := 0, nHead := FileSrc.RawRead(&Head, 40)
FileSrcSize := FileSrc.Length, FileSrc.Close()
nBytes := Min( (FileSrcSize+=16) - Mod(FileSrcSize,16), 1024*512 )
If !( FileSrcSize )
Return (0, ErrorLevel := FileSrcSize=0 ? "Source file is 0 bytes" : FileExist(Src) ? "Error opening Source file."
: "Source file does not exist.")
If !( FileOpen(Trg, "w -rwd").__Handle )
Return (0, ErrorLevel := "Error creating Target file")
If ( Decrypt )
If ( nHead!=40 Or StrGet(&Head, 4, "utf-8") != ".aea" )
Return (0, ErrorLevel := "Source not a .aea file.")
Else If ( (blkSz := NumGet(&Head, 4, "UInt")) = 0 || blkSz > 1024*512)
Return (0, ErrorLevel := ".aea version mismatch.")
SetBatchLines, % (-1, BatchLines := A_BatchLines)
hKey := 0, hAlg := 0, hHash := 0
hBcrypt := DllCall("Kernel32.dll\LoadLibrary", "Str","Bcrypt.dll", "Ptr")
If ( Encrypt )
StrPut(".aea", &Head, 4, "utf-8") ; BCRYPT_USE_SYSTEM_PREFERRED_RNG := 0x2
, DllCall("Bcrypt.dll\BCryptGenRandom", "Ptr",hAlg, "Ptr",pIni, "Int",nIni, "Int",0x2)
, NumPut(FileSrcSize, &Head, 4, "UInt")
If ( [sKey].GetCapacity(1) = "" )
VarSetCapacity(Key, 32, 0), DllCall("Kernel32.dll\RtlMoveMemory", "Ptr",&Key, "Ptr",sKey+0, "Ptr",32)
Else
cbKey := StrPut(sKey,"utf-8"), VarSetCapacity(Key, Max(32,cbKey), 0), cbKey := StrPut(sKey, &Key, cbKey, "utf-8") -1
, DllCall("Bcrypt.dll\BCryptOpenAlgorithmProvider", "PtrP",hAlg, "WStr","SHA256", "Ptr", 0, "Int",0x8) ; HMAC = 0x8
, DllCall("Bcrypt.dll\BCryptCreateHash", "Ptr",hAlg, "PtrP",hHash, "Ptr",0, "Int",0, "Ptr",pIni, "Int",nIni, "Int",0)
, DllCall("Bcrypt.dll\BCryptHashData", "Ptr",hHash, "Ptr",&Key, "Int",cbKey, "Int",0)
, DllCall("Bcrypt.dll\BCryptFinishHash", "Ptr",hHash, "Ptr",&Key, "Int",32, "Int",0)
, DllCall("Bcrypt.dll\BCryptDestroyHash", "Ptr",hHash)
, DllCall("Bcrypt.dll\BCryptCloseAlgorithmProvider", "Ptr",hAlg, "Int",0)
DllCall("Bcrypt.dll\BCryptOpenAlgorithmProvider", "PtrP",hAlg, "WStr","AES", "Ptr",0, "Int",0)
DllCall("Bcrypt.dll\BCryptSetProperty", "Ptr",hAlg, "WStr","ChainingMode", "WStr","ChainingModeCBC", "Int",15, "Int",0)
DllCall("Bcrypt.dll\BCryptGenerateSymmetricKey","Ptr",hAlg, "PtrP",hKey, "Ptr",0, "Int",0, "Ptr",&Key, "Int",32, "Int",0)
FileSrc := FileOpen(Src, "r -rwd"), FileSrc.Pos := Encrypt ? 0 : 40
FileTrg := FileOpen(Trg, "w -rwd"), FileTrg.Pos := Decrypt ? 0 : FileTrg.RawWrite(&Head,40)
rBytes := nBytes-Encrypt, wBytes := 0, VarSetCapacity(Bin, nBytes)
Loop
{ rBytes := FileSrc.RawRead(&Bin, rBytes)
nErr := DllCall("Bcrypt.dll\BCrypt" . Mode, "Ptr",hKey, "Ptr",&Bin, "Int",rBytes, "Ptr",0,"Ptr"
, pIni, "Int",nIni, "Ptr",&Bin, "Int",nBytes, "UIntP",wBytes, "Int",1, "UInt")
wBytes := nErr? 0 : FileTrg.RawWrite(&Bin, wBytes)
} Until ( nErr Or FileSrc.AtEOF )
FileSrc.Close(), FileTrg.Close()
DllCall("Bcrypt.dll\BCryptDestroyKey", "Ptr",hKey)
DllCall("Bcrypt.dll\BCryptCloseAlgorithmProvider", "Ptr",hAlg, "Int", 0)
DllCall("Kernel32.dll\FreeLibrary", "Ptr",hBCrypt)
SetBatchLines, % ( BatchLines )
Return (True, ErrorLevel := nErr ? Format("Bcrypt error: 0x{:08X}", nErr) : "")
}
; Usage example
#NoEnv
#Warn
#SingleInstance, Force
SetWorkingDir, %A_ScriptDir%
Original := A_AhkPath . "\..\license.txt"
Encrypted := "license.txt.aea"
Decrypted := "license_new.txt"
KeyPhrase := "unbent-snugly-mousy-swivel-collide" ; Phrase generated @ https://www.useapassphrase.com/
If FileCryptFile("encrypt", Original, Encrypted, KeyPhrase)
FileCryptFile("decrypt", Encrypted, Decrypted, KeyPhrase)
Msgbox % ( ErrorLevel ? ErrorLevel : "Done" )