文件的哈希值校验算法
文件MD5 CRC32.ahk
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
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
; 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
; 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
; 在密码学中,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
; 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
; 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)
}
综合的哈希值校验算法实现类库
; 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"
}
}
声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。
评论(0)