Jump to content
Advert

Recommended Posts

Posted

yes, I'm want to:

Quote

store the public key blob in a variable or constant within you script and use it to encrypt data

 

I'm tryed to find internal function by this keyword __CryptoNG_BcryptImportKeyPair

but can't find...

Advert
Posted
16 minutes ago, kroman82 said:

sorry, I'm found that...

...
Func __CryptoNG_BcryptImportKeyPair($hAlgorithmProvider, $sKeyBlobFile, $sKeyBlobType, $xKeyBlob = Binary(""))

    If $__gbDebugging Then _DebugOut(@CRLF & "Function: __CryptoNG_BcryptImportKeyPair()")

    Local $aResult[0]

    Local $iError = 0, _
            $iStatusCode = 0

    Local $tBuffer = ""

    Local $hFile = -1, _
            $hKey = -1

;~  Local $xKeyBlob = Binary("")
    If $xKeyBlob = Binary("") Then


        ;Make sure file exists
        If Not FileExists($sKeyBlobFile) Then Return SetError(3, 0, "")


        ;Read binary blob file
        $hFile = FileOpen($sKeyBlobFile, $FO_BINARY)
        If $hFile = -1 Then Return SetError(4, 0, "")

        $xKeyBlob = FileRead($hFile)
        FileClose($hFile)

    EndIf
...

Placing $xKeyBlob as a parameter I think would work nicely :)

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting  image.gif.922e3a93535f431de08b31ee669cc446.gif
autoit_scripter_blue_userbar.png

Posted

..then again:

...
Func __CryptoNG_BcryptImportKeyPair($hAlgorithmProvider, $sKeyBlobFile, $sKeyBlobType)

    If $__gbDebugging Then _DebugOut(@CRLF & "Function: __CryptoNG_BcryptImportKeyPair()")

    Local $aResult[0]

    Local $iError = 0, _
            $iStatusCode = 0

    Local $tBuffer = ""

    Local $hFile = -1, _
            $hKey = -1


    Local $xKeyBlob = Binary("")
    If StringLeft($sKeyBlobFile, 3) = "ECS" Or StringLeft($sKeyBlobFile, 3) = "RSA" Then
        $xKeyBlob = $sKeyBlobFile
    Else

        ;Make sure file exists
        If Not FileExists($sKeyBlobFile) Then Return SetError(3, 0, "")


        ;Read binary blob file
        $hFile = FileOpen($sKeyBlobFile, $FO_BINARY)
        If $hFile = -1 Then Return SetError(4, 0, "")

        $xKeyBlob = FileRead($hFile)
        FileClose($hFile)

    EndIf
...

these blob files start with a header that is ECS or RSA and no filename will start as such. This idea will be easier to implement script wide.

Am just looking at it. Never used the UDF yet. Just sharing ideas.

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting  image.gif.922e3a93535f431de08b31ee669cc446.gif
autoit_scripter_blue_userbar.png

Posted (edited)

ok, here is my running code/idea:  <removed>

I will remove this file in a few days to save in forum file space. I hope this is all you are after @kroman82
( I worked on it because I've got things to do but I don't wanna do 'em but am anxious 🤪 )

Edit: removed zip.
New v2.4.0 can now accept the public/private key blob as either a string containing the file path to the key blob file or as binary data containing the key blob itself.

Edited by argumentum
removed zip file

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting  image.gif.922e3a93535f431de08b31ee669cc446.gif
autoit_scripter_blue_userbar.png

Posted

I use both Crypt.au3 and CryptoNG.au3 and often operate conversion and creation and non-file usage. I would like to share some codes that I have improved or generated, hoping to be helpful to you.

 

#include "..\CryptoNG.au3"

#include <bignum.au3>
#include <string.au3>
#include <array.au3>

 

    Local $c_data = FileOpenDialog("Select a license data", @ScriptDir & "\", "c data (*.*)", 1)
    If @error Then
        MsgBox(4096,"","No File(s) choose")
        Exit
    EndIf

     Local $hFileOpen = FileOpen($c_data, 0)
     Local $c = FileRead($hFileOpen)

$Private_c =_WinAPI_Base64Decode($c)

$n_binary = Binary("0xput in data")

$Public_key = Create_to_Blob(@ScriptDir&"\Test.blob","public", 2048, 65537, $n_binary, 0x0, 0x0, 0, 0 )

$m = _CryptoNG_RSA_EncryptData($Private_c , $Public_key, $CNG_BCRYPT_PAD_NONE, Default, "binary" )

 

 

;Read_to_Blob(@ScriptDir&"\example_legacy_privatekey.blob", "Private", "Legacy")
;Read_to_Blob(@ScriptDir&"\example_legacy_publickey.blob", "Public", "Legacy")

;Read_to_Blob(@ScriptDir&"\example_rsa_privatekey.blob","Private")
;Read_to_Blob(@ScriptDir&"\example_rsa_publickey.blob","public")

 

;Create_to_Blob(@ScriptDir&"\Test20250227.blob","public",2048,65537,Binary("0x" & _BigHex_Swap_endian("092E57E9A31BB37F89222D15A2449594A4ED5705BF395A4469218881CA8C8A27437F7CE2B1ADEF8D93AE19BF381489DD7D06ED674FF945BF932F3FD81CEDB875F8A677CD4A4468A5DF249B9C0611F5E31DE60DBA86BCB69C38D0EED3931A61E379136E52FB7D39B30B5FA29CA5205D8B6A8101E666779EF3D99B196B4F54AA43F682B53FA5BE8986A7086D4C75975DCB22640DD8ACFAEBA7C8D72058AC997F4EB72F824FD45C55C29C0834AB0D629B56F191A4BB16CDA0694141DC64DAACEF8F923FDC8F3734FA5CE59E7034C2D9237358084259D10134C0A13C2098847630B656179B1F7DB61674D1B705A10E41A7F215D0D865A46E6BC2850642BA413C55C5")),Binary("0x" & _BigHex_Swap_endian("C7C6000BB7C3E10D0440AB2BE592D5F0A7D7899A721A256C0554CF3989D77C1AC1BCC27F9CF4884033A16D0CA8B478A9B2DCB92B6A5993AD3E303D971F1539C8AD306697BA08B340EEAD98D4C462B5E77DF9615F0DA5ED5DFA5B6167AD19D6C6A06AAD1ED71E8E1B7A99F9F3E3838DE7F51F0B2C5AE3D2B784C55A29AAB8A8CF")),Binary("0x" & _BigHex_Swap_endian("AF54BA9A2567F5AD9BC29158786F9E7264DDB487E8750B1E2455121383CE487EA2F1E43842D42864830063FCD906B521F6DE05CACBD8CC5886486DFA51DFB6D404F5168F26B5508F6F71D937C27A0EF90300A60B9293AB00B3D2917C65D2B7AFDC5635F0AC721622307DF3D846F501CA1125D567D4178929CFF93281202345F3")),0,1,"Legacy")
;Create_to_Blob(@ScriptDir&"\Test20250227.blob","PRIVATE",2048,65537,Binary("0x" & _BigHex_Swap_endian("092E57E9A31BB37F89222D15A2449594A4ED5705BF395A4469218881CA8C8A27437F7CE2B1ADEF8D93AE19BF381489DD7D06ED674FF945BF932F3FD81CEDB875F8A677CD4A4468A5DF249B9C0611F5E31DE60DBA86BCB69C38D0EED3931A61E379136E52FB7D39B30B5FA29CA5205D8B6A8101E666779EF3D99B196B4F54AA43F682B53FA5BE8986A7086D4C75975DCB22640DD8ACFAEBA7C8D72058AC997F4EB72F824FD45C55C29C0834AB0D629B56F191A4BB16CDA0694141DC64DAACEF8F923FDC8F3734FA5CE59E7034C2D9237358084259D10134C0A13C2098847630B656179B1F7DB61674D1B705A10E41A7F215D0D865A46E6BC2850642BA413C55C5")),Binary("0x" & _BigHex_Swap_endian("C7C6000BB7C3E10D0440AB2BE592D5F0A7D7899A721A256C0554CF3989D77C1AC1BCC27F9CF4884033A16D0CA8B478A9B2DCB92B6A5993AD3E303D971F1539C8AD306697BA08B340EEAD98D4C462B5E77DF9615F0DA5ED5DFA5B6167AD19D6C6A06AAD1ED71E8E1B7A99F9F3E3838DE7F51F0B2C5AE3D2B784C55A29AAB8A8CF")),Binary("0x" & _BigHex_Swap_endian("AF54BA9A2567F5AD9BC29158786F9E7264DDB487E8750B1E2455121383CE487EA2F1E43842D42864830063FCD906B521F6DE05CACBD8CC5886486DFA51DFB6D404F5168F26B5508F6F71D937C27A0EF90300A60B9293AB00B3D2917C65D2B7AFDC5635F0AC721622307DF3D846F501CA1125D567D4178929CFF93281202345F3")),0,1,"Legacy")
 

Global Const $tagRSAPUBKEY = _
                "align 1;" & _
                "char magic[4];" & _
                "uint bitlen;" & _
                "uint PubExpLength;" & _
                "uint ModulusLength;" & _
                "uint PLength;" & _
                "uint QLength;" & _
                "byte PubExp[3];" & _
                "byte Modulus[1];"

Global Const $tagRSAPRIVATEKEY = _
                "align 1;" & _
                "char magic[4];" & _
                "uint bitlen;" & _
                "uint PubExpLength;" & _
                "uint ModulusLength;" & _
                "uint PLength;" & _
                "uint QLength;" & _
                "byte PubExp[3];" & _
                "byte Modulus[1];" & _
                "byte P[1];" & _
                "byte q[1];"

Global Const $tagRSAPRIVATEKEY_Legacy = _
                "byte bType[1];" & _    
                "byte bVersion[1];" & _ 
                "word reserved[1];" & _
                "byte aiKeyAlg[4];" & _ 
                "char magic[4];" & _
                "uint bitlen;" & _
                "byte PubExp[4];" & _
                "byte Modulus[1];" & _
                "byte p[1];" & _
                "byte q[1];" & _
                "byte exponent1[1];" & _ 
                "byte exponent2[1];" & _ 
                "byte coefficient[1];" & _ 
                "byte privateExponent[1];" 

Global Const $tagRSAPUBKEY_Legacy = _
                "byte bType[1];" & _    
                "byte bVersion[1];" & _
                "word reserved[1];" & _
                "byte aiKeyAlg[4];" & _ 
                "char magic[4];" & _
                "uint bitlen;" & _
                "byte PubExp[4];" & _
                "byte Modulus[1];"

Func _BigNum_inverse($a, $b)
        $result = 0
    Local $array[0][2], $cc = 1

    While 1
        If Mod($cc, 2) = 1 Then
            _ArrayAdd($array, $b & "|" & $a)
        Else
            _ArrayAdd($array, $a & "|" & $b)
        EndIf
        $cc += 1

        $result = _BigNum_Mod($a, $b)
                If $result <> 0 Then
            $a = $b
            $b = $result
        Else            
            ExitLoop
        EndIf

    WEnd

    $cc = 1
    Local $d = "", $k = ""
    For $i = UBound($array) - 1 To 0 Step -1

        If $cc = 1 Then
            If $array[$i][0] = 1 Then
                $d = 1
            Else
                $d = 1
                $k = $array[$i][0] - 1
            EndIf
        EndIf

        If $cc <> 1 Then
            If $k = "" Then
                $k = _BigNum_Div((_BigNum_Sub(_BigNum_Mul($array[$i][0], $d), 1)), $array[$i][1])
            Else
                $d = _BigNum_Div((_BigNum_Add(_BigNum_Mul($array[$i][1], $k), 1)), $array[$i][0])
                $k = ""
            EndIf
        EndIf

        $cc += 1

    Next

    Return $d
EndFunc  

Func _BigHex_Swap_endian($data)
        $result = ""

        if IsBinary($data) Then
        $data = Hex($data,BinaryLen($data))
        EndIf

        if Mod(StringLen($data),2) <> 0 Then
        $data = "0" & $data
        EndIf

        for $i = 1 to StringLen($data) step 2
        $result = StringMid($data,$i,2) & $result
        Next

        Return $result

EndFunc


Func _BigNum_ToBase2($iDec, $base = 16 , $checkfirstzero = 0)
    $base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ;base64
    ;Sexagesimal
    $base60_2 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx" ;sexagesimal
    $base32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" ;base32
    $base24 = "0123456789ABCDEFGHJKLMNP" ;base24
    $base16 = "0123456789ABCDEF" ;hex
    ;Duodecimal system or dozenal
    $base12 = "0123456789AB" ;duodecimal
    $base10 = "0123456789" ;base10
    $base8 = "01234567" ;oct
    $base2 = "01" ;binary

    If $base = 2 Then
        $Symbol = $base2
    ElseIf $base = 8 Then
        $Symbol = $base8
    ElseIf $base = 10 Then
        $Symbol = $base10
    ElseIf $base = 16 Then
        $Symbol = $base16
    ElseIf $base = 60 Then
        $Symbol = $base60_2
    ElseIf $base = 64 Then
        $Symbol = $base64
    EndIf


    Local $Out, $ost
    $Symbol = StringSplit($Symbol, '')
    If @error Or $Symbol[0] < 2 Then Return SetError(1, 0, $iDec)
    Do
        $ost = _BigNum_Mod($iDec, $Symbol[0])
        $iDec = _BigNum_Div(_BigNum_Sub($iDec, $ost), $Symbol[0])
        $Out = $Symbol[$ost + 1] & $Out
    Until Not Number($iDec)
    if $checkfirstzero = 1 Then
        if Mod(StringLen($Out),2) <> 0 Then
            $Out = "0" & $Out
        EndIf
    EndIf
    Return SetError(0, $Symbol[0], $Out)
EndFunc


Func _BigHex_ToBase2($sDecimal, $iBase)
    Local $vDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!""#$%&'()*+,-./:;<=>?@[\]^_`{|}~" ; 96 ASCII symbols, use Unicode for more  94個字元
    If $iBase > StringLen($vDigits) Then SetError(1, 0, 0)
    $vDigits = StringSplit($vDigits, '', 2)
    Local $sResult = 0
    For $i = 1 To StringLen($sDecimal)
        $nn = _ArraySearch($vDigits, StringMid($sDecimal, $i, 1))
        $sResult = _BigNum_Add(_BigNum_Mul($iBase, $sResult), $nn)
    Next
    Return $sResult
EndFunc





Func Read_to_Blob($key_path ,$tag = "Public", $tag2 = "new" , $type = "File" , $showdata = 1)
Local $returndata[2]

if $type <> "File" Then
$blob_b = $key_path
Else
Local $hFile = FileOpen($key_path,$FO_BINARY)
Local $blob_b = FileRead($hFile)
FileClose($hFile)
EndIf

Local $blob_handle = DllStructCreate("byte a["&BinaryLen($blob_b)&"];")
$blob_handle.a = $blob_b
if $tag2 = "new" Then
    if $tag = "Public" Then
        Local $blob_data = DllStructCreate($tagRSAPUBKEY,DllStructGetPtr($blob_handle))
        Local $tagRSAPUBKEY2 = StringReplace($tagRSAPUBKEY,"Modulus[1]","Modulus["&$blob_data.bitlen/8&"]")
        $blob_data = DllStructCreate($tagRSAPUBKEY2,DllStructGetPtr($blob_handle))
        

        $returndata[1] = $tagRSAPUBKEY2

        if $showdata = 1 Then
        _WinAPI_DisplayStruct($blob_data,$tagRSAPUBKEY2)
        EndIf
    Else
        Local $blob_data = DllStructCreate($tagRSAPRIVATEKEY,DllStructGetPtr($blob_handle))
        Local $tagRSAPRIVATEKEY2 = StringReplace($tagRSAPRIVATEKEY,"Modulus[1]","Modulus["&$blob_data.bitlen/8&"]")
        $tagRSAPRIVATEKEY2 = StringReplace($tagRSAPRIVATEKEY2,"p[1]","p["&$blob_data.bitlen/8/2&"]")
        $tagRSAPRIVATEKEY2 = StringReplace($tagRSAPRIVATEKEY2,"q[1]","q["&$blob_data.bitlen/8/2&"]")
        $blob_data = DllStructCreate($tagRSAPRIVATEKEY2,DllStructGetPtr($blob_handle))
        

        $returndata[1] = $tagRSAPRIVATEKEY2

        if $showdata = 1 Then
        _WinAPI_DisplayStruct($blob_data,$tagRSAPRIVATEKEY2)
        EndIf
    EndIf
Else
    if $tag = "Public" Then
        Local $blob_data = DllStructCreate($tagRSAPUBKEY_Legacy,DllStructGetPtr($blob_handle))
        Local $tagRSAPUBKEY2_Legacy = StringReplace($tagRSAPUBKEY_Legacy,"Modulus[1]","Modulus["&$blob_data.bitlen/8&"]")
        $blob_data = DllStructCreate($tagRSAPUBKEY2_Legacy,DllStructGetPtr($blob_handle))
        

        $returndata[1] = $tagRSAPUBKEY2_Legacy

        if $showdata = 1 Then
        _WinAPI_DisplayStruct($blob_data,$tagRSAPUBKEY2_Legacy)
        EndIf
    Else
        Local $blob_data = DllStructCreate($tagRSAPRIVATEKEY_Legacy,DllStructGetPtr($blob_handle))
        Local $tagRSAPRIVATEKEY2_Legacy = StringReplace($tagRSAPRIVATEKEY_Legacy,"Modulus[1]","Modulus["&$blob_data.bitlen/8&"]")
        $tagRSAPRIVATEKEY2_Legacy = StringReplace($tagRSAPRIVATEKEY2_Legacy,"p[1]","p["&$blob_data.bitlen/8/2&"]")
        $tagRSAPRIVATEKEY2_Legacy = StringReplace($tagRSAPRIVATEKEY2_Legacy,"q[1]","q["&$blob_data.bitlen/8/2&"]")
        $tagRSAPRIVATEKEY2_Legacy = StringReplace($tagRSAPRIVATEKEY2_Legacy,"exponent1[1]","exponent1["&$blob_data.bitlen/8/2&"]")
        $tagRSAPRIVATEKEY2_Legacy = StringReplace($tagRSAPRIVATEKEY2_Legacy,"exponent2[1]","exponent2["&$blob_data.bitlen/8/2&"]")
        $tagRSAPRIVATEKEY2_Legacy = StringReplace($tagRSAPRIVATEKEY2_Legacy,"coefficient[1]","coefficient["&$blob_data.bitlen/8/2&"]")
        $tagRSAPRIVATEKEY2_Legacy = StringReplace($tagRSAPRIVATEKEY2_Legacy,"privateExponent[1]","privateExponent["&$blob_data.bitlen/8&"]")
        $blob_data = DllStructCreate($tagRSAPRIVATEKEY2_Legacy,DllStructGetPtr($blob_handle))
        

        $returndata[1] = $tagRSAPRIVATEKEY2_Legacy

        if $showdata = 1 Then
        _WinAPI_DisplayStruct($blob_data,$tagRSAPRIVATEKEY2_Legacy)
        EndIf

        
    EndIf
EndIf

$returndata[0] = $blob_data
Return $returndata

EndFunc


Func Create_to_Blob($key_path,$tag = "Public" , $bitlen = 2048, $e = 65537, $Modulus = Binary("0x00"), $p = Binary("0x00"), $q = Binary("0x00") ,$write_or_binary = 1, $show = 0, $tag2 = "new")

if $tag2 = "new" Then
    if $tag = "Public" Then
        Local $tagRSAPUBKEY2 = StringReplace($tagRSAPUBKEY,"Modulus[1]","Modulus["&$bitlen/8&"]")
        Local $blob_data = DllStructCreate($tagRSAPUBKEY2)
        $blob_data.magic = "RSA1" 
        $blob_data.bitlen = $bitlen 
        $blob_data.PubExpLength = 3 
        $blob_data.ModulusLength = $blob_data.bitlen/8 
        $blob_data.PLength = 0 
        $blob_data.QLength = 0 
        $blob_data.PubExp = $e 
        $blob_data.Modulus = $Modulus 

        if $show = 1 Then
            _WinAPI_DisplayStruct($blob_data,$tagRSAPUBKEY2)
        EndIf

    Else
        Local $tagRSAPRIVATEKEY2 = StringReplace($tagRSAPRIVATEKEY,"Modulus[1]","Modulus["&$bitlen/8&"]")
        $tagRSAPRIVATEKEY2 = StringReplace($tagRSAPRIVATEKEY2,"p[1]","p["&$bitlen/8/2&"]")
        $tagRSAPRIVATEKEY2 = StringReplace($tagRSAPRIVATEKEY2,"q[1]","q["&$bitlen/8/2&"]")
        Local $blob_data = DllStructCreate($tagRSAPRIVATEKEY2)
        $blob_data.magic = "RSA2" 
        $blob_data.bitlen = $bitlen 
        $blob_data.PubExpLength = 3 
        $blob_data.ModulusLength = $blob_data.bitlen/8 
        $blob_data.PLength = $blob_data.bitlen/8/2 
        $blob_data.QLength = $blob_data.bitlen/8/2 
        $blob_data.PubExp = $e 
        $blob_data.Modulus = $Modulus 
        $blob_data.p = $p 
        $blob_data.q = $q 

        if $show = 1 then
            _WinAPI_DisplayStruct($blob_data,$tagRSAPRIVATEKEY2)
        EndIf

    EndIf
Else
    if $tag = "Public" Then
        Local $tagRSAPUBKEY_Legacy2 = StringReplace($tagRSAPUBKEY_Legacy,"Modulus[1]","Modulus["&$bitlen/8&"]")
        Local $blob_data = DllStructCreate($tagRSAPUBKEY_Legacy2)
        $blob_data.bType = 0x06 
        $blob_data.bVersion = 0x02
        $blob_data.aiKeyAlg = Binary("0x00A40000")
        $blob_data.magic = "RSA1"
        $blob_data.bitlen = $bitlen 
        $blob_data.PubExp =  Binary("0x" & _BigHex_Swap_endian(_BigNum_ToBase2($e,16,1))) 
        $blob_data.Modulus = Binary("0x" & _BigHex_Swap_endian($Modulus)) 

        if $show = 1 Then
            _WinAPI_DisplayStruct($blob_data,$tagRSAPUBKEY_Legacy2)
        EndIf

    Else

        Local $tagRSAPRIVATEKEY_Legacy2 = StringReplace($tagRSAPRIVATEKEY_Legacy,"Modulus[1]","Modulus["&$bitlen/8&"]")
        $tagRSAPRIVATEKEY_Legacy2 = StringReplace($tagRSAPRIVATEKEY_Legacy2,"p[1]","p["&$bitlen/8/2&"]")
        $tagRSAPRIVATEKEY_Legacy2 = StringReplace($tagRSAPRIVATEKEY_Legacy2,"q[1]","q["&$bitlen/8/2&"]")
        $tagRSAPRIVATEKEY_Legacy2 = StringReplace($tagRSAPRIVATEKEY_Legacy2,"exponent1[1]","exponent1["&$bitlen/8/2&"]")
        $tagRSAPRIVATEKEY_Legacy2 = StringReplace($tagRSAPRIVATEKEY_Legacy2,"exponent2[1]","exponent2["&$bitlen/8/2&"]")
        $tagRSAPRIVATEKEY_Legacy2 = StringReplace($tagRSAPRIVATEKEY_Legacy2,"coefficient[1]","coefficient["&$bitlen/8/2&"]")
        $tagRSAPRIVATEKEY_Legacy2 = StringReplace($tagRSAPRIVATEKEY_Legacy2,"privateExponent[1]","privateExponent["&$bitlen/8&"]")
        Local $blob_data = DllStructCreate($tagRSAPRIVATEKEY_Legacy2)
        $blob_data.bType = 0x07 
        $blob_data.bVersion = 0x02
        $blob_data.aiKeyAlg = Binary("0x00A40000")
        $blob_data.magic = "RSA2" 
        $blob_data.bitlen = $bitlen 
        $blob_data.PubExp = Binary("0x" & _BigHex_Swap_endian(_BigNum_ToBase2($e,16,1)))
        $blob_data.Modulus = Binary("0x" & _BigHex_Swap_endian($Modulus)) 
        $blob_data.p = Binary("0x" & _BigHex_Swap_endian($p)) 
        $blob_data.q = Binary("0x" & _BigHex_Swap_endian($q)) 
        Local $D = _BigNum_inverse(_BigNum_Mul(_BigNum_Sub(_BigHex_ToBase2(Hex($p), 16),1),_BigNum_Sub(_BigHex_ToBase2(Hex($q), 16),1)),$e)
        $blob_data.exponent1 = Binary("0x" &_BigHex_Swap_endian(_BigNum_ToBase2(_BigNum_mod($D,_BigNum_Sub(_BigHex_ToBase2(Hex($p), 16),1)),16,1)))
        $blob_data.exponent2 = Binary("0x" &_BigHex_Swap_endian(_BigNum_ToBase2(_BigNum_mod($D,_BigNum_Sub(_BigHex_ToBase2(Hex($q), 16),1)),16,1))) 
        $blob_data.coefficient =  Binary("0x" &_BigHex_Swap_endian(_BigNum_ToBase2(_BigNum_inverse(_BigHex_ToBase2(Hex($p), 16) , _BigHex_ToBase2(Hex($q), 16)),16,1)))
        $blob_data.privateExponent = Binary("0x" &_BigHex_Swap_endian(_BigNum_ToBase2($D,16,1))) 


        if $show = 1 then
            _WinAPI_DisplayStruct($blob_data,$tagRSAPRIVATEKEY_Legacy2)
        EndIf

    EndIf

EndIf


Local $blob_binary = DllStructCreate("byte a["&DllStructGetSize($blob_data)&"];",DllStructGetPtr($blob_data))

if $write_or_binary = 1 Then
$hFile = FileOpen($key_path,$FO_BINARY+$FO_OVERWRITE)
FileWrite($hFile,$blob_binary.a)
FileClose($hFile)
Else
Return $blob_binary.a
EndIf



EndFunc

Func __CryptoNG_BcryptImportKeyPair($hAlgorithmProvider, $sKeyBlobFile, $sKeyBlobType, $Key_type = "file" )

    If $__gbDebugging Then _DebugOut(@CRLF & "Function: __CryptoNG_BcryptImportKeyPair()")

    Local $aResult[0]

    Local $iError          = 0, _
          $iStatusCode     = 0

    Local $tBuffer = ""

    Local $hFile = -1, _
          $hKey  = -1

    Local $xKeyBlob = Binary("")


    ;Make sure file exists
    if $Key_type = "file" Then
    If Not FileExists($sKeyBlobFile) Then Return SetError(3, 0, "")


    ;Read binary blob file
    $hFile = FileOpen($sKeyBlobFile, $FO_BINARY)
    If $hFile = -1 Then Return SetError(4, 0, "")

    $xKeyBlob = FileRead($hFile)
    FileClose($hFile)
    Else
    $xKeyBlob = $sKeyBlobFile
    EndIf

    ;Create a binary buffer, containing key blob, to pass to function
    $tBuffer      = DllStructCreate(StringFormat("byte data[%i]", BinaryLen($xKeyBlob)))
    $tBuffer.data = $xKeyBlob

    If $__gbDebugging Then _DebugReportVar("Public/Private Key Blob", $tBuffer.data)


    ;Import key pair
    $aResult = DllCall(__CryptoNG_GetBcryptDllHandle(), "int", "BCryptImportKeyPair", _
                       "handle",   $hAlgorithmProvider, _
                       "handle",   Null, _
                       "wstr",     $sKeyBlobType, _
                       "handle*",  Null, _
                       "struct*",  $tBuffer, _
                       "ulong",    DllStructGetSize($tBuffer), _
                       "ulong",    $CNG_BCRYPT_NO_KEY_VALIDATION _
                       )
    If @error Then
        $iError = @error
        $__gsLastErrorMessage = __CryptoNG_DllCallErrorMessage($iError)
        Return SetError(1, $iError, "")
    EndIf

    If $__gbDebugging Then _DebugReportVar("BCryptImportKeyPair $aResult", $aResult)


    ;Get returned values from dllcall
    $iStatusCode = $aResult[0]
    $hKey        = $aResult[4]


    ;Check status code from dllcall
    If $iStatusCode <> $CNG_STATUS_SUCCESS Then
        $__gsLastErrorMessage = __CryptoNG_StatusMessage($iStatusCode)
        Return SetError(2, $iStatusCode, "")
    EndIf


    ;All is good, return handle pointer
    Return $hKey

EndFunc

Func _CryptoNG_RSA_EncryptData($sText, $sPublicKeyBlobFile, $iPadding = Default, $sProvider = Default ,$Key_type = "file")

    If $__gbDebugging Then _DebugOut(@CRLF & "Function: _CryptoNG_RSA_EncryptData()")

    Local $hAlgorithmProvider = -1, _
          $hEncryptionKey     = -1

    Local $xEncryptedText = ""


    ;Resolve defaults
    If $sProvider = Default Then $sProvider = "Microsoft Primitive Provider"
    If $iPadding  = Default Then $iPadding  = $CNG_BCRYPT_PAD_PKCS1

    ;Make sure that text is not blank
    If $sText = "" Then
        $__gsLastErrorMessage = "Invalid parameter - Text cannot be blank."
        Return SetError(-1, 0, "")
    EndIf


    ;Make sure that key blob file exists
    if $Key_type = "file" Then
    If Not FileExists($sPublicKeyBlobFile) Then
        $__gsLastErrorMessage = "Public key blob file does not exist."
        Return SetError(-2, 0, "")
    EndIf
    EndIf

    ;Open algorithm provider
    $hAlgorithmProvider = __CryptoNG_BCryptOpenEncryptionAlgorithmProvider($CNG_BCRYPT_RSA_ALGORITHM, $sProvider)
    If @error Then Return SetError(2, 0, "")

    ;Import rsa public key
    $hEncryptionKey = __CryptoNG_BcryptImportKeyPair($hAlgorithmProvider, $sPublicKeyBlobFile, $CNG_BCRYPT_RSAPUBLIC_BLOB, $Key_type)
    If @error Then
        If $hAlgorithmProvider <> -1 Then __CryptoNG_BcryptCloseAlgorithmProvider($hAlgorithmProvider)
        Return SetError(3, 0, "")
    EndIf

    ;Encrypt data
    $xEncryptedText = __CryptoNG_BCryptEncrypt_RSA($CNG_BCRYPT_RSA_ALGORITHM, $sText, $hEncryptionKey, $iPadding)
    If @error Then
        If $hAlgorithmProvider <> -1 Then __CryptoNG_BcryptCloseAlgorithmProvider($hAlgorithmProvider)
        If $hEncryptionKey     <> -1 Then __CryptoNG_BcryptDestroyKey($hEncryptionKey)
        Return SetError(4, 0, "")
    EndIf

    ;Clean up
    If $hAlgorithmProvider <> -1 Then __CryptoNG_BcryptCloseAlgorithmProvider($hAlgorithmProvider)
    If $hEncryptionKey     <> -1 Then __CryptoNG_BcryptDestroyKey($hEncryptionKey)

    Return $xEncryptedText

EndFunc

 

Posted
7 hours ago, konya said:

...hoping to be helpful to you.

As is, it is not.
You could take all you posted here and put it in the examples section, and in the place of this post, a link to the examples area post.

Also add a link in the code for users to find the includes

#include <bignum.au3> ; https://get it from here

and add comments for the reader of the post, to have context as otherwise, ...what is this and what does it solve.

Thanks

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting  image.gif.922e3a93535f431de08b31ee669cc446.gif
autoit_scripter_blue_userbar.png

  • 1 year later...
Posted

In doing some experimenting with this I found a bit of a bug in _CryptoNG_CryptBinaryToString in that there's a crash if the binary size goes over about 65536 bytes.  Here's code that demonstrates this limit.  Output from the script show this: 

CryptoNG 2.4.0 | AutoIt 3.3.18.0 x86 | WIN_11 build 22631

Encoding   10000 bytes (expect   13336 Base64 chars)... ok, got 13336 chars
Encoding   30000 bytes (expect   40000 Base64 chars)... ok, got 40000 chars
Encoding   45000 bytes (expect   60000 Base64 chars)... ok, got 60000 chars
Encoding   48000 bytes (expect   64000 Base64 chars)... ok, got 64000 chars
Encoding   49000 bytes (expect   65336 Base64 chars)... ok, got 65336 chars
Encoding   49152 bytes (expect   65536 Base64 chars)... ok, got 65536 chars
Encoding   50000 bytes (expect   66668 Base64 chars)... !>21:39:38 AutoIt3.exe ended.rc:-1073741819
+>21:39:38 AutoIt3Wrapper Finished.

 

;================================================================================================================================
; CryptoNG_B64_CrashDemo.au3
;
; Demonstrates a hard process crash (access violation, no @error possible) in
; _CryptoNG_CryptBinaryToString when the binary input is larger than ~49 KB.
;
; Observed with: CryptoNG 2.4.0, AutoIt 3.3.18.0 (x86), Windows 11 build 22631
;
; Each attempt is announced on the console BEFORE the call is made, so when
; the process dies, the last line printed identifies the failing size.
;
; Expected Base64 length for n bytes = ceil(n/3)*4. The crash begins right
; around the size where that figure exceeds 65,535 characters (~49,151 bytes
; of input), which points at AutoIt's documented DllCall "str"/"wstr" buffer
; limit of 65,536 characters.
;================================================================================================================================

#include "CryptoNG.au3"

ConsoleWrite("CryptoNG " & $CNG_VERSION & " | AutoIt " & @AutoItVersion & (@AutoItX64 ? " x64" : " x86") & _
             " | " & @OSVersion & " build " & @OSBuild & @CRLF & @CRLF)

Local $aSizes[8] = [10000, 30000, 45000, 48000, 49000, 49152, 50000, 100000]
Local $iFlags = BitOR($CNG_CRYPT_STRING_BASE64, $CNG_CRYPT_STRING_NOCRLF)

For $i = 0 To UBound($aSizes) - 1

    Local $iBytes = $aSizes[$i]
    Local $iExpectedChars = Int(($iBytes + 2) / 3) * 4

    Local $xData = _CryptoNG_GenerateRandom($CNG_BCRYPT_RNG_ALGORITHM, $iBytes)
    If @error Then
        ConsoleWrite("GenerateRandom failed @error=" & @error & @CRLF)
        ExitLoop
    EndIf

    ;Announce BEFORE the call - if the process dies, this is the failing size
    ConsoleWrite(StringFormat("Encoding %7i bytes (expect %7i Base64 chars)... ", $iBytes, $iExpectedChars))

    Local $sBase64 = _CryptoNG_CryptBinaryToString($xData, $iFlags)
    If @error Then
        ConsoleWrite("returned @error=" & @error & " @extended=" & @extended & @CRLF)
    Else
        ConsoleWrite("ok, got " & StringLen($sBase64) & " chars" & @CRLF)
    EndIf

Next

ConsoleWrite(@CRLF & "Script completed without crashing." & @CRLF)

Here are AI generated versions (Claude/Fable 5) that don't exhibit the same issue:

Func __AesGcm_CryptBinaryToString($xData, $iStringFormat)

    Local $aRet

    ;Validate parameters
    If Not IsBinary($xData) Then Return SetError(-1, 0, "")

    Local $iDataLen = BinaryLen($xData)

    ;Copy binary into a struct buffer
    Local $tData = DllStructCreate("byte data[" & $iDataLen & "]")
    DllStructSetData($tData, "data", $xData)

    ;Call 1 - query required output size (in WCHARs, includes null terminator)
    $aRet = DllCall("crypt32.dll", "bool", "CryptBinaryToStringW", _
                    "struct*", $tData, "dword", $iDataLen, "dword", $iStringFormat, _
                    "ptr", 0, "dword*", 0)
    If @error Then Return SetError(1, @error, "")
    If Not $aRet[0] Then Return SetError(2, 0, "")
    Local $iChars = $aRet[5]

    ;Call 2 - convert into a struct-backed output buffer (no wstr size limit)
    Local $tOut = DllStructCreate("wchar text[" & $iChars & "]")
    $aRet = DllCall("crypt32.dll", "bool", "CryptBinaryToStringW", _
                    "struct*", $tData, "dword", $iDataLen, "dword", $iStringFormat, _
                    "struct*", $tOut, "dword*", $iChars)
    If @error Then Return SetError(1, @error, "")
    If Not $aRet[0] Then Return SetError(2, 0, "")

    Return DllStructGetData($tOut, "text")

EndFunc   ;==>__AesGcm_CryptBinaryToString
;=================================================================
Func __AesGcm_CryptStringToBinary($sData, $iStringFormat)

    Local $aRet

    ;Validate parameters
    If Not IsString($sData) Or $sData = "" Then Return SetError(-1, 0, "")

    Local $iChars = StringLen($sData)

    ;Copy the string into a struct buffer (avoids the wstr input limit too)
    Local $tIn = DllStructCreate("wchar text[" & ($iChars + 1) & "]")
    DllStructSetData($tIn, "text", $sData)

    ;Call 1 - query required output size (also validates the input format)
    $aRet = DllCall("crypt32.dll", "bool", "CryptStringToBinaryW", _
                    "struct*", $tIn, "dword", $iChars, "dword", $iStringFormat, _
                    "ptr", 0, "dword*", 0, "ptr", 0, "ptr", 0)
    If @error Then Return SetError(1, @error, "")
    If Not $aRet[0] Then Return SetError(2, 0, "")
    Local $iBytes = $aRet[5]

    ;Call 2 - convert into a struct-backed output buffer
    Local $tOut = DllStructCreate("byte data[" & $iBytes & "]")
    $aRet = DllCall("crypt32.dll", "bool", "CryptStringToBinaryW", _
                    "struct*", $tIn, "dword", $iChars, "dword", $iStringFormat, _
                    "struct*", $tOut, "dword*", $iBytes, "ptr", 0, "ptr", 0)
    If @error Then Return SetError(1, @error, "")
    If Not $aRet[0] Then Return SetError(2, 0, "")

    ;$aRet[5] (the 5th parameter, the dword* byte count) holds the actual bytes written
    Return BinaryMid(DllStructGetData($tOut, "data"), 1, $aRet[5])

EndFunc   ;==>__AesGcm_CryptStringToBinary

 

Posted

I decided to dig a little deeper into the CryptoNG 2.4.0 UDF with AI to identify potential issues with the code.  I sent the entire CryptoNG.au3 to Claude and asked for a validation.  After analyzing the multiple thousands of lines of code, the result was about a half dozen bugs.  That's absolutely amazing!! - if *I* was going to write a few thousand lines of code, I guarantee that the bug count would be exponentially higher, and that says a lot about the quality of TheXMan's work.  I love this UDF, and I appreciate all the time and extensive effort that's gone into maintaining it all these years.  I also want to do what I can to help improve things when possible.  As such, here's a list of the issues that were identified by AI.  I've looked at them and they appear to me to be legit, however it's always good for more eyes to take a look.

1. Wrong conversion in __CryptoNG_BCryptHashData (line 6027) — affects hash correctness.
   Function __CryptoNG_BCryptHashData 
    ;Create a data buffer and move hash data to it
    If IsString($vData) Then
        ; Original: $xData = BinaryToString($vData, $SB_UTF8) 
        ; Patched: $xData = StringToBinary($vData, $SB_UTF8)
    Else
        $xData = Binary($vData)
    EndIf
    
2. _CryptoNG_EnumKeyStorageProvider () returns N copies of the first provider (line 2902)
Const $NCRYPT_KSP_NAME_SIZE = DllStructGetSize($tagNCRYPT_KSP_NAME) 
Corrected: Const  $NCRYPT_KSP_NAME_SIZE = DllStructGetSize(DllStructCreate($tagNCRYPT_KSP_NAME))
DllStructGetSize is being given the tag string, not a struct, so it fails and returns 0. 
The loop then steps through the struct array with a stride of 0 and every iteration reads the same first entry.

3. "Provider" is silently ignored in 10 public functions.∗∗
 These accept and document a Provider parameter but never pass it to  __CryptoNG_BCryptOpenEncryptionAlgorithmProvider, so they always use the Microsoft Primitive Provider: 
 _CryptoNG_3DES_CBC_DecryptData
 _CryptoNG_AES_CBC_DecryptData
 _CryptoNG_AES_ECB_DecryptData
 _CryptoNG_AES_GCM_DecryptData
 _CryptoNG_DecryptData
 _CryptoNG_ECDSA_SignHash
 _CryptoNG_ECDSA_VerifySignature
 _CryptoNG_RSA_DecryptData
 _CryptoNG_RSA_SignHash
 _CryptoNG_RSA_VerifySignature
 Notice the asymmetry: the *Encrypt* variants pass it, the *Decrypt/Sign/Verify* variants mostly don't. Harmless with the default provider, but if you ever specify one, encrypt and decrypt could run on different providers without any error.
 
4. Resource leaks + wrong return type in the IV/nonce validation paths.** 
In the four `*_CBC_*File` functions, the IV length check happens *after* the input/output files are opened 
and the key handle is generated, but the failure path only closes the algorithm provider, so
the two file handles and the key handle leak. The output file is also left created-but-empty on disk. 
On top of that, these paths Return SetError(8, 0, "") when every other failure in those functions returns False, so a caller testing 
"If Not result" gets inconsistent behavior( and False both test falsy, but result = False comparisons and the documented contract break).
 The same key-handle leak exists in _CryptoNG_3DES_CBC_DecryptData / _CryptoNG_AES_CBC_DecryptData (IV checked after key generation) and in both AES-GCM functions (nonce/auth-tag checked after key generation. Simplest fix is to move the IV/nonce validation up before any handles are opened — it doesn't depend on them.
 
5. Dead constant-vs-constant comparisons. Lines 601, 832, 1063, 1310: If $CNG_BCRYPT_3DES_ALGORITHM <> $CNG_BCRYPT_RC4_ALGORITHM Then (and the AES equivalent) compare two literals — always true. Harmless, but not necessary.

6. Minor items:

__CryptoNG_BCryptCreateHash closes the algorithm provider on a DllCall failure, but every caller also closes it in their error path → double close of the same handle.

In _CryptoNG_ECDSA_CreateKeyPair / _CryptoNG_RSA_CreateKeyPair(Ex), the FileWrite failure paths return without FileClose($hFile).

__CryptoNG_IsAuthTagByteLengthValid does Mod($iAuthTagBytes, dwIncrement) without the dwIncrement <> 0 guard that its sibling __CryptoNG_IsKeyBitLengthValid has — divide-by-zero if a provider ever reports increment 0.

_CryptoNG_CryptBinaryToString uses a "wstr" return buffer, which AutoIt caps at 65,535 characters; converting more than roughly 48 KB of binary to Base64 will truncate. If you ever feed it large blobs, switch the output to a wchar struct sized from the first call. It also returns False on DllCall error where the docs promise "".

__CryptoNG_BCryptSetProperty's string case passes BinaryLen($vValue) as cbInput — that's the ANSI byte count while the data is marshaled as wstr (UTF-16). It happens to work for chaining-mode strings because Windows only reads up to the declared length and the values are ASCII, but (StringLen($vValue) + 1) * 2 would be the correct size.

I also had AI generate a test script to verify CryptoNG output against known good test parameters; that code is below.

;================================================================================================================================
; CryptoNG_BugDemo.au3 - Known-answer test bed demonstrating bugs in CryptoNG v2.4.0
;
;
; Reference values come from published standards:
;   T1  FIPS 180-2          SHA-256("abc")
;   T2  RFC 4231 Test Case 2  HMAC-SHA256(key="Jefe", "what do ya want for nothing?")
;   T3  RFC 6070            PBKDF2-HMAC-SHA1("password", "salt", c=4096, dkLen=20)
;   T4  NIST SP 800-38A F.2.5  AES-256-CBC, first block
;   T5  SHA-256 of the UTF-8 bytes of "caf<e-acute>" (verify yourself: printf 'caf\xc3\xa9' | sha256sum)
;================================================================================================================================

#include "CryptoNG.au3"          

Global $g_iPass = 0, $g_iFail = 0

ConsoleWrite(@CRLF & "CryptoNG bug demo - UDF version " & _CryptoNG_Version() & @CRLF & @CRLF)

;--------------------------------------------------------------------------------------------------------------------
; T1-T4: CONTROLS. These use ASCII-only input and exercise code paths that are correct in v2.4.0.
;--------------------------------------------------------------------------------------------------------------------

; T1 - FIPS 180-2: SHA-256("abc")
Local $xHash = _CryptoNG_HashData($CNG_BCRYPT_SHA256_ALGORITHM, "abc")
Report("T1 CONTROL  SHA-256('abc')  [FIPS 180-2]", _
       HexOf($xHash), "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")

; T2 - RFC 4231 Test Case 2: HMAC-SHA256, key "Jefe"
$xHash = _CryptoNG_HashData($CNG_BCRYPT_SHA256_ALGORITHM, "what do ya want for nothing?", True, "Jefe")
Report("T2 CONTROL  HMAC-SHA256  [RFC 4231 TC2]", _
       HexOf($xHash), "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843")

; T3 - RFC 6070: PBKDF2-HMAC-SHA1("password", "salt", 4096 iterations, 20 bytes)
Local $xKey = _CryptoNG_PBKDF2("password", "salt", 4096, 160)   ; 160 bits = 20 bytes, default hash = SHA1
Report("T3 CONTROL  PBKDF2-HMAC-SHA1 c=4096  [RFC 6070]", _
       HexOf($xKey), "4b007901b765489abead49d926f721d065a429c1")

; T4 - NIST SP 800-38A F.2.5: AES-256-CBC, first ciphertext block
Local $xAesKey = Binary("0x603DEB1015CA71BE2B73AEF0857D77811F352C073B6108D72D9810A30914DFF4")
Local $xAesIV  = Binary("0x000102030405060708090A0B0C0D0E0F")
Local $xAesPT  = Binary("0x6BC1BEE22E409F96E93D7E117393172A")
Local $xCipher = _CryptoNG_AES_CBC_EncryptData($xAesPT, $xAesKey, $xAesIV)
Report("T4 CONTROL  AES-256-CBC block 1  [NIST SP 800-38A F.2.5]", _
       HexOf(BinaryMid($xCipher, 1, 16)), "f58c4c04d6e5f1ba779eabfb5f7bfbd6")

;--------------------------------------------------------------------------------------------------------------------
; T5: BUG #1 - __CryptoNG_BCryptHashData uses BinaryToString() instead of StringToBinary().
; Any string containing non-ASCII characters is hashed as ANSI bytes (or mangled), not UTF-8.
; "caf" & ChrW(233) is "caf<e-acute>"; its UTF-8 bytes are 63 61 66 C3 A9.
; Verify the expected digest yourself on any Linux box:  printf 'caf\xc3\xa9' | sha256sum
;--------------------------------------------------------------------------------------------------------------------
Local $sCafe = "caf" & ChrW(233)
$xHash = _CryptoNG_HashData($CNG_BCRYPT_SHA256_ALGORITHM, $sCafe)
Report("T5 BUG#1    SHA-256 of UTF-8 'caf" & ChrW(233) & "'", _
       HexOf($xHash), "850f7dc43910ff890f8879c0ed26fe697c93a067ad93a7d50f466a7028a9bf4e")
If HexOf($xHash) = "dafd66c0b98965e688be1fc12942c09f0350e6be0685017c3f234e97d0adc92e" Then _
    ConsoleWrite("            (actual value matches the ANSI/cp1252 digest - data was hashed as ANSI, not UTF-8)" & @CRLF)

;--------------------------------------------------------------------------------------------------------------------
; T6: BUG #1 cross-check needing NO external reference value: hashing the string directly must match
; hashing a UTF-8 file with the same content. (HashFile reads raw bytes, so it is unaffected by the bug.)
;--------------------------------------------------------------------------------------------------------------------
Local $sUtf8File = @TempDir & "\cng_demo_utf8.txt"
Local $hF = FileOpen($sUtf8File, $FO_OVERWRITE + 256)   ; 256 = $FO_UTF8_NOBOM
FileWrite($hF, $sCafe)
FileClose($hF)
Local $xFileHash = _CryptoNG_HashFile($CNG_BCRYPT_SHA256_ALGORITHM, $sUtf8File)
Report("T6 BUG#1    HashData(string) = HashFile(same content, UTF-8 file)", HexOf($xHash), HexOf($xFileHash))
FileDelete($sUtf8File)

;--------------------------------------------------------------------------------------------------------------------
; T7: BUG #3 - $sProvider is silently ignored by the Decrypt/Sign/Verify functions.
; Decrypting with a provider name that does not exist MUST fail; in v2.4.0 it "succeeds".
;--------------------------------------------------------------------------------------------------------------------
Local $sBogus = "Bogus Provider That Does Not Exist"
$xCipher = _CryptoNG_AES_CBC_EncryptData("provider test", $xAesKey, $xAesIV)

_CryptoNG_AES_CBC_EncryptData("provider test", $xAesKey, $xAesIV, $sBogus)
Report("T7a CONTROL Encrypt with bogus provider is rejected", (@error <> 0), True)

_CryptoNG_AES_CBC_DecryptData($xCipher, $xAesKey, $xAesIV, $sBogus)
Report("T7b BUG#3   Decrypt with bogus provider is rejected", (@error <> 0), True)

;--------------------------------------------------------------------------------------------------------------------
; T8: BUG #2 - _CryptoNG_EnumKeyStorageProviders steps through the result array with a stride of 0
; and returns N copies of the FIRST provider. A normal Windows box registers at least
; "Microsoft Software Key Storage Provider", "...Smart Card...", and "...Platform Crypto Provider".
;--------------------------------------------------------------------------------------------------------------------
Local $aKSP = _CryptoNG_EnumKeyStorageProviders()
If @error Or Not IsArray($aKSP) Then
    Report("T8 BUG#2    EnumKeyStorageProviders returns distinct entries", "call failed: " & _CryptoNG_LastErrorMessage(), "an array")
ElseIf UBound($aKSP) < 2 Then
    ConsoleWrite("T8 SKIPPED  only " & UBound($aKSP) & " key storage provider registered; cannot detect the stride bug" & @CRLF)
Else
    Local $bAllSame = True
    For $i = 1 To UBound($aKSP) - 1
        If $aKSP[$i] <> $aKSP[0] Then $bAllSame = False
    Next
    Report("T8 BUG#2    EnumKeyStorageProviders returns distinct entries (got " & UBound($aKSP) & ")", Not $bAllSame, True)
    For $i = 0 To UBound($aKSP) - 1
        ConsoleWrite("            [" & $i & "] " & $aKSP[$i] & @CRLF)
    Next
EndIf

;--------------------------------------------------------------------------------------------------------------------
; T9: BUG #4 - the bad-IV failure path in the CBC *File functions returns "" instead of the documented
; False, and leaks both file handles (so the files cannot be deleted afterwards) and the key handle.
;--------------------------------------------------------------------------------------------------------------------
Local $sPlainFile = @TempDir & "\cng_demo_plain.txt"
Local $sEncFile   = @TempDir & "\cng_demo_enc.bin"
Local $sDecFile   = @TempDir & "\cng_demo_dec.txt"
$hF = FileOpen($sPlainFile, $FO_OVERWRITE)
FileWrite($hF, "file handle leak test")
FileClose($hF)
_CryptoNG_AES_CBC_EncryptFile($sPlainFile, $sEncFile, $xAesKey, $xAesIV)

Local $vRet = _CryptoNG_AES_CBC_DecryptFile($sEncFile, $sDecFile, $xAesKey, Binary("0x00"))  ; 1-byte IV -> must fail
Local $iErr = @error
Report("T9a         Bad-IV decrypt sets @error = 8", $iErr, 8)
Report("T9b BUG#4   Bad-IV decrypt returns Bool False per docs (got type " & VarGetType($vRet) & ")", _
       (VarGetType($vRet) = "Bool" And $vRet = False), True)
Report("T9c BUG#4   Output file deletable afterwards (no leaked handle)", (FileDelete($sDecFile) = 1), True)
Report("T9d BUG#4   Input file deletable afterwards (no leaked handle)",  (FileDelete($sEncFile) = 1), True)
FileDelete($sPlainFile)

;--------------------------------------------------------------------------------------------------------------------
ConsoleWrite(@CRLF & StringFormat("RESULT: %i passed, %i failed", $g_iPass, $g_iFail) & @CRLF)
ConsoleWrite("Expected against ORIGINAL v2.4.0: T1-T4 and T7a pass; T5, T6, T7b, T8, T9b, T9c, T9d FAIL." & @CRLF)
ConsoleWrite("Expected against PATCHED copy:    everything passes." & @CRLF)

;=== helpers ====================================================================================================================
Func HexOf($xBin)
    Return StringLower(StringTrimLeft(String(Binary($xBin)), 2))
EndFunc

Func Report($sTest, $vActual, $vExpected)
    Local $bPass = ($vActual == $vExpected)
    If IsBool($vExpected) Then $bPass = ($vActual = $vExpected)
    If $bPass Then
        $g_iPass += 1
        ConsoleWrite("PASS  " & $sTest & @CRLF)
    Else
        $g_iFail += 1
        ConsoleWrite("FAIL  " & $sTest & @CRLF)
        ConsoleWrite("      expected: " & String($vExpected) & @CRLF)
        ConsoleWrite("      actual  : " & String($vActual) & @CRLF)
    EndIf
EndFunc

  

I hope this input helps to make a great UDF even better.  With today's technology it's much easier to identify issues than it was even a year or so ago.  I appreciate how much time and effort was required to create this UDF years ago and maintain it even now, and my post is by no means intended to make light of the tremendous amount of work that's gone into this code.  Times and tools are changing, and my hope is that we can keep quality code moving forward with modern tools while remembering that the hard work, done by actual people, is how we got to where we are today.  

Note to TheXman: I have a patched version of the 2.4.0 UDF that passes all the tests in the demo code posted here, and I'd be happy to send it to you for review if you want it. I won't post the entire code here as I believe revisions should be handled through "official" channels.  Thank you for all your effort in this awesome work.

 

 

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...