CityGame Posted Saturday at 06:20 PM Posted Saturday at 06:20 PM Hello everyone, I'm new to the forum, but have been using AutoIt for years. It's quite an easy but very powerful tool to create programs, thank you My home language is spanish, so I'm sorry if I make a few mistakes while writing in english. I'm currently trying to create an updater for an already done program. The updater must be secure and not blindly download and run a new version installer, of course, so as first step I'm downloading a manifest file (that contains information about the current version update) and a signature file for that manifest created using a private key (generated by OpenSSL). Using the public key embedded in the updater program, I would then verify that the signature "matches" the manifest file. It's the first time I use those cryptography Windows functions and I have always avoided as much as I could using DllCall (because mistakes can just crash the program) so I'm not really experienced with it, but this time there is no way around and I'm "a bit" confused, I have been trying to debug this for a few days without success, and would like to ask for help here. The actual code of the first part of the updater is the following. I've translated all comments and error/warning/debug messages to english, but variable names remain in spanish. If that's a problem, please tell me. I've been using for years another naming convention for the type of variables different than the one used on the forums but I think is easy to guess, but again, if it's a problem, I would change it. The manifest and signature files exist, so the program can be run. expandcollapse popup#include <FileConstants.au3> #include <MsgBoxConstants.au3> #include <StringConstants.au3> AutoItSetOption("MustDeclareVars", 1) Global $ERROR_AU3_DLLCALL_FAILED = 1 Global $str_ProgramaVersion = 2026.3 Global $str_ActualizarManifestURL = "https://www.citygame.es/software/temp.ini" Global $str_ActualizarFirmaURL = "https://www.citygame.es/software/temp.sig" Global $str_ActualizarClavePublicaDERBase64 = "MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA4yO4ngl4jYTmEd/37XoZzkhlguyxVrNqAx0+iMpa5jIaIbeFHgmfXZzkyYFF4TW0h67xm+5wpBjyC4G0EzqX8o9COzj8wrhY9lCh0IUsVDBplC8qtgum0TEBXZGZWCSj7jD+mOrwmz4I6wUBiw5nhnt+yrMNT5f8SNK45iDE5dDUSSUtzuDCfMfGVjicBPZKKQLD2A78Ttf2rw4lTinibQjXMG5/80dGeoScAGcJfI1u6vnoyOXNssNYVD4UeMd04gvmbdTd9ovV3bGe0feBwdiiwGhVsktbQbTuy/vT8LBINqDpet6FtHLMoGHp6hq8Rx/yaykbM3wBrsz16Zyc34n1Y0dgeuYYjAbcJJplUGiBt4tv1oInASTdMwH6o+8jN77jCEOb17ZuqBYusoTxFZTNIrfzZyqT9CkwCGEvKIr4pNtjxe2whjmlUdYkRF9Z1aDhlGJsrQZUuMSBGMMOxR50GI8c3x0e1tuQNATpGukU1Q8trhsw9IGKx9WxRv+FAgMBAAE=" ;============================================================================== ; The main function does some more things, but I have left only the the update related lines. Local $int_ResultadoActualizacion = 0 $int_ResultadoActualizacion = Actualizacion() Exit $int_ResultadoActualizacion ;============================================================================== Func Actualizacion() ; Step 01 of 14: Local variables of the update function. Local Const $PROV_RSA_AES = 24 Local Const $CRYPT_VERIFYCONTEXT = 0xF0000000 Local Const $CALG_SHA_256 = 0x0000800C Local Const $HP_HASHVAL = 0x0002 Local Const $X509_ASN_ENCODING = 0x00000001 Local Const $PKCS_7_ASN_ENCODING = 0x00010000 Local $array_CryptStringToBinaryW Local $array_CryptAcquireContextW Local $array_CryptCreateHash Local $array_CryptHashData Local $array_CryptGetHashParam Local $array_CryptImportPublicKeyInfo Local $array_CryptDecodeObjectEx Local $array_CryptVerifySignatureW Local $bin_ActualizarManifestDatos Local $bin_ActualizarFirmaDatos Local $bin_ActualizarClavePublicaDER Local $bin_ActualizarManifestHash Local $dllstruct_ActualizarClavePublicaDER Local $dllstruct_ActualizarFirmaDatos Local $dllstruct_ActualizarManifestDatos Local $dllstruct_CryptDecodeObjectEx Local $dword_LongitudBufferCryptDecodeObjectEx Local $dword_LongitudBufferCryptGetHashParam Local $handle_ProveedorServiciosCriptograficos = 0 Local $handle_Hash = 0 Local $handle_ActualizarClavePublica = 0 Local $int_RetornoFileWrite = 0 Local $int_RetornoShellExecute = 0 Local $int_ResultadoMsgBox = 0 Local $object_PeticionActualizarManifest Local $object_PeticionActualizarFirma ; Step 02 of 14: Create objects to download manifest and its signature. If ((StringLeft(StringLower($str_ActualizarManifestURL), 8) <> "https://") Or (StringLeft(StringLower($str_ActualizarFirmaURL), 8) <> "https://")) Then MsgBox(16, "Error", "Download URLs no using HTTPS.", 0) Return EndIf $object_PeticionActualizarManifest = ObjCreate("WinHttp.WinHttpRequest.5.1") If @error Or Not IsObj($object_PeticionActualizarManifest) Then MsgBox(16, "Error", "Could not create WinHTTP object to download manifest.", 0) Return Else $object_PeticionActualizarManifest.Option(6) = False ; No seguir redirecciones automáticamente: WinHttpRequestOption_EnableRedirects = 6 $object_PeticionActualizarManifest.Open("GET", $str_ActualizarManifestURL, False) $object_PeticionActualizarManifest.Send() If $object_PeticionActualizarManifest.Status <> 200 Then MsgBox(48, "Warning", "Could not download manifest file." & @CRLF & @CRLF & "Server reply: " & $object_PeticionActualizarManifest.Status, 0) Return EndIf $bin_ActualizarManifestDatos = $object_PeticionActualizarManifest.ResponseBody EndIf $object_PeticionActualizarFirma = ObjCreate("WinHttp.WinHttpRequest.5.1") If @error Or Not IsObj($object_PeticionActualizarFirma) Then MsgBox(16, "Error", "Could not create WinHTTP object to download manifest signature.", 0) Return Else $object_PeticionActualizarFirma.Option(6) = False ; No seguir redirecciones automáticamente: WinHttpRequestOption_EnableRedirects = 6 $object_PeticionActualizarFirma.Open("GET", $str_ActualizarFirmaURL, False) $object_PeticionActualizarFirma.Send() If $object_PeticionActualizarFirma.Status <> 200 Then MsgBox(48, "Warning", "Could not download manifest signature file." & @CRLF & @CRLF & "Server reply: " & $object_PeticionActualizarManifest.Status, 0) Return EndIf $bin_ActualizarFirmaDatos = $object_PeticionActualizarFirma.ResponseBody EndIf ; Step 03.1 of 14: Get public key ready to use: convert DER from base64 to binary. $str_ActualizarClavePublicaDERBase64 = StringStripWS($str_ActualizarClavePublicaDERBase64, 3) If $str_ActualizarClavePublicaDERBase64 = "" Then MsgBox(16, "Error", "Embedded public key is damaged or has unexpected format.", 0) Return EndIf $array_CryptStringToBinaryW = DllCall("crypt32.dll", "bool", "CryptStringToBinaryW", "wstr", $str_ActualizarClavePublicaDERBase64, "dword", 0, "dword", 1, "ptr", 0, "dword*", 0, "ptr", 0, "ptr", 0) If @error Or Not $array_CryptStringToBinaryW[0] Then MsgBox(16, "Error", "Could not convert public key from DER Base64 to binary (step 1).", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf Local $pointer_CryptStringToBinaryWTamano = $array_CryptStringToBinaryW[5] Local $dllstruct_CryptStringToBinaryWResultado = DllStructCreate("byte[" & $pointer_CryptStringToBinaryWTamano & "]") $array_CryptStringToBinaryW = DllCall("crypt32.dll", "bool", "CryptStringToBinaryW", "wstr", $str_ActualizarClavePublicaDERBase64, "dword", 0, "dword", 1, "ptr", DllStructGetPtr($dllstruct_CryptStringToBinaryWResultado), "dword*", $pointer_CryptStringToBinaryWTamano, "ptr", 0, "ptr", 0) If @error Or Not $array_CryptStringToBinaryW[0] Then MsgBox(16, "Error", "Could not convert public key from DER Base64 to binary (step 2).", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf $bin_ActualizarClavePublicaDER = DllStructGetData($dllstruct_CryptStringToBinaryWResultado, 1) ; Step 03.2 of 14: Get public key ready to use: decode DER. $dllstruct_ActualizarClavePublicaDER = DllStructCreate("byte[" & BinaryLen($bin_ActualizarClavePublicaDER) & "]") DllStructSetData($dllstruct_ActualizarClavePublicaDER, 1, $bin_ActualizarClavePublicaDER) $dword_LongitudBufferCryptDecodeObjectEx = 0 ; Wrong?: $array_CryptDecodeObjectEx = DllCall("crypt32.dll", "bool", "CryptDecodeObjectEx", "dword", $X509_ASN_ENCODING, "str", "X509_PUBLIC_KEY_INFO", "ptr", DllStructGetPtr($dllstruct_ActualizarClavePublicaDER), "dword", BinaryLen($bin_ActualizarClavePublicaDER), "dword", 0, "ptr", 0, "ptr", 0, "dword*", $dword_LongitudBufferCryptDecodeObjectEx) $array_CryptDecodeObjectEx = DllCall("crypt32.dll", "bool", "CryptDecodeObjectEx", "dword", BitOR($X509_ASN_ENCODING, $PKCS_7_ASN_ENCODING), "ptr", 8, "ptr", DllStructGetPtr($dllstruct_ActualizarClavePublicaDER), "dword", BinaryLen($bin_ActualizarClavePublicaDER), "dword", 0, "ptr", 0, "ptr", 0, "dword*", $dword_LongitudBufferCryptDecodeObjectEx) If @error Or Not $array_CryptDecodeObjectEx[0] Or $dword_LongitudBufferCryptDecodeObjectEx = 0 Then Local $array_GetLastError = DllCall("kernel32.dll", "dword", "GetLastError") MsgBox(64, "Debug", "CryptDecodeObjectEx result (1 OK / 0 Fail): " & $array_CryptDecodeObjectEx[0] & " - GetLastError: " & $array_GetLastError[0]) MsgBox(64, "Debug", BinaryLen($bin_ActualizarClavePublicaDER) & " " & $dword_LongitudBufferCryptDecodeObjectEx) MsgBox(16, "Error", "Could not decode public key (Step 1: getting size of the result.).", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf $dllstruct_CryptDecodeObjectEx = DllStructCreate("byte[" & $dword_LongitudBufferCryptDecodeObjectEx & "]") $array_CryptDecodeObjectEx = DllCall("crypt32.dll", "bool", "CryptDecodeObjectEx", "dword", BitOR($X509_ASN_ENCODING, $PKCS_7_ASN_ENCODING), "ptr", 8, "ptr", DllStructGetPtr($dllstruct_ActualizarClavePublicaDER), "dword", BinaryLen($bin_ActualizarClavePublicaDER), "dword", 0, "ptr", 0, "ptr", DllStructGetPtr($dllstruct_CryptDecodeObjectEx), "dword*", $dword_LongitudBufferCryptDecodeObjectEx) If @error Or Not $array_CryptDecodeObjectEx[0] Then Local $array_GetLastError = DllCall("kernel32.dll", "dword", "GetLastError") MsgBox(64, "Debug", "CryptDecodeObjectEx result (1 OK / 0 Fail): " & $array_CryptDecodeObjectEx[0] & " - GetLastError: " & $array_GetLastError[0]) MsgBox(64, "Debug", BinaryLen($bin_ActualizarClavePublicaDER) & " " & $dword_LongitudBufferCryptDecodeObjectEx) MsgBox(16, "Error", "Could not decode public key (Step 2: getting the actual result.).", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf MsgBox(64, "Debug", "About to call CryptAcquireContextW") ; Step 03.3 of 14: Get public key ready to use: Adquire context and import it. $array_CryptAcquireContextW = DllCall("advapi32.dll", "bool", "CryptAcquireContextW", "ptr*", 0, "ptr", 0, "ptr", 0, "dword", $PROV_RSA_AES, "dword", $CRYPT_VERIFYCONTEXT) If @error Or Not $array_CryptAcquireContextW[0] Then MsgBox(16, "Error", "Adquiring context failed.", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf $handle_ProveedorServiciosCriptograficos = $array_CryptAcquireContextW[1] MsgBox(64, "Debug", "CryptAcquireContextW checked ok") MsgBox(64, "Debug", "About to call CryptImportPublicKeyInfo") $array_CryptImportPublicKeyInfo = DllCall("crypt32.dll", "bool", "CryptImportPublicKeyInfo", "ptr", $handle_ProveedorServiciosCriptograficos, "dword", BitOR($X509_ASN_ENCODING, $PKCS_7_ASN_ENCODING), "ptr", DllStructGetPtr($dllstruct_CryptDecodeObjectEx), "ptr*", $handle_ActualizarClavePublica) If @error Or Not $array_CryptImportPublicKeyInfo[0] Then DllCall("advapi32.dll", "bool", "CryptReleaseContext", "ptr", $handle_ProveedorServiciosCriptograficos, "dword", 0) MsgBox(16, "Error", "Importing public key failed.", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf ;DllCall("advapi32.dll", "bool", "CryptReleaseContext", "ptr", $handle_ProveedorServiciosCriptograficos, "dword", 0) ; Reuse context? $handle_ActualizarClavePublica = $array_CryptImportPublicKeyInfo[4] MsgBox(64, "Debug", "CryptImportPublicKeyInfo checked ok") ; Step 04.1 of 14: Compute hash of manifest: Create hash object. ; Reuse context? ;$array_CryptAcquireContextW = DllCall("advapi32.dll", "bool", "CryptAcquireContextW", "ptr*", 0, "ptr", 0, "ptr", 0, "dword", $PROV_RSA_AES, "dword", $CRYPT_VERIFYCONTEXT) ;If @error Or Not $array_CryptAcquireContextW[0] Then ; MsgBox(16, "Error", "Se ha producido un error al adquirir el contexto del proveedor de servicios criptográficos para calcular el hash de la información de actualización descargada.", 0) ; Return $ERROR_AU3_DLLCALL_FAILED ;EndIf ;$handle_ProveedorServiciosCriptograficos = $array_CryptAcquireContextW[1] $array_CryptCreateHash = DllCall("advapi32.dll", "bool", "CryptCreateHash", "ptr", $handle_ProveedorServiciosCriptograficos, "dword", $CALG_SHA_256, "ptr", 0, "dword", 0, "ptr*", 0) If @error Or Not $array_CryptCreateHash[0] Then DllCall("advapi32.dll", "bool", "CryptDestroyKey", "ptr", $handle_ActualizarClavePublica) DllCall("advapi32.dll", "bool", "CryptReleaseContext", "ptr", $handle_ProveedorServiciosCriptograficos, "dword", 0) MsgBox(16, "Error", "Creating hash object failed.", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf $handle_Hash = $array_CryptCreateHash[6] ; Step 04.2 of 14: Compute hash of manifest: Do compute hash. $dllstruct_ActualizarManifestDatos = DllStructCreate("byte[" & BinaryLen($bin_ActualizarManifestDatos) & "]") DllStructSetData($dllstruct_ActualizarManifestDatos, 1, $bin_ActualizarManifestDatos) $array_CryptHashData = DllCall("advapi32.dll", "bool", "CryptHashData", "ptr", $handle_Hash, "ptr", DllStructGetPtr($dllstruct_ActualizarManifestDatos), "dword", BinaryLen($bin_ActualizarManifestDatos), "dword", 0) If @error Or Not $array_CryptHashData[0] Then DllCall("advapi32.dll", "bool", "CryptDestroyHash", "ptr", $handle_Hash) DllCall("advapi32.dll", "bool", "CryptDestroyKey", "ptr", $handle_ActualizarClavePublica) DllCall("advapi32.dll", "bool", "CryptReleaseContext", "ptr", $handle_ProveedorServiciosCriptograficos, "dword", 0) MsgBox(16, "Error", "Computing hash failed.", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf ; Step 04.3 of 14: Compute hash of manifest: Obtain hash (not needed?, I use the object directly instead of this obtainted data). $dword_LongitudBufferCryptGetHashParam = 0 $array_CryptGetHashParam = DllCall("advapi32.dll", "bool", "CryptGetHashParam", "ptr", $handle_Hash, "dword", $HP_HASHVAL, "ptr", 0, "dword*", $dword_LongitudBufferCryptGetHashParam, "dword", 0) If @error Or Not $array_CryptGetHashParam[0] Or $dword_LongitudBufferCryptGetHashParam <= 0 Then DllCall("advapi32.dll", "bool", "CryptDestroyHash", "ptr", $handle_Hash) DllCall("advapi32.dll", "bool", "CryptDestroyKey", "ptr", $handle_ActualizarClavePublica) DllCall("advapi32.dll", "bool", "CryptReleaseContext", "ptr", $handle_ProveedorServiciosCriptograficos, "dword", 0) MsgBox(16, "Error", "Obtaining computed hash failed (step 1).", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf Local $dllstruct_CryptGetHashParamResultado = DllStructCreate("byte[" & $dword_LongitudBufferCryptGetHashParam & "]") $array_CryptGetHashParam = DllCall("advapi32.dll", "bool", "CryptGetHashParam", "ptr", $handle_Hash, "dword", $HP_HASHVAL, "ptr", DllStructGetPtr($dllstruct_CryptGetHashParamResultado), "dword*", $dword_LongitudBufferCryptGetHashParam, "dword", 0) If @error Or Not $array_CryptGetHashParam[0] Then DllCall("advapi32.dll", "bool", "CryptDestroyHash", "ptr", $handle_Hash) DllCall("advapi32.dll", "bool", "CryptDestroyKey", "ptr", $handle_ActualizarClavePublica) DllCall("advapi32.dll", "bool", "CryptReleaseContext", "ptr", $handle_ProveedorServiciosCriptograficos, "dword", 0) MsgBox(16, "Error", "Obtaining computed hash failed (step 2).", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf ;DllCall("advapi32.dll", "bool", "CryptDestroyHash", "ptr", $handle_Hash) ; Should not release this before verifying the signature? ;DllCall("advapi32.dll", "bool", "CryptReleaseContext", "ptr", $handle_ProveedorServiciosCriptograficos, "dword", 0) ; Should not release this before verifying the signature? $bin_ActualizarManifestHash = DllStructGetData($dllstruct_CryptGetHashParamResultado, 1) ; Step 05 of 14: Verify signature using public key. $dllstruct_ActualizarFirmaDatos = DllStructCreate("byte[" & BinaryLen($bin_ActualizarFirmaDatos) & "]") DllStructSetData($dllstruct_ActualizarFirmaDatos, 1, $bin_ActualizarFirmaDatos) $array_CryptVerifySignatureW = DllCall("advapi32.dll", "bool", "CryptVerifySignatureW", "ptr", $handle_Hash, "ptr", DllStructGetPtr($dllstruct_ActualizarFirmaDatos), "dword", BinaryLen($bin_ActualizarFirmaDatos), "ptr", $handle_ActualizarClavePublica, "ptr", 0, "dword", 0) If @error Then DllCall("advapi32.dll", "bool", "CryptDestroyHash", "ptr", $handle_Hash) DllCall("advapi32.dll", "bool", "CryptDestroyKey", "ptr", $handle_ActualizarClavePublica) DllCall("advapi32.dll", "bool", "CryptReleaseContext", "ptr", $handle_ProveedorServiciosCriptograficos, "dword", 0) MsgBox(16, "Error", "Could not verify signature.", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf DllCall("advapi32.dll", "bool", "CryptDestroyHash", "ptr", $handle_Hash) DllCall("advapi32.dll", "bool", "CryptDestroyKey", "ptr", $handle_ActualizarClavePublica) DllCall("advapi32.dll", "bool", "CryptReleaseContext", "ptr", $handle_ProveedorServiciosCriptograficos, "dword", 0) If $array_CryptVerifySignatureW[0] = 0 Then MsgBox(48, "Warning", "Signature is not valid. Manifest file may be corrupted...", 0) Return EndIf MsgBox(48, "Debug", "Manifest is OK. Next we parse the file and so on...", 0) EndFunc I've tried to follow the documentation on Microsoft about all these functions, but I think I made a mistake, as the CryptDecodeObjectEx function doesn't work as I expected. When I call it to get the size of the result, I get a 0 size, so something must be wrong on my call, but I can't guess where is the mistake. Later, that causes the CryptImportPublicKeyInfo call to crash, so I suppose I must fix something on the CryptDecodeObjectEx call first. Can you please help me to find the problem? If some more information is needed, please just tell me. Thank you very much
Nine Posted Saturday at 06:57 PM Posted Saturday at 06:57 PM I am not gonna run a program that I do not fully understand. And yours is a quite long for me to follow all the steps and understand what it does. I strongly suggest that you eliminate all unnecessary parts to surround the part that doesn't work. In other words, make a minimalist snippet with CryptDecodeObjectEx that shows the issue. Thanks. “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy Interface Object based on Tag
CityGame Posted Saturday at 07:52 PM Author Posted Saturday at 07:52 PM Hello, and thanks for replying The part that fails is where the public key (the long string on the $str_ActualizarClavePublicaDERBase64 variable) is converted from Base64 to binary (step 03.1; that seems to work), then decoded (step 03.2; that's the part that I think that fails), then imported to the cryptographic context to be used (step 03.3; that's the part where it crashes, probably because the previous one did fail somehow). If we are just checking that, I suppose I can remove any following steps (steps 04 and 05) and the previous download of the files that would be checked (step 02)... I have not removed unused variables at the beginning. I bet I will have to add those parts again once this one works to ask for help with them Just in case, that "import" of the public key doesn't mean the public key is imported to the certificate store of the computer, it's imported to the context of this program so the Windows functions that verify the files can use it. The program is safe. I'm trying to create a really secure updater that won't be fooled to run an untrusted update even if something like the recent Notepad++ hack happens. Here is the smaller version: expandcollapse popup#include <FileConstants.au3> #include <MsgBoxConstants.au3> #include <StringConstants.au3> AutoItSetOption("MustDeclareVars", 1) Global $ERROR_AU3_DLLCALL_FAILED = 1 Global $str_ActualizarClavePublicaDERBase64 = "MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA4yO4ngl4jYTmEd/37XoZzkhlguyxVrNqAx0+iMpa5jIaIbeFHgmfXZzkyYFF4TW0h67xm+5wpBjyC4G0EzqX8o9COzj8wrhY9lCh0IUsVDBplC8qtgum0TEBXZGZWCSj7jD+mOrwmz4I6wUBiw5nhnt+yrMNT5f8SNK45iDE5dDUSSUtzuDCfMfGVjicBPZKKQLD2A78Ttf2rw4lTinibQjXMG5/80dGeoScAGcJfI1u6vnoyOXNssNYVD4UeMd04gvmbdTd9ovV3bGe0feBwdiiwGhVsktbQbTuy/vT8LBINqDpet6FtHLMoGHp6hq8Rx/yaykbM3wBrsz16Zyc34n1Y0dgeuYYjAbcJJplUGiBt4tv1oInASTdMwH6o+8jN77jCEOb17ZuqBYusoTxFZTNIrfzZyqT9CkwCGEvKIr4pNtjxe2whjmlUdYkRF9Z1aDhlGJsrQZUuMSBGMMOxR50GI8c3x0e1tuQNATpGukU1Q8trhsw9IGKx9WxRv+FAgMBAAE=" ;============================================================================== ; The main function does some more things, but I have left only the the update related lines. Local $int_ResultadoActualizacion = 0 $int_ResultadoActualizacion = Actualizacion() Exit $int_ResultadoActualizacion ;============================================================================== Func Actualizacion() ; Step 01 of 14: Local variables of the update function. Local Const $PROV_RSA_AES = 24 Local Const $CRYPT_VERIFYCONTEXT = 0xF0000000 Local Const $CALG_SHA_256 = 0x0000800C Local Const $HP_HASHVAL = 0x0002 Local Const $X509_ASN_ENCODING = 0x00000001 Local Const $PKCS_7_ASN_ENCODING = 0x00010000 Local $array_CryptStringToBinaryW Local $array_CryptAcquireContextW Local $array_CryptCreateHash Local $array_CryptHashData Local $array_CryptGetHashParam Local $array_CryptImportPublicKeyInfo Local $array_CryptDecodeObjectEx Local $array_CryptVerifySignatureW Local $bin_ActualizarManifestDatos Local $bin_ActualizarFirmaDatos Local $bin_ActualizarClavePublicaDER Local $bin_ActualizarManifestHash Local $dllstruct_ActualizarClavePublicaDER Local $dllstruct_ActualizarFirmaDatos Local $dllstruct_ActualizarManifestDatos Local $dllstruct_CryptDecodeObjectEx Local $dword_LongitudBufferCryptDecodeObjectEx Local $dword_LongitudBufferCryptGetHashParam Local $handle_ProveedorServiciosCriptograficos = 0 Local $handle_Hash = 0 Local $handle_ActualizarClavePublica = 0 Local $int_RetornoFileWrite = 0 Local $int_RetornoShellExecute = 0 Local $int_ResultadoMsgBox = 0 Local $object_PeticionActualizarManifest Local $object_PeticionActualizarFirma ; Step 03.1 of 14: Get public key ready to use: convert DER from base64 to binary. $str_ActualizarClavePublicaDERBase64 = StringStripWS($str_ActualizarClavePublicaDERBase64, 3) If $str_ActualizarClavePublicaDERBase64 = "" Then MsgBox(16, "Error", "Embedded public key is damaged or has unexpected format.", 0) Return EndIf $array_CryptStringToBinaryW = DllCall("crypt32.dll", "bool", "CryptStringToBinaryW", "wstr", $str_ActualizarClavePublicaDERBase64, "dword", 0, "dword", 1, "ptr", 0, "dword*", 0, "ptr", 0, "ptr", 0) If @error Or Not $array_CryptStringToBinaryW[0] Then MsgBox(16, "Error", "Could not convert public key from DER Base64 to binary (step 1).", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf Local $pointer_CryptStringToBinaryWTamano = $array_CryptStringToBinaryW[5] Local $dllstruct_CryptStringToBinaryWResultado = DllStructCreate("byte[" & $pointer_CryptStringToBinaryWTamano & "]") $array_CryptStringToBinaryW = DllCall("crypt32.dll", "bool", "CryptStringToBinaryW", "wstr", $str_ActualizarClavePublicaDERBase64, "dword", 0, "dword", 1, "ptr", DllStructGetPtr($dllstruct_CryptStringToBinaryWResultado), "dword*", $pointer_CryptStringToBinaryWTamano, "ptr", 0, "ptr", 0) If @error Or Not $array_CryptStringToBinaryW[0] Then MsgBox(16, "Error", "Could not convert public key from DER Base64 to binary (step 2).", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf $bin_ActualizarClavePublicaDER = DllStructGetData($dllstruct_CryptStringToBinaryWResultado, 1) ; Step 03.2 of 14: Get public key ready to use: decode DER. $dllstruct_ActualizarClavePublicaDER = DllStructCreate("byte[" & BinaryLen($bin_ActualizarClavePublicaDER) & "]") DllStructSetData($dllstruct_ActualizarClavePublicaDER, 1, $bin_ActualizarClavePublicaDER) $dword_LongitudBufferCryptDecodeObjectEx = 0 ; Wrong?: $array_CryptDecodeObjectEx = DllCall("crypt32.dll", "bool", "CryptDecodeObjectEx", "dword", $X509_ASN_ENCODING, "str", "X509_PUBLIC_KEY_INFO", "ptr", DllStructGetPtr($dllstruct_ActualizarClavePublicaDER), "dword", BinaryLen($bin_ActualizarClavePublicaDER), "dword", 0, "ptr", 0, "ptr", 0, "dword*", $dword_LongitudBufferCryptDecodeObjectEx) $array_CryptDecodeObjectEx = DllCall("crypt32.dll", "bool", "CryptDecodeObjectEx", "dword", BitOR($X509_ASN_ENCODING, $PKCS_7_ASN_ENCODING), "ptr", 8, "ptr", DllStructGetPtr($dllstruct_ActualizarClavePublicaDER), "dword", BinaryLen($bin_ActualizarClavePublicaDER), "dword", 0, "ptr", 0, "ptr", 0, "dword*", $dword_LongitudBufferCryptDecodeObjectEx) If @error Or Not $array_CryptDecodeObjectEx[0] Or $dword_LongitudBufferCryptDecodeObjectEx = 0 Then Local $array_GetLastError = DllCall("kernel32.dll", "dword", "GetLastError") MsgBox(64, "Debug", "CryptDecodeObjectEx result (1 OK / 0 Fail): " & $array_CryptDecodeObjectEx[0] & " - GetLastError: " & $array_GetLastError[0]) MsgBox(64, "Debug", BinaryLen($bin_ActualizarClavePublicaDER) & " " & $dword_LongitudBufferCryptDecodeObjectEx) MsgBox(16, "Error", "Could not decode public key (Step 1: getting size of the result.).", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf $dllstruct_CryptDecodeObjectEx = DllStructCreate("byte[" & $dword_LongitudBufferCryptDecodeObjectEx & "]") $array_CryptDecodeObjectEx = DllCall("crypt32.dll", "bool", "CryptDecodeObjectEx", "dword", BitOR($X509_ASN_ENCODING, $PKCS_7_ASN_ENCODING), "ptr", 8, "ptr", DllStructGetPtr($dllstruct_ActualizarClavePublicaDER), "dword", BinaryLen($bin_ActualizarClavePublicaDER), "dword", 0, "ptr", 0, "ptr", DllStructGetPtr($dllstruct_CryptDecodeObjectEx), "dword*", $dword_LongitudBufferCryptDecodeObjectEx) If @error Or Not $array_CryptDecodeObjectEx[0] Then Local $array_GetLastError = DllCall("kernel32.dll", "dword", "GetLastError") MsgBox(64, "Debug", "CryptDecodeObjectEx result (1 OK / 0 Fail): " & $array_CryptDecodeObjectEx[0] & " - GetLastError: " & $array_GetLastError[0]) MsgBox(64, "Debug", BinaryLen($bin_ActualizarClavePublicaDER) & " " & $dword_LongitudBufferCryptDecodeObjectEx) MsgBox(16, "Error", "Could not decode public key (Step 2: getting the actual result.).", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf MsgBox(64, "Debug", "About to call CryptAcquireContextW") ; Step 03.3 of 14: Get public key ready to use: Adquire context and import it. $array_CryptAcquireContextW = DllCall("advapi32.dll", "bool", "CryptAcquireContextW", "ptr*", 0, "ptr", 0, "ptr", 0, "dword", $PROV_RSA_AES, "dword", $CRYPT_VERIFYCONTEXT) If @error Or Not $array_CryptAcquireContextW[0] Then MsgBox(16, "Error", "Adquiring context failed.", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf $handle_ProveedorServiciosCriptograficos = $array_CryptAcquireContextW[1] MsgBox(64, "Debug", "CryptAcquireContextW checked ok") MsgBox(64, "Debug", "About to call CryptImportPublicKeyInfo") $array_CryptImportPublicKeyInfo = DllCall("crypt32.dll", "bool", "CryptImportPublicKeyInfo", "ptr", $handle_ProveedorServiciosCriptograficos, "dword", BitOR($X509_ASN_ENCODING, $PKCS_7_ASN_ENCODING), "ptr", DllStructGetPtr($dllstruct_CryptDecodeObjectEx), "ptr*", $handle_ActualizarClavePublica) If @error Or Not $array_CryptImportPublicKeyInfo[0] Then DllCall("advapi32.dll", "bool", "CryptReleaseContext", "ptr", $handle_ProveedorServiciosCriptograficos, "dword", 0) MsgBox(16, "Error", "Importing public key failed.", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf ;DllCall("advapi32.dll", "bool", "CryptReleaseContext", "ptr", $handle_ProveedorServiciosCriptograficos, "dword", 0) ; Reuse context? $handle_ActualizarClavePublica = $array_CryptImportPublicKeyInfo[4] MsgBox(64, "Debug", "CryptImportPublicKeyInfo checked ok") EndFunc Hope everything is ok now, but if some more explanation is needed, just tell me. Thank you
Nine Posted 17 hours ago Posted 17 hours ago Although I am not familiar with those API and not much more about cryptography, I will try to help. The issue is (as you already noticed) coming from the call to CryptDecodeObjectEx. Based on MSDN, the first parameter seem alright, second might be replaced with this : $array_CryptDecodeObjectEx = DllCall("crypt32.dll", "bool", "CryptDecodeObjectEx", "dword", BitOR($X509_ASN_ENCODING, $PKCS_7_ASN_ENCODING), "ptr", Ptr(8), _ Ptr(8) implies Quote X509_PUBLIC_KEY_INFO (LPCSTR) 8 The pvStructInfo parameter is a pointer to a CERT_PUBLIC_KEY_INFO structure. So this is the third parameter, a pointer to this structure. Quote typedef struct _CERT_PUBLIC_KEY_INFO { CRYPT_ALGORITHM_IDENTIFIER Algorithm; CRYPT_BIT_BLOB PublicKey; } CERT_PUBLIC_KEY_INFO, *PCERT_PUBLIC_KEY_INFO; The algorithm is again a structure : Quote typedef struct _CRYPT_ALGORITHM_IDENTIFIER { LPSTR pszObjId; CRYPT_OBJID_BLOB Parameters; } CRYPT_ALGORITHM_IDENTIFIER, *PCRYPT_ALGORITHM_IDENTIFIER; Where pszObjId is a string constant found here. Now my questions are what string should reflect your situation ? And what could be the parameters (if any) ? “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy Interface Object based on Tag
CityGame Posted 12 hours ago Author Posted 12 hours ago Quote Although I am not familiar with those API and not much more about cryptography, I will try to help. Thanks a lot. I'm not familiar with it either I've changed the second parameter to Ptr(8), as you said. As you point, it seems my third parameter is wrong... I'm passing only a structure with the public key, but the algorithm identifier structure is missing... Thanks for finding this, I didn't know about that page with the structure and the algorithms... There are a ton of algorithms... I created the signature as RSA using OpenSSL (Command: openssl genrsa -out private-key.pem 3072) and the hashes used are SHA-256 (Command to sign the ini: openssl dgst -sha256 -sign private-key.pem -out temp.sig temp.ini), so I suppose the algorithm is RSA, but I'm sorry, I don't really know which of the different RSA choices should I choose... Maybe "szOID_RSA_HASH" or "szOID_RSA_SHA256RSA" (it seems none of them use parameters, so if I'm not mistaken, the parameters should be "0") I've tried to create the new DllStruct, but I'm doing something wrong. The CryptDecodeObjectEx function fails (Result: 0 / GetLastError: 2148086027): Local $dllstruct_ActualizarClavePublicaDER_Algorithm = DllStructCreate("ptr;int") If @error Then MsgBox(64, "Debug", "1 DllStructCreateError: " & @error) DllStructSetData($dllstruct_ActualizarClavePublicaDER_Algorithm, 1, Ptr("1.2.840.113549.1.1.11")) DllStructSetData($dllstruct_ActualizarClavePublicaDER_Algorithm, 2, 0) $dllstruct_ActualizarClavePublicaDER = DllStructCreate("ptr;byte[" & BinaryLen($bin_ActualizarClavePublicaDER) & "]") If @error Then MsgBox(64, "Debug", "2 DllStructCreateError: " & @error) DllStructSetData($dllstruct_ActualizarClavePublicaDER, 1, DllStructGetPtr($dllstruct_ActualizarClavePublicaDER_Algorithm)) DllStructSetData($dllstruct_ActualizarClavePublicaDER, 2, $bin_ActualizarClavePublicaDER) $dword_LongitudBufferCryptDecodeObjectEx = 0 $array_CryptDecodeObjectEx = DllCall("crypt32.dll", "bool", "CryptDecodeObjectEx", "dword", BitOR($X509_ASN_ENCODING, $PKCS_7_ASN_ENCODING), "ptr", ptr(8), "ptr", DllStructGetPtr($dllstruct_ActualizarClavePublicaDER), "dword", BinaryLen($bin_ActualizarClavePublicaDER), "dword", 0, "ptr", 0, "ptr", 0, "dword*", $dword_LongitudBufferCryptDecodeObjectEx) If @error Or Not $array_CryptDecodeObjectEx[0] Or $dword_LongitudBufferCryptDecodeObjectEx = 0 Then Local $array_GetLastError = DllCall("kernel32.dll", "dword", "GetLastError") MsgBox(64, "Debug", "CryptDecodeObjectEx result (1 OK / 0 Fail): " & $array_CryptDecodeObjectEx[0] & " - GetLastError: " & $array_GetLastError[0]) MsgBox(64, "Debug", BinaryLen($bin_ActualizarClavePublicaDER) & " " & $dword_LongitudBufferCryptDecodeObjectEx) MsgBox(16, "Error", "Could not decode public key (Step 1: getting size of the result.).", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf $dllstruct_CryptDecodeObjectEx = DllStructCreate("byte[" & $dword_LongitudBufferCryptDecodeObjectEx & "]") $array_CryptDecodeObjectEx = DllCall("crypt32.dll", "bool", "CryptDecodeObjectEx", "dword", BitOR($X509_ASN_ENCODING, $PKCS_7_ASN_ENCODING), "ptr", ptr(8), "ptr", DllStructGetPtr($dllstruct_ActualizarClavePublicaDER), "dword", BinaryLen($bin_ActualizarClavePublicaDER), "dword", 0, "ptr", 0, "ptr", DllStructGetPtr($dllstruct_CryptDecodeObjectEx), "dword*", $dword_LongitudBufferCryptDecodeObjectEx) If @error Or Not $array_CryptDecodeObjectEx[0] Then Local $array_GetLastError = DllCall("kernel32.dll", "dword", "GetLastError") MsgBox(64, "Debug", "CryptDecodeObjectEx result (1 OK / 0 Fail): " & $array_CryptDecodeObjectEx[0] & " - GetLastError: " & $array_GetLastError[0]) MsgBox(64, "Debug", BinaryLen($bin_ActualizarClavePublicaDER) & " " & $dword_LongitudBufferCryptDecodeObjectEx) MsgBox(16, "Error", "Could not decode public key (Step 2: getting the actual result.).", 0) Return $ERROR_AU3_DLLCALL_FAILED EndIf
Nine Posted 4 hours ago Posted 4 hours ago I believe it should be something like this, but it is not working for me either. Local $sAlgo = "1.2.840.113549.1.1.11" ; CRYPT_ALGORITHM_IDENTIFIER structure Local $tAlgorithm = DllStructCreate("ptr str;ptr param") Local $tString = DllStructCreate("char str[" & StringLen($sAlgo) + 1 & "]") $tString.str = $sAlgo ConsoleWrite($tString.str & @CRLF) $tAlgorithm.str = DllStructGetPtr($tString) $tAlgorithm.param = 0 ; CERT_PUBLIC_KEY_INFO Local $tPubliKey = DllStructCreate("ptr algo;ptr pkey") $tPubliKey.algo = DllStructGetPtr($tAlgorithm) $tPubliKey.pkey = 0 ; certainly wrong - should be BLOBHEADER ? ; X509_PUBLIC_KEY_INFO = 8 $array_CryptDecodeObjectEx = DllCall("crypt32.dll", "bool", "CryptDecodeObjectEx", "dword", BitOR($X509_ASN_ENCODING, $PKCS_7_ASN_ENCODING), "ptr", Ptr(8), _ "ptr", DllStructGetPtr($tPubliKey), "dword", DllStructGetSize($tPubliKey), "dword", 0, "ptr", 0, "ptr*", 0, "dword*", 0) _ArrayDisplay($array_CryptDecodeObjectEx) “They did not know it was impossible, so they did it” ― Mark Twain Spoiler Block all input without UAC Save/Retrieve Images to/from Text Monitor Management (VCP commands) Tool to search in text (au3) files Date Range Picker Virtual Desktop Manager Sudoku Game 2020 Overlapped Named Pipe IPC HotString 2.0 - Hot keys with string x64 Bitwise Operations Multi-keyboards HotKeySet Recursive Array Display Fast and simple WCD IPC Multiple Folders Selector Printer Manager GIF Animation (cached) Debug Messages Monitor UDF Screen Scraping Round Corner GUI UDF Multi-Threading Made Easy Interface Object based on Tag
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now