文件的哈希值校验算法

文件MD5 CRC32.ahk

Plain text
复制到剪贴板
Open code in new window
EnlighterJS 3 Syntax Highlighter
MsgBox % FileCRC32(A_AhkPath)
MsgBox % MD5_File(A_AhkPath)
; ************ MD5 hashing functions by Laszlo *******************
FileCRC32( sFile="",cSz=4 ) { ; by SKAN 10-Oct-2009 www.autohotkey.com/community/viewtopic.php?t=64211
cSz := (cSz<0||cSz>8) ? 2**22 : 2**(18+cSz), VarSetCapacity(Buffer,cSz,0)
, hFil := DllCall("CreateFile", "Str", sFile, "UInt", 0x80000000, "Int", 3, "Int", 0, "Int", 3, "Int", 0, "Int", 0)
IfLess,hFil,1, Return,hFil
hMod := DllCall("LoadLibrary", "Str", "ntdll.dll"), CRC32 := 0
, DllCall("GetFileSizeEx", "UInt",hFil, "UInt",&Buffer), fSz := NumGet(Buffer, 0,"Int64")
Loop % ( fSz//cSz + !!Mod( fSz,cSz ) )
DllCall("ReadFile", "UInt", hFil, "UInt", &Buffer, "UInt", cSz, "UIntP",Bytes, "UInt",0)
, CRC32 := DllCall("NTDLL\RtlComputeCrc32", "UInt", CRC32, "UInt", &Buffer, "UInt", Bytes, "UInt")
DllCall("CloseHandle", "UInt", hFil)
SetFormat, Integer, % SubStr((AFI := A_FormatInteger) "H", 0)
CRC32 := SubStr(CRC32 + 0x1000000000, -7), DllCall("CharUpper", "Str", CRC32)
SetFormat, Integer, %AFI%
Return CRC32, DllCall("FreeLibrary", "UInt", hMod)
}
MD5_File(sFile="", cSz=4) { ; www.autohotkey.com/forum/viewtopic.php?p=275910#275910
cSz := (cSz<0||cSz>8) ? 2**22 : 2**(18+cSz), VarSetCapacity(Buffer, cSz, 0)
hFil := DllCall("CreateFile", "Str", sFile, "UInt", 0x80000000, "Int", 1,"Int", 0,"Int", 3,"Int", 0,"Int", 0)
IfLess,hFil,1, Return,hFil
DllCall("GetFileSizeEx", "UInt", hFil, "Str", Buffer), fSz := NumGet(Buffer, 0, "Int64")
VarSetCapacity(MD5_CTX, 104, 0), DllCall("advapi32\MD5Init", "Str", MD5_CTX)
LoopNum := fSz//cSz
Loop % (LoopNum +!!Mod(fSz,cSz))
{
if (LoopNum > 125)
ToolTip % (A_index * cSz *100) / fSz "%"
DllCall("ReadFile", "UInt", hFil, "Str", Buffer, "UInt", cSz, "UIntP", bytesRead, "UInt", 0)
, DllCall("advapi32\MD5Update", "Str", MD5_CTX, "Str", Buffer, "UInt", bytesRead)
}
if (LoopNum > 125)
ToolTip
DllCall("advapi32\MD5Final", "Str", MD5_CTX), DllCall("CloseHandle", "UInt", hFil)
Loop % StrLen(Hex:="123456789ABCDEF0")
N := NumGet(MD5_CTX, 87+A_Index, "Char"), MD5 .= SubStr(Hex,N>>4,1) . SubStr(Hex,N&15,1)
Return MD5
}
MD5(ByRef V, L=0) { ; www.autohotkey.com/forum/viewtopic.php?p=275910#275910
VarSetCapacity( MD5_CTX,104,0 ), DllCall( "advapi32\MD5Init", "Str",MD5_CTX )
DllCall("advapi32\MD5Update", "Str", MD5_CTX, "Str", V, "UInt", L ? L : VarSetCapacity(V) )
DllCall("advapi32\MD5Final", "Str", MD5_CTX )
Loop % StrLen(Hex:="123456789ABCDEF0")
N := NumGet(MD5_CTX,87+A_Index, "Char"), MD5 .= SubStr(Hex,N>>4,1) . SubStr(Hex,N&15,1)
Return MD5
}
MsgBox % FileCRC32(A_AhkPath) MsgBox % MD5_File(A_AhkPath) ; ************ MD5 hashing functions by Laszlo ******************* FileCRC32( sFile="",cSz=4 ) { ; by SKAN 10-Oct-2009 www.autohotkey.com/community/viewtopic.php?t=64211 cSz := (cSz<0||cSz>8) ? 2**22 : 2**(18+cSz), VarSetCapacity(Buffer,cSz,0) , hFil := DllCall("CreateFile", "Str", sFile, "UInt", 0x80000000, "Int", 3, "Int", 0, "Int", 3, "Int", 0, "Int", 0) IfLess,hFil,1, Return,hFil hMod := DllCall("LoadLibrary", "Str", "ntdll.dll"), CRC32 := 0 , DllCall("GetFileSizeEx", "UInt",hFil, "UInt",&Buffer), fSz := NumGet(Buffer, 0,"Int64") Loop % ( fSz//cSz + !!Mod( fSz,cSz ) ) DllCall("ReadFile", "UInt", hFil, "UInt", &Buffer, "UInt", cSz, "UIntP",Bytes, "UInt",0) , CRC32 := DllCall("NTDLL\RtlComputeCrc32", "UInt", CRC32, "UInt", &Buffer, "UInt", Bytes, "UInt") DllCall("CloseHandle", "UInt", hFil) SetFormat, Integer, % SubStr((AFI := A_FormatInteger) "H", 0) CRC32 := SubStr(CRC32 + 0x1000000000, -7), DllCall("CharUpper", "Str", CRC32) SetFormat, Integer, %AFI% Return CRC32, DllCall("FreeLibrary", "UInt", hMod) } MD5_File(sFile="", cSz=4) { ; www.autohotkey.com/forum/viewtopic.php?p=275910#275910 cSz := (cSz<0||cSz>8) ? 2**22 : 2**(18+cSz), VarSetCapacity(Buffer, cSz, 0) hFil := DllCall("CreateFile", "Str", sFile, "UInt", 0x80000000, "Int", 1,"Int", 0,"Int", 3,"Int", 0,"Int", 0) IfLess,hFil,1, Return,hFil DllCall("GetFileSizeEx", "UInt", hFil, "Str", Buffer), fSz := NumGet(Buffer, 0, "Int64") VarSetCapacity(MD5_CTX, 104, 0), DllCall("advapi32\MD5Init", "Str", MD5_CTX) LoopNum := fSz//cSz Loop % (LoopNum +!!Mod(fSz,cSz)) { if (LoopNum > 125) ToolTip % (A_index * cSz *100) / fSz "%" DllCall("ReadFile", "UInt", hFil, "Str", Buffer, "UInt", cSz, "UIntP", bytesRead, "UInt", 0) , DllCall("advapi32\MD5Update", "Str", MD5_CTX, "Str", Buffer, "UInt", bytesRead) } if (LoopNum > 125) ToolTip DllCall("advapi32\MD5Final", "Str", MD5_CTX), DllCall("CloseHandle", "UInt", hFil) Loop % StrLen(Hex:="123456789ABCDEF0") N := NumGet(MD5_CTX, 87+A_Index, "Char"), MD5 .= SubStr(Hex,N>>4,1) . SubStr(Hex,N&15,1) Return MD5 } MD5(ByRef V, L=0) { ; www.autohotkey.com/forum/viewtopic.php?p=275910#275910 VarSetCapacity( MD5_CTX,104,0 ), DllCall( "advapi32\MD5Init", "Str",MD5_CTX ) DllCall("advapi32\MD5Update", "Str", MD5_CTX, "Str", V, "UInt", L ? L : VarSetCapacity(V) ) DllCall("advapi32\MD5Final", "Str", MD5_CTX ) Loop % StrLen(Hex:="123456789ABCDEF0") N := NumGet(MD5_CTX,87+A_Index, "Char"), MD5 .= SubStr(Hex,N>>4,1) . SubStr(Hex,N&15,1) Return MD5 }
MsgBox % FileCRC32(A_AhkPath)

MsgBox % MD5_File(A_AhkPath)


; ************  MD5 hashing functions by Laszlo  *******************

FileCRC32( sFile="",cSz=4 ) { ; by SKAN 10-Oct-2009  www.autohotkey.com/community/viewtopic.php?t=64211
  cSz := (cSz<0||cSz>8) ? 2**22 : 2**(18+cSz), VarSetCapacity(Buffer,cSz,0)
  , hFil := DllCall("CreateFile", "Str", sFile, "UInt", 0x80000000, "Int", 3, "Int", 0, "Int", 3, "Int", 0, "Int", 0)
  IfLess,hFil,1, Return,hFil
  hMod := DllCall("LoadLibrary", "Str", "ntdll.dll"), CRC32 := 0
  , DllCall("GetFileSizeEx", "UInt",hFil, "UInt",&Buffer), fSz := NumGet(Buffer, 0,"Int64")
  Loop % ( fSz//cSz + !!Mod( fSz,cSz ) )
    DllCall("ReadFile", "UInt", hFil, "UInt", &Buffer, "UInt", cSz, "UIntP",Bytes, "UInt",0)
    , CRC32 := DllCall("NTDLL\RtlComputeCrc32", "UInt", CRC32, "UInt", &Buffer, "UInt", Bytes, "UInt")
  DllCall("CloseHandle", "UInt", hFil)
  SetFormat, Integer, % SubStr((AFI := A_FormatInteger) "H", 0)
  CRC32 := SubStr(CRC32 + 0x1000000000, -7), DllCall("CharUpper", "Str", CRC32)
  SetFormat, Integer, %AFI%
  Return CRC32, DllCall("FreeLibrary", "UInt", hMod)
}

MD5_File(sFile="", cSz=4) { ; www.autohotkey.com/forum/viewtopic.php?p=275910#275910
  cSz := (cSz<0||cSz>8) ? 2**22 : 2**(18+cSz), VarSetCapacity(Buffer, cSz, 0)
  hFil := DllCall("CreateFile", "Str", sFile, "UInt", 0x80000000, "Int", 1,"Int", 0,"Int", 3,"Int", 0,"Int", 0)
  IfLess,hFil,1, Return,hFil
  DllCall("GetFileSizeEx", "UInt", hFil, "Str", Buffer), fSz := NumGet(Buffer, 0, "Int64")
  VarSetCapacity(MD5_CTX, 104, 0), DllCall("advapi32\MD5Init", "Str", MD5_CTX)
    LoopNum := fSz//cSz
  Loop % (LoopNum +!!Mod(fSz,cSz))
  {
    if (LoopNum > 125)
      ToolTip % (A_index * cSz *100) / fSz "%"
    DllCall("ReadFile", "UInt", hFil, "Str", Buffer, "UInt", cSz, "UIntP", bytesRead, "UInt", 0)
    , DllCall("advapi32\MD5Update", "Str", MD5_CTX, "Str", Buffer, "UInt", bytesRead)
  }
  if (LoopNum > 125)
    ToolTip
  DllCall("advapi32\MD5Final", "Str", MD5_CTX), DllCall("CloseHandle", "UInt", hFil)
  Loop % StrLen(Hex:="123456789ABCDEF0")
    N := NumGet(MD5_CTX, 87+A_Index, "Char"), MD5 .= SubStr(Hex,N>>4,1) . SubStr(Hex,N&15,1)
  Return MD5
}

MD5(ByRef V, L=0) { ; www.autohotkey.com/forum/viewtopic.php?p=275910#275910
  VarSetCapacity( MD5_CTX,104,0 ), DllCall( "advapi32\MD5Init", "Str",MD5_CTX )
  DllCall("advapi32\MD5Update", "Str", MD5_CTX, "Str", V, "UInt", L ? L : VarSetCapacity(V) )
  DllCall("advapi32\MD5Final", "Str", MD5_CTX )
  Loop % StrLen(Hex:="123456789ABCDEF0")
    N := NumGet(MD5_CTX,87+A_Index, "Char"), MD5 .= SubStr(Hex,N>>4,1) . SubStr(Hex,N&15,1)
  Return MD5
}

 

Hash哈希检验.ahk

Plain text
复制到剪贴板
Open code in new window
EnlighterJS 3 Syntax Highlighter
MsgBox % Hash("", A_AhkPath) ; 默认SHA256哈希格式为十六进制(默认为大写)
MsgBox % Hash("Upper:0", A_AhkPath) ; 与上面相同,但哈希将使用小写形式
MsgBox % Hash("Base64:1", A_AhkPath) ; 默认SHA256哈希为Base64文本
MsgBox % Hash("alg:SHA512 Upper:0", A_AhkPath) ; SHA512哈希格式为十六进制(小写)
MsgBox % Hash("alg:SHA512 Base64:1", A_AhkPath) ; 格式化为Base64文本的SHA512哈希
Hash(Options, ByRef Var, nBytes:="") { ; Hash() v0.37 by SKAN on D444/D445 @ tiny.cc/hashit
Local
HA := {"ALG":"SHA256","BAS":0, "UPP":1, "ENC":"UTF-8"}
Loop, Parse, % Format("{:U}", Options), %A_Space%, +
A := StrSplit(A_LoopField, ":", "+"), HA[ SubStr(A[1], 1, 3) ] := A[2]
HA.X := ( HA.ENC="UTF-16" ? 2 : 1)
OK1 := { "SHA1":1, "SHA256":1, "SHA384":1, "SHA512":1, "MD2":1, "MD4":1, "MD5":1 }[ HA.ALG ]
OK2 := { "CP0":1, "UTF-8":1, "UTF-16":1}[ HA.ENC ]
NaN := ( StrLen(nBytes) And (nBytes != Round(nBytes)) ), lVar := StrLen(Var)
pNum := ( lVar And [var].GetCapacity(1)="" And (Var = Abs(Round(Var))) ), nVar := VarSetCapacity(Var)
If ( OK1="" Or OK2="" Or NaN=1 Or lVar<1 Or (pNum=1 And nBytes<1) Or (pNum=0 And nVar<nBytes))
Return ( 0, ErrorLevel := OK1="" ? "Algorithm not known.`n=> MD2 MD4 MD5 SHA1 SHA256 SHA384 SHA512`nDefault: SHA256"
: OK2="" ? "Codepage incorrect.`n=> CP0 UTF-16 UTF-8`nDefault: UTF-8"
: NaN=1 ? "nBytes in incorrect format"
: lVar<1 ? "Var is empty. Nothing to hash."
: (pNum=1 And nBytes<1) ? "Pointer requires nBytes greater than 0."
: (pNum=0 And nVar<nBytes) ? "Var's capacity is lesser than nBytes." : "" )
hBcrypt := DllCall("Kernel32.dll\LoadLibrary", "Str","Bcrypt.dll", "Ptr")
DllCall("Bcrypt.dll\BCryptOpenAlgorithmProvider", "PtrP",hAlg:=0, "WStr",HA.ALG, "Ptr",0, "Int",0, "UInt")
DllCall("Bcrypt.dll\BCryptCreateHash", "Ptr",hAlg, "PtrP",hHash:=0, "Ptr", 0, "Int", 0, "Ptr",0, "Int",0, "Int", 0)
nLen := 0, FileLen := File := rBytes := sStr := nErr := ""
If ( nBytes!="" And (pBuf:=pNum ? Var+0 : &Var) ) {
If ( nBytes<=0 )
nBytes := StrPut(Var, HA.ENC)
, VarSetCapacity(sStr, nBytes * HA.X)
, nBytes := ( StrPut(Var, pBuf := &sStr, nBytes, HA.ENC) - 1 ) * HA.X
nErr := DllCall("Bcrypt.dll\BCryptHashData", "Ptr",hHash, "Ptr",pBuf, "Int",nBytes, "Int", 0, "UInt")
} Else {
File := FileOpen(Var, "r -rwd")
If ( (FileLen := File.Length) And VarSetCapacity(Bin, 65536) )
Loop
If ( rBytes := File.RawRead(&Bin, 65536) )
nErr := DllCall("Bcrypt.dll\BCryptHashData", "Ptr",hHash, "Ptr",&Bin, "Int",rBytes, "Int", 0, "Uint")
Until ( nErr Or File.AtEOF Or !rBytes )
File := ( FileLen="" ? 0 : File.Close() )
}
DllCall("Bcrypt.dll\BCryptGetProperty", "Ptr",hAlg, "WStr", "HashDigestLength", "UIntP",nLen, "Int",4, "PtrP",0, "Int",0)
VarSetCapacity(Hash, nLen)
DllCall("Bcrypt.dll\BCryptFinishHash", "Ptr",hHash, "Ptr",&Hash, "Int",nLen, "Int", 0)
DllCall("Bcrypt.dll\BCryptDestroyHash", "Ptr",hHash)
DllCall("Bcrypt.dll\BCryptCloseAlgorithmProvider", "Ptr",hAlg, "Int",0)
DllCall("Kernel32.dll\FreeLibrary", "Ptr",hBCrypt)
If ( nErr=0 )
VarSetCapacity(sStr, 260, 0), nFlags := HA.BAS ? 0x40000001 : 0x4000000C
, DllCall("Crypt32\CryptBinaryToString", "Ptr",&Hash, "Int",nLen, "Int",nFlags, "Str",sStr, "UIntP",130)
, sStr := ( nFlags=0x4000000C And HA.UPP ? Format("{:U}", sStr) : sStr )
Return ( sStr, ErrorLevel := File=0 ? ( FileExist(Var) ? "Open file error. File in use." : "File does not exist." )
: FileLen=0 ? "Zero byte file. Nothing to hash."
: (FileLen & rBytes=0) ? "Read file error."
: nErr ? Format("Bcrypt error. 0x{:08X}", nErr)
: nErr="" ? "Unknown error." : "" )
}
MsgBox % Hash("", A_AhkPath) ; 默认SHA256哈希格式为十六进制(默认为大写) MsgBox % Hash("Upper:0", A_AhkPath) ; 与上面相同,但哈希将使用小写形式 MsgBox % Hash("Base64:1", A_AhkPath) ; 默认SHA256哈希为Base64文本 MsgBox % Hash("alg:SHA512 Upper:0", A_AhkPath) ; SHA512哈希格式为十六进制(小写) MsgBox % Hash("alg:SHA512 Base64:1", A_AhkPath) ; 格式化为Base64文本的SHA512哈希 Hash(Options, ByRef Var, nBytes:="") { ; Hash() v0.37 by SKAN on D444/D445 @ tiny.cc/hashit Local HA := {"ALG":"SHA256","BAS":0, "UPP":1, "ENC":"UTF-8"} Loop, Parse, % Format("{:U}", Options), %A_Space%, + A := StrSplit(A_LoopField, ":", "+"), HA[ SubStr(A[1], 1, 3) ] := A[2] HA.X := ( HA.ENC="UTF-16" ? 2 : 1) OK1 := { "SHA1":1, "SHA256":1, "SHA384":1, "SHA512":1, "MD2":1, "MD4":1, "MD5":1 }[ HA.ALG ] OK2 := { "CP0":1, "UTF-8":1, "UTF-16":1}[ HA.ENC ] NaN := ( StrLen(nBytes) And (nBytes != Round(nBytes)) ), lVar := StrLen(Var) pNum := ( lVar And [var].GetCapacity(1)="" And (Var = Abs(Round(Var))) ), nVar := VarSetCapacity(Var) If ( OK1="" Or OK2="" Or NaN=1 Or lVar<1 Or (pNum=1 And nBytes<1) Or (pNum=0 And nVar<nBytes)) Return ( 0, ErrorLevel := OK1="" ? "Algorithm not known.`n=> MD2 MD4 MD5 SHA1 SHA256 SHA384 SHA512`nDefault: SHA256" : OK2="" ? "Codepage incorrect.`n=> CP0 UTF-16 UTF-8`nDefault: UTF-8" : NaN=1 ? "nBytes in incorrect format" : lVar<1 ? "Var is empty. Nothing to hash." : (pNum=1 And nBytes<1) ? "Pointer requires nBytes greater than 0." : (pNum=0 And nVar<nBytes) ? "Var's capacity is lesser than nBytes." : "" ) hBcrypt := DllCall("Kernel32.dll\LoadLibrary", "Str","Bcrypt.dll", "Ptr") DllCall("Bcrypt.dll\BCryptOpenAlgorithmProvider", "PtrP",hAlg:=0, "WStr",HA.ALG, "Ptr",0, "Int",0, "UInt") DllCall("Bcrypt.dll\BCryptCreateHash", "Ptr",hAlg, "PtrP",hHash:=0, "Ptr", 0, "Int", 0, "Ptr",0, "Int",0, "Int", 0) nLen := 0, FileLen := File := rBytes := sStr := nErr := "" If ( nBytes!="" And (pBuf:=pNum ? Var+0 : &Var) ) { If ( nBytes<=0 ) nBytes := StrPut(Var, HA.ENC) , VarSetCapacity(sStr, nBytes * HA.X) , nBytes := ( StrPut(Var, pBuf := &sStr, nBytes, HA.ENC) - 1 ) * HA.X nErr := DllCall("Bcrypt.dll\BCryptHashData", "Ptr",hHash, "Ptr",pBuf, "Int",nBytes, "Int", 0, "UInt") } Else { File := FileOpen(Var, "r -rwd") If ( (FileLen := File.Length) And VarSetCapacity(Bin, 65536) ) Loop If ( rBytes := File.RawRead(&Bin, 65536) ) nErr := DllCall("Bcrypt.dll\BCryptHashData", "Ptr",hHash, "Ptr",&Bin, "Int",rBytes, "Int", 0, "Uint") Until ( nErr Or File.AtEOF Or !rBytes ) File := ( FileLen="" ? 0 : File.Close() ) } DllCall("Bcrypt.dll\BCryptGetProperty", "Ptr",hAlg, "WStr", "HashDigestLength", "UIntP",nLen, "Int",4, "PtrP",0, "Int",0) VarSetCapacity(Hash, nLen) DllCall("Bcrypt.dll\BCryptFinishHash", "Ptr",hHash, "Ptr",&Hash, "Int",nLen, "Int", 0) DllCall("Bcrypt.dll\BCryptDestroyHash", "Ptr",hHash) DllCall("Bcrypt.dll\BCryptCloseAlgorithmProvider", "Ptr",hAlg, "Int",0) DllCall("Kernel32.dll\FreeLibrary", "Ptr",hBCrypt) If ( nErr=0 ) VarSetCapacity(sStr, 260, 0), nFlags := HA.BAS ? 0x40000001 : 0x4000000C , DllCall("Crypt32\CryptBinaryToString", "Ptr",&Hash, "Int",nLen, "Int",nFlags, "Str",sStr, "UIntP",130) , sStr := ( nFlags=0x4000000C And HA.UPP ? Format("{:U}", sStr) : sStr ) Return ( sStr, ErrorLevel := File=0 ? ( FileExist(Var) ? "Open file error. File in use." : "File does not exist." ) : FileLen=0 ? "Zero byte file. Nothing to hash." : (FileLen & rBytes=0) ? "Read file error." : nErr ? Format("Bcrypt error. 0x{:08X}", nErr) : nErr="" ? "Unknown error." : "" ) }
MsgBox % Hash("", A_AhkPath)                        ; 默认SHA256哈希格式为十六进制(默认为大写)
MsgBox % Hash("Upper:0",  A_AhkPath)                ; 与上面相同,但哈希将使用小写形式
MsgBox % Hash("Base64:1", A_AhkPath)                ; 默认SHA256哈希为Base64文本
MsgBox % Hash("alg:SHA512 Upper:0",   A_AhkPath)    ; SHA512哈希格式为十六进制(小写)
MsgBox % Hash("alg:SHA512 Base64:1",  A_AhkPath)    ; 格式化为Base64文本的SHA512哈希

Hash(Options, ByRef Var, nBytes:="") {  ; Hash() v0.37 by SKAN on D444/D445 @ tiny.cc/hashit
  Local
  HA := {"ALG":"SHA256","BAS":0, "UPP":1, "ENC":"UTF-8"}
  Loop, Parse, % Format("{:U}", Options), %A_Space%, +
    A := StrSplit(A_LoopField, ":", "+"), HA[ SubStr(A[1], 1, 3) ] := A[2]

  HA.X := ( HA.ENC="UTF-16" ? 2 : 1)
  OK1  := { "SHA1":1, "SHA256":1, "SHA384":1, "SHA512":1, "MD2":1, "MD4":1, "MD5":1 }[ HA.ALG ]
  OK2  := { "CP0":1, "UTF-8":1, "UTF-16":1}[ HA.ENC ]
  NaN  := ( StrLen(nBytes) And (nBytes != Round(nBytes)) ),                    lVar := StrLen(Var)
  pNum := ( lVar And [var].GetCapacity(1)="" And (Var = Abs(Round(Var))) ),    nVar := VarSetCapacity(Var)

  If ( OK1="" Or OK2="" Or NaN=1 Or lVar<1 Or (pNum=1 And nBytes<1) Or (pNum=0 And nVar<nBytes))
     Return ( 0, ErrorLevel := OK1="" ? "Algorithm not known.`n=> MD2 MD4 MD5 SHA1 SHA256 SHA384 SHA512`nDefault: SHA256"
                            :  OK2="" ? "Codepage incorrect.`n=> CP0 UTF-16 UTF-8`nDefault: UTF-8"
                            :  NaN=1  ? "nBytes in incorrect format"
                            :  lVar<1 ? "Var is empty. Nothing to hash."
              : (pNum=1 And nBytes<1) ? "Pointer requires nBytes greater than 0."
           : (pNum=0 And nVar<nBytes) ? "Var's capacity is lesser than nBytes." : "" )

  hBcrypt := DllCall("Kernel32.dll\LoadLibrary", "Str","Bcrypt.dll", "Ptr")
  DllCall("Bcrypt.dll\BCryptOpenAlgorithmProvider", "PtrP",hAlg:=0, "WStr",HA.ALG, "Ptr",0, "Int",0, "UInt")
  DllCall("Bcrypt.dll\BCryptCreateHash", "Ptr",hAlg, "PtrP",hHash:=0, "Ptr", 0, "Int", 0, "Ptr",0, "Int",0, "Int", 0)

  nLen := 0, FileLen := File := rBytes := sStr := nErr := ""
  If ( nBytes!="" And (pBuf:=pNum ? Var+0 : &Var) ) {
    If ( nBytes<=0  )
         nBytes := StrPut(Var, HA.ENC)
       , VarSetCapacity(sStr, nBytes * HA.X)
       , nBytes := ( StrPut(Var, pBuf := &sStr, nBytes, HA.ENC) - 1 ) * HA.X
    nErr := DllCall("Bcrypt.dll\BCryptHashData", "Ptr",hHash, "Ptr",pBuf, "Int",nBytes, "Int", 0, "UInt")
  } Else {
    File := FileOpen(Var, "r -rwd")
    If  ( (FileLen := File.Length) And VarSetCapacity(Bin, 65536) )
      Loop
        If ( rBytes := File.RawRead(&Bin, 65536) )
          nErr   := DllCall("Bcrypt.dll\BCryptHashData", "Ptr",hHash, "Ptr",&Bin, "Int",rBytes, "Int", 0, "Uint")
        Until ( nErr Or File.AtEOF Or !rBytes )
    File := ( FileLen="" ? 0 : File.Close() )
  }

  DllCall("Bcrypt.dll\BCryptGetProperty", "Ptr",hAlg, "WStr", "HashDigestLength", "UIntP",nLen, "Int",4, "PtrP",0, "Int",0)
  VarSetCapacity(Hash, nLen)
  DllCall("Bcrypt.dll\BCryptFinishHash", "Ptr",hHash, "Ptr",&Hash, "Int",nLen, "Int", 0)
  DllCall("Bcrypt.dll\BCryptDestroyHash", "Ptr",hHash)
  DllCall("Bcrypt.dll\BCryptCloseAlgorithmProvider", "Ptr",hAlg, "Int",0)
  DllCall("Kernel32.dll\FreeLibrary", "Ptr",hBCrypt)

  If ( nErr=0 )
     VarSetCapacity(sStr, 260, 0),  nFlags := HA.BAS ? 0x40000001 : 0x4000000C
   , DllCall("Crypt32\CryptBinaryToString", "Ptr",&Hash, "Int",nLen, "Int",nFlags, "Str",sStr, "UIntP",130)
   , sStr := ( nFlags=0x4000000C And HA.UPP ? Format("{:U}", sStr) : sStr )

  Return ( sStr, ErrorLevel := File=0    ? ( FileExist(Var) ? "Open file error. File in use." : "File does not exist." )
                           : FileLen=0 ? "Zero byte file. Nothing to hash."
                : (FileLen & rBytes=0) ? "Read file error."
                                : nErr ? Format("Bcrypt error. 0x{:08X}", nErr)
                             : nErr="" ? "Unknown error." : "" )
}

 

字符串哈希值校验算法 - 单函数实现

MD5.ahk

Plain text
复制到剪贴板
Open code in new window
EnlighterJS 3 Syntax Highlighter
; MD5算法是一种广泛使用的散列函数,产生128位散列值
MsgBox % MD5("Hello World") "`n"
. MD5("Hello World", 1)
MD5(string, case := 0) {
static MD5_DIGEST_LENGTH := 16
hModule := DllCall("LoadLibrary", "Str", "advapi32.dll", "Ptr")
, VarSetCapacity(MD5_CTX, 104, 0), DllCall("advapi32\MD5Init", "Ptr", &MD5_CTX)
, DllCall("advapi32\MD5Update", "Ptr", &MD5_CTX, "AStr", string, "UInt", StrLen(string))
, DllCall("advapi32\MD5Final", "Ptr", &MD5_CTX)
loop % MD5_DIGEST_LENGTH
o .= Format("{:02" (case ? "X" : "x") "}", NumGet(MD5_CTX, 87 + A_Index, "UChar"))
return o, DllCall("FreeLibrary", "Ptr", hModule)
}
; MD5算法是一种广泛使用的散列函数,产生128位散列值 MsgBox % MD5("Hello World") "`n" . MD5("Hello World", 1) MD5(string, case := 0) { static MD5_DIGEST_LENGTH := 16 hModule := DllCall("LoadLibrary", "Str", "advapi32.dll", "Ptr") , VarSetCapacity(MD5_CTX, 104, 0), DllCall("advapi32\MD5Init", "Ptr", &MD5_CTX) , DllCall("advapi32\MD5Update", "Ptr", &MD5_CTX, "AStr", string, "UInt", StrLen(string)) , DllCall("advapi32\MD5Final", "Ptr", &MD5_CTX) loop % MD5_DIGEST_LENGTH o .= Format("{:02" (case ? "X" : "x") "}", NumGet(MD5_CTX, 87 + A_Index, "UChar")) return o, DllCall("FreeLibrary", "Ptr", hModule) }
; MD5算法是一种广泛使用的散列函数,产生128位散列值
MsgBox % MD5("Hello World") "`n"
     . MD5("Hello World", 1)

MD5(string, case := 0) {
  static MD5_DIGEST_LENGTH := 16
  hModule := DllCall("LoadLibrary", "Str", "advapi32.dll", "Ptr")
  , VarSetCapacity(MD5_CTX, 104, 0), DllCall("advapi32\MD5Init", "Ptr", &MD5_CTX)
  , DllCall("advapi32\MD5Update", "Ptr", &MD5_CTX, "AStr", string, "UInt", StrLen(string))
  , DllCall("advapi32\MD5Final", "Ptr", &MD5_CTX)
  loop % MD5_DIGEST_LENGTH
    o .= Format("{:02" (case ? "X" : "x") "}", NumGet(MD5_CTX, 87 + A_Index, "UChar"))
  return o, DllCall("FreeLibrary", "Ptr", hModule)
}

 

CRC32.ahk

Plain text
复制到剪贴板
Open code in new window
EnlighterJS 3 Syntax Highlighter
; CRC32在AutoHotkey中的实现
CRC32(str) {
static table := []
loop 256 {
crc := A_Index - 1
loop 8
crc := (crc & 1) ? (crc >> 1) ^ 0xEDB88320 : (crc >> 1)
table[A_Index - 1] := crc
}
crc := ~0
loop, parse, str
crc := table[(crc & 0xFF) ^ Asc(A_LoopField)] ^ (crc >> 8)
return Format("{:#x}", ~crc)
}
MsgBox % CRC32("The quick brown fox jumps over the lazy dog") ; -> 0x414fa339
; CRC32通过DllCall(WinAPI)
CRC32WinAPI(str, enc = "UTF-8") {
l := (enc = "CP1200" || enc = "UTF-16") ? 2 : 1, s := (StrPut(str, enc) - 1) * l
VarSetCapacity(b, s, 0) && StrPut(str, &b, floor(s / l), enc)
CRC32 := DllCall("ntdll.dll\RtlComputeCrc32", "UInt", 0, "Ptr", &b, "UInt", s)
return Format("{:#x}", CRC32)
}
MsgBox % CRC32WinAPI("The quick brown fox jumps over the lazy dog") ; -> 0x414fa339
; CRC32文件通过DllCall(WinAPI)
CRC32_File(filename) {
if !(f := FileOpen(filename, "r", "UTF-8"))
throw Exception("Failed to open file: " filename, -1)
f.Seek(0)
while (dataread := f.RawRead(data, 262144))
crc := DllCall("ntdll.dll\RtlComputeCrc32", "uint", crc, "ptr", &data, "uint", dataread, "uint")
f.Close()
return Format("{:#x}", crc)
}
MsgBox % CRC32_File(A_AhkPath)
; CRC32在AutoHotkey中的实现 CRC32(str) { static table := [] loop 256 { crc := A_Index - 1 loop 8 crc := (crc & 1) ? (crc >> 1) ^ 0xEDB88320 : (crc >> 1) table[A_Index - 1] := crc } crc := ~0 loop, parse, str crc := table[(crc & 0xFF) ^ Asc(A_LoopField)] ^ (crc >> 8) return Format("{:#x}", ~crc) } MsgBox % CRC32("The quick brown fox jumps over the lazy dog") ; -> 0x414fa339 ; CRC32通过DllCall(WinAPI) CRC32WinAPI(str, enc = "UTF-8") { l := (enc = "CP1200" || enc = "UTF-16") ? 2 : 1, s := (StrPut(str, enc) - 1) * l VarSetCapacity(b, s, 0) && StrPut(str, &b, floor(s / l), enc) CRC32 := DllCall("ntdll.dll\RtlComputeCrc32", "UInt", 0, "Ptr", &b, "UInt", s) return Format("{:#x}", CRC32) } MsgBox % CRC32WinAPI("The quick brown fox jumps over the lazy dog") ; -> 0x414fa339 ; CRC32文件通过DllCall(WinAPI) CRC32_File(filename) { if !(f := FileOpen(filename, "r", "UTF-8")) throw Exception("Failed to open file: " filename, -1) f.Seek(0) while (dataread := f.RawRead(data, 262144)) crc := DllCall("ntdll.dll\RtlComputeCrc32", "uint", crc, "ptr", &data, "uint", dataread, "uint") f.Close() return Format("{:#x}", crc) } MsgBox % CRC32_File(A_AhkPath)
; CRC32在AutoHotkey中的实现
CRC32(str) {
  static table := []
  loop 256 {
    crc := A_Index - 1
    loop 8
      crc := (crc & 1) ? (crc >> 1) ^ 0xEDB88320 : (crc >> 1)
    table[A_Index - 1] := crc
  }
  crc := ~0
  loop, parse, str
    crc := table[(crc & 0xFF) ^ Asc(A_LoopField)] ^ (crc >> 8)
  return Format("{:#x}", ~crc)
}

MsgBox % CRC32("The quick brown fox jumps over the lazy dog")  ; -> 0x414fa339


; CRC32通过DllCall(WinAPI)
CRC32WinAPI(str, enc = "UTF-8") {
  l := (enc = "CP1200" || enc = "UTF-16") ? 2 : 1, s := (StrPut(str, enc) - 1) * l
  VarSetCapacity(b, s, 0) && StrPut(str, &b, floor(s / l), enc)
  CRC32 := DllCall("ntdll.dll\RtlComputeCrc32", "UInt", 0, "Ptr", &b, "UInt", s)
  return Format("{:#x}", CRC32)
}

MsgBox % CRC32WinAPI("The quick brown fox jumps over the lazy dog")  ; -> 0x414fa339


; CRC32文件通过DllCall(WinAPI)
CRC32_File(filename) {
  if !(f := FileOpen(filename, "r", "UTF-8"))
    throw Exception("Failed to open file: " filename, -1)
  f.Seek(0)
  while (dataread := f.RawRead(data, 262144))
    crc := DllCall("ntdll.dll\RtlComputeCrc32", "uint", crc, "ptr", &data, "uint", dataread, "uint")
  f.Close()
  return Format("{:#x}", crc)
}

MsgBox % CRC32_File(A_AhkPath)

 

SHA1.ahk

Plain text
复制到剪贴板
Open code in new window
EnlighterJS 3 Syntax Highlighter
; 在密码学中,SHA-1(安全哈希算法1)是一种加密哈希函数
MsgBox % SHA("Hello World") "`n"
. SHA("Hello World", 1)
SHA(string, case := 0) {
static SHA_DIGEST_LENGTH := 20
hModule := DllCall("LoadLibrary", "Str", "advapi32.dll", "Ptr")
, VarSetCapacity(SHA_CTX, 136, 0), DllCall("advapi32\A_SHAInit", "Ptr", &SHA_CTX)
, DllCall("advapi32\A_SHAUpdate", "Ptr", &SHA_CTX, "AStr", string, "UInt", StrLen(string))
, DllCall("advapi32\A_SHAFinal", "Ptr", &SHA_CTX, "UInt", &SHA_CTX + 116)
loop % SHA_DIGEST_LENGTH
o .= Format("{:02" (case ? "X" : "x") "}", NumGet(SHA_CTX, 115 + A_Index, "UChar"))
return o, DllCall("FreeLibrary", "Ptr", hModule)
}
; 在密码学中,SHA-1(安全哈希算法1)是一种加密哈希函数 MsgBox % SHA("Hello World") "`n" . SHA("Hello World", 1) SHA(string, case := 0) { static SHA_DIGEST_LENGTH := 20 hModule := DllCall("LoadLibrary", "Str", "advapi32.dll", "Ptr") , VarSetCapacity(SHA_CTX, 136, 0), DllCall("advapi32\A_SHAInit", "Ptr", &SHA_CTX) , DllCall("advapi32\A_SHAUpdate", "Ptr", &SHA_CTX, "AStr", string, "UInt", StrLen(string)) , DllCall("advapi32\A_SHAFinal", "Ptr", &SHA_CTX, "UInt", &SHA_CTX + 116) loop % SHA_DIGEST_LENGTH o .= Format("{:02" (case ? "X" : "x") "}", NumGet(SHA_CTX, 115 + A_Index, "UChar")) return o, DllCall("FreeLibrary", "Ptr", hModule) }
; 在密码学中,SHA-1(安全哈希算法1)是一种加密哈希函数

MsgBox % SHA("Hello World") "`n"
       . SHA("Hello World", 1)

SHA(string, case := 0) {
  static SHA_DIGEST_LENGTH := 20
  hModule := DllCall("LoadLibrary", "Str", "advapi32.dll", "Ptr")
  , VarSetCapacity(SHA_CTX, 136, 0), DllCall("advapi32\A_SHAInit", "Ptr", &SHA_CTX)
  , DllCall("advapi32\A_SHAUpdate", "Ptr", &SHA_CTX, "AStr", string, "UInt", StrLen(string))
  , DllCall("advapi32\A_SHAFinal", "Ptr", &SHA_CTX, "UInt", &SHA_CTX + 116)
  loop % SHA_DIGEST_LENGTH
    o .= Format("{:02" (case ? "X" : "x") "}", NumGet(SHA_CTX, 115 + A_Index, "UChar"))
  return o, DllCall("FreeLibrary", "Ptr", hModule)
}

 

MD4.ahk

Plain text
复制到剪贴板
Open code in new window
EnlighterJS 3 Syntax Highlighter
; MD4消息摘要算法是一个加密散列函数
MsgBox % MD4("Hello World") "`n"
. MD4("Hello World", 1)
MD4(string, case := 0) {
static MD4_DIGEST_LENGTH := 16
hModule := DllCall("LoadLibrary", "Str", "advapi32.dll", "Ptr")
, VarSetCapacity(MD4_CTX, 104, 0), DllCall("advapi32\MD4Init", "Ptr", &MD4_CTX)
, DllCall("advapi32\MD4Update", "Ptr", &MD4_CTX, "AStr", string, "UInt", StrLen(string))
, DllCall("advapi32\MD4Final", "Ptr", &MD4_CTX)
loop % MD4_DIGEST_LENGTH
o .= Format("{:02" (case ? "X" : "x") "}", NumGet(MD4_CTX, 87 + A_Index, "UChar"))
return o, DllCall("FreeLibrary", "Ptr", hModule)
}
; MD4消息摘要算法是一个加密散列函数 MsgBox % MD4("Hello World") "`n" . MD4("Hello World", 1) MD4(string, case := 0) { static MD4_DIGEST_LENGTH := 16 hModule := DllCall("LoadLibrary", "Str", "advapi32.dll", "Ptr") , VarSetCapacity(MD4_CTX, 104, 0), DllCall("advapi32\MD4Init", "Ptr", &MD4_CTX) , DllCall("advapi32\MD4Update", "Ptr", &MD4_CTX, "AStr", string, "UInt", StrLen(string)) , DllCall("advapi32\MD4Final", "Ptr", &MD4_CTX) loop % MD4_DIGEST_LENGTH o .= Format("{:02" (case ? "X" : "x") "}", NumGet(MD4_CTX, 87 + A_Index, "UChar")) return o, DllCall("FreeLibrary", "Ptr", hModule) }
; MD4消息摘要算法是一个加密散列函数

MsgBox % MD4("Hello World") "`n"
       . MD4("Hello World", 1)

MD4(string, case := 0) {
  static MD4_DIGEST_LENGTH := 16
  hModule := DllCall("LoadLibrary", "Str", "advapi32.dll", "Ptr")
  , VarSetCapacity(MD4_CTX, 104, 0), DllCall("advapi32\MD4Init", "Ptr", &MD4_CTX)
  , DllCall("advapi32\MD4Update", "Ptr", &MD4_CTX, "AStr", string, "UInt", StrLen(string))
  , DllCall("advapi32\MD4Final", "Ptr", &MD4_CTX)
  loop % MD4_DIGEST_LENGTH
    o .= Format("{:02" (case ? "X" : "x") "}", NumGet(MD4_CTX, 87 + A_Index, "UChar"))
  return o, DllCall("FreeLibrary", "Ptr", hModule)
}

 

Adler32.ahk

Plain text
复制到剪贴板
Open code in new window
EnlighterJS 3 Syntax Highlighter
; Adler-32是一种校验和算法
MsgBox % Adler32("Hello World") ; <== 0x180b041d
MsgBox % Adler32("The quick brown fox jumps over the lazy dog") ; <== 0x5bdc0fda
Adler32(str) {
a := 1, b := 0
loop, parse, str
b := Mod(b + (a := Mod(a + Asc(A_LoopField), 0xFFF1)), 0xFFF1)
return Format("{:#x}", (b << 16) | a)
}
; Adler-32是一种校验和算法 MsgBox % Adler32("Hello World") ; <== 0x180b041d MsgBox % Adler32("The quick brown fox jumps over the lazy dog") ; <== 0x5bdc0fda Adler32(str) { a := 1, b := 0 loop, parse, str b := Mod(b + (a := Mod(a + Asc(A_LoopField), 0xFFF1)), 0xFFF1) return Format("{:#x}", (b << 16) | a) }
; Adler-32是一种校验和算法

MsgBox % Adler32("Hello World")                                 ; <== 0x180b041d
MsgBox % Adler32("The quick brown fox jumps over the lazy dog") ; <== 0x5bdc0fda

Adler32(str) {
  a := 1, b := 0
  loop, parse, str
    b := Mod(b + (a := Mod(a + Asc(A_LoopField), 0xFFF1)), 0xFFF1)
  return Format("{:#x}", (b << 16) | a)
}

 

综合的哈希值校验算法实现类库

Plain text
复制到剪贴板
Open code in new window
EnlighterJS 3 Syntax Highlighter
; AES 的密码长度必须为 128位、192位、256位 也就是 16字节、24字节、32字节 中的一个,并且 IV 长度也要对应,否则将报错。
; 从字符串创建 SHA-1 哈希值
MsgBox % Crypt.Hash.String("SHA1", "The quick brown fox jumps over the lazy dog")
; -> 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12
; 使用HMAC从字符串创建SHA-256哈希
MsgBox % Crypt.Hash.HMAC("SHA256", "The quick brown fox jumps over the lazy dog", "Secret Salt")
; -> 68dba4b3a6d5c36b6e3567e1a925fe87c7386162e8fb6e2e9f17ade4aa7dc262
; 从文件创建SHA-256哈希
MsgBox % Crypt.Hash.File("SHA256", "C:\Program Files\AutoHotkey\AutoHotkey.exe")
; -> 0a9964fe0e0fb3f0679df317a65f9945c474dab8c4370b45b93da64a8b201b9f
; 使用SHA-1创建PBKDF2哈希,1500次迭代,从字符串中创建密钥大小为192
MsgBox % Crypt.Hash.PBKDF2("SHA1", "The quick brown fox jumps over the lazy dog", "Secret Salt", 1500, 192)
; -> 531c1bbae7c3de019d1f53adcac7d85bf2b04caba9d6d6d1
; 更多示例详见:https://www.autohotkey.com/boards/viewtopic.php?p=109958#p109958
; ==============================================================================================
; 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"
}
}
; AES 的密码长度必须为 128位、192位、256位 也就是 16字节、24字节、32字节 中的一个,并且 IV 长度也要对应,否则将报错。 ; 从字符串创建 SHA-1 哈希值 MsgBox % Crypt.Hash.String("SHA1", "The quick brown fox jumps over the lazy dog") ; -> 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12 ; 使用HMAC从字符串创建SHA-256哈希 MsgBox % Crypt.Hash.HMAC("SHA256", "The quick brown fox jumps over the lazy dog", "Secret Salt") ; -> 68dba4b3a6d5c36b6e3567e1a925fe87c7386162e8fb6e2e9f17ade4aa7dc262 ; 从文件创建SHA-256哈希 MsgBox % Crypt.Hash.File("SHA256", "C:\Program Files\AutoHotkey\AutoHotkey.exe") ; -> 0a9964fe0e0fb3f0679df317a65f9945c474dab8c4370b45b93da64a8b201b9f ; 使用SHA-1创建PBKDF2哈希,1500次迭代,从字符串中创建密钥大小为192 MsgBox % Crypt.Hash.PBKDF2("SHA1", "The quick brown fox jumps over the lazy dog", "Secret Salt", 1500, 192) ; -> 531c1bbae7c3de019d1f53adcac7d85bf2b04caba9d6d6d1 ; 更多示例详见:https://www.autohotkey.com/boards/viewtopic.php?p=109958#p109958 ; ============================================================================================== ; 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" } }
; AES 的密码长度必须为 128位、192位、256位 也就是 16字节、24字节、32字节 中的一个,并且 IV 长度也要对应,否则将报错。

; 从字符串创建 SHA-1 哈希值
MsgBox % Crypt.Hash.String("SHA1", "The quick brown fox jumps over the lazy dog")
; -> 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12

; 使用HMAC从字符串创建SHA-256哈希
MsgBox % Crypt.Hash.HMAC("SHA256", "The quick brown fox jumps over the lazy dog", "Secret Salt")
; -> 68dba4b3a6d5c36b6e3567e1a925fe87c7386162e8fb6e2e9f17ade4aa7dc262

; 从文件创建SHA-256哈希
MsgBox % Crypt.Hash.File("SHA256", "C:\Program Files\AutoHotkey\AutoHotkey.exe")
; -> 0a9964fe0e0fb3f0679df317a65f9945c474dab8c4370b45b93da64a8b201b9f

; 使用SHA-1创建PBKDF2哈希,1500次迭代,从字符串中创建密钥大小为192
MsgBox % Crypt.Hash.PBKDF2("SHA1", "The quick brown fox jumps over the lazy dog", "Secret Salt", 1500, 192)
; -> 531c1bbae7c3de019d1f53adcac7d85bf2b04caba9d6d6d1

; 更多示例详见:https://www.autohotkey.com/boards/viewtopic.php?p=109958#p109958

; ==============================================================================================
; 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"
  }
}

 

声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。