Skip to content

Instantly share code, notes, and snippets.

@anonymous1184
Created January 6, 2023 18:33
Show Gist options
  • Save anonymous1184/789b1485b6e161bcb782cfa651cc52f6 to your computer and use it in GitHub Desktop.
Save anonymous1184/789b1485b6e161bcb782cfa651cc52f6 to your computer and use it in GitHub Desktop.
MasterPassword.ahk

Information:

https://redd.it/1051mkc

See the example.ahk in this gist.

Crypt.ahk was modified to make it #Warn-compatible (Crypt.ahk.patch file provided for diff)


Creates a new encrypted password in the defined path:

MasterPassword_Create(Password, Path)

Returns the password, asks for the decryption key if necessary:

MasterPassword(Path)

Clears the password from memory:

MasterPassword("")

To automatically clear the password:

Options := {}
; Options.Inactive := int  ; In minutes
; Options.Lid      := bool ; On lid close
; Options.Lock     := bool ; On lock screen
; Options.Sleep    := bool ; On system sleep
MasterPassword_Clear(Options)

Stop and remove auto-clearing

MasterPassword_Clear("")
; ===============================================================================================================================
; 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")
{
phHash := pbSecret := cbSecret := 0
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)
{
cbOutput := pbIV := cbIV := 0, Encoding := "UTF-8"
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)
{
cbOutput := pbIV := cbIV := 0, Encoding := "UTF-8"
;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 := 0
, "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)
{
pcbResult := pbOutput := 0
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 := 0
, "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 := 0))
{
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 := 0
, "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"
}
}
--- a/Crypt.ahk
+++ b/Crypt.ahk
@@ -367,0 +368 @@
+ phHash := pbSecret := cbSecret := 0
@@ -419,0 +421 @@
+ cbOutput := pbIV := cbIV := 0, Encoding := "UTF-8"
@@ -462,0 +465 @@
+ cbOutput := pbIV := cbIV := 0, Encoding := "UTF-8"
@@ -565 +568 @@
- , "ptr*", phKey
+ , "ptr*", phKey := 0
@@ -579,0 +583 @@
+ pcbResult := pbOutput := 0
@@ -608 +612 @@
- NT_STATUS := DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", phAlgorithm
+ NT_STATUS := DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", phAlgorithm := 0
@@ -648 +652 @@
- , "uint*", pcchString))
+ , "uint*", pcchString := 0))
@@ -672 +676 @@
- , "uint*", pcbBinary
+ , "uint*", pcbBinary := 0
; Clear on sleep:
MasterPassword_Clear({"Sleep": true})
return ; End of auto-execute
; To create a new encrypted file containing your password
^!c::
InputBox passwd, Master Password:,,, 200, 100,,, Locale
if (!passwd)
return
MasterPassword_Create(passwd, A_AppData "\master.dat")
return
; To type your password after successfully decrypting it
^!p:: ; Via hotkey
:*X:pass\:: ; Via hotstring
SetKeyDelay 30
SendEvent % "{Text}" MasterPassword(A_AppData "\master.dat")
return
#Include %A_LineFile%\..\Crypt.ahk
; https://github.com/jNizM/AHK_CNG
#Include %A_LineFile%\..\MasterPassword.ahk
; Version: 2023.01.06.1
; Information: https://redd.it/1051mkc
MasterPassword(Path) {
static decrypted := ""
if (!Path)
return decrypted := ""
if (decrypted)
return decrypted
try
FileRead data, % Path
catch
throw Exception("Couldn't read password file.", -1, Path)
data := StrSplit(data, "|")
encrypted := data[1]
iterations := data[2]
loop 3 {
InputBox key, Encryption Key:,, Hide, 200, 100,,, Locale
if (ErrorLevel)
Exit
if (!key)
continue
try {
salt := MasterPassword_Salt(key)
key := Crypt.Hash.PBKDF2("SHA512", key, salt, iterations, 512)
decrypted := Crypt.Decrypt.String("AES", "CBC", encrypted, key)
return decrypted
}
}
MsgBox 0x40010, Error, Password couldn't be decrypted.
Exit
}
; Options := {}
; Options.Inactive := int ; In minutes
; Options.Lid := bool ; On lid close
; Options.Lock := bool ; On lock screen
; Options.Sleep := bool ; On system sleep
MasterPassword_Clear(Options) {
static timer := "", a := "", b := ""
if (IsObject(timer)) {
SetTimer % timer, Delete
timer := ""
}
if (IsObject(a))
OnMessage(0x0218, a, 0), a := ""
if (IsObject(b))
OnMessage(0x02B1, b, 0), b := ""
if (!IsObject(Options))
return
if (Options.Inactive ~= "^\d+$") {
if (Options.Inactive) {
ms := 1000 * 60 * Options.Inactive
timer := Func("MasterPassword_Timer").Bind(ms)
SetTimer % timer, % 1000 * 10
}
}
; WM_POWERBROADCAST
if (Options.Lid = true || Options.Sleep = true) {
VarSetCapacity(GUID_LIDSWITCH_STATE_CHANGE, 16, 0)
NumPut(0xBA3E0F4D,GUID_LIDSWITCH_STATE_CHANGE, 0, "UInt")
NumPut(0x4094B817,GUID_LIDSWITCH_STATE_CHANGE, 4, "UInt")
NumPut(0x63D5D1A2,GUID_LIDSWITCH_STATE_CHANGE, 8, "UInt")
NumPut(0xF3A0E679,GUID_LIDSWITCH_STATE_CHANGE, 12, "UInt")
DllCall("User32\RegisterPowerSettingNotification"
, "UInt",A_ScriptHwnd
, "Ptr",&GUID_LIDSWITCH_STATE_CHANGE
, "UInt",0)
if (IsObject(a)) {
OnMessage(0x0218, a, 0)
a := ""
}
a := Func("MasterPassword_Monitor").Bind("A")
OnMessage(0x0218, a)
}
; WM_WTSSESSION_CHANGE
if (Options.Lock = true) {
DllCall("Wtsapi32\WTSRegisterSessionNotification"
, "Ptr",A_ScriptHwnd
, "UInt",1)
if (IsObject(b)) {
OnMessage(0x02B1, b, 0)
b := ""
}
b := Func("MasterPassword_Monitor").Bind("B")
OnMessage(0x02B1, b)
}
}
MasterPassword_Create(Pass, Path) {
; Dynamically generated salt
salt := MasterPassword_Salt(Pass)
; Calculate iterations per second
tc := A_TickCount, iterations := 100000
Crypt.Hash.PBKDF2("SHA512", Pass, salt, iterations, 512)
elapsed := A_TickCount - tc
iterations := Ceil(1000 * iterations / elapsed)
; Derive key
key := Crypt.Hash.PBKDF2("SHA512", Pass, salt, iterations, 512)
; Encrypt password with AES CBC
encrypted := Crypt.Encrypt.String("AES", "CBC", Pass, key)
; Save it alongside the number of number of iterations for the key
if (!FileOpen(Path, 0x1, "CP1252").Write(encrypted "|" iterations))
throw Exception("Couldn't write to " Path, -1)
}
MasterPassword_Monitor(Type, wParam, lParam, Msg) {
if (Type = "A" && Msg = 0x0218 && wParam = 0x4) ; Lid/Sleep
|| (Type = "B" && Msg = 0x02B1 && wParam = 0x7) ; Lock
MasterPassword("")
}
MasterPassword_Salt(String) {
strLen := StrLen(String)
seed := DllCall("Ntdll\RtlComputeCrc32"
, "Ptr",0
, "AStr",String
, "UInt",strLen
, "UInt")
Random ,, % seed
salt := ""
loop % strLen {
Random r, 0x20, 0xFFFF
salt .= Chr(r)
}
Random ,, % A_Now
salt := Crypt.Hash.String("SHA512", salt)
return salt
}
MasterPassword_Timer(ms) {
if (A_TimeIdle >= ms)
MasterPassword("")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment