Cryptbinarytostring ошибка 0xd

does anyone know why this code is not working?

 #include "stdafx.h"
#include <windows.h>
#include <WinCrypt.h>


int _tmain(int argc, _TCHAR* argv[])
{
wchar_t *bin = TEXT("ProductID:1233===>55555");
BYTE out2[1000];
DWORD olen;
olen = 1000;

if (CryptStringToBinary(bin, 0, 1, out2, &olen, 0, 0) == 0)
{
    wprintf(TEXT("Failure\n"));
}
else
{
//wprintf(TEXT("rn%s\n"),out2);
    wprintf(TEXT("Success\n"));
}
system("pause");
    return 0;
}

Thank you very much in advance!

Tom

asked Jul 4, 2010 at 17:53

Tom Jones's user avatar

Tom JonesTom Jones

31 silver badge3 bronze badges

1

Because you specified a length (parameter 2) of 0?

Edit: Just to clarify our eventual solution in the comments below, the code in the original question (since edited) contained two errors:

  1. It was calling CryptBinaryToString instead of CryptStringToBinary. Since it’s invalid to pass a 0 in the second parameter to CryptBinaryToString, the function was failing.
  2. It was passing 1 in the third parameter (dwFlags), which is interpreted as CRYPT_STRING_BASE64. Since the string to encrypt wasn’t in base 64 (it contained invalid characters such as ‘:’), the function was failing. In general, passing a raw value instead of using an existing definition (e.g., CRYPT_STRING_BASE64) is not a good idea.

answered Jul 4, 2010 at 17:58

Emerick Rogul's user avatar

Emerick RogulEmerick Rogul

6,7063 gold badges32 silver badges39 bronze badges

8

  • Remove From My Forums
  • Question

  • I have a binary string which i want to convert to base64 string using CryptBinaryToString(). the function works and returns a base64 string but filled with ‘null’/’invalid’ bytes somewhere at the middle and end of string.

    //pData contains the binary string and it is the pointer to 'BYTE array' (LPBYTE).
    
    
    
    
    //pdwDataSize is the number of bytes in pData.
    
    
    
    
    dwBase64Size = 0; //Get the length of buffer to be allocated.
    
    
    
      
    CryptBinaryToStringA(pData, pdwDataSize,CRYPT_STRING_BASE64 , NULL, &dwBase64Size);
    
    //Allocate buffer
    
    
    
    
    LPSTR pBase64 = (LPSTR)malloc(dwBase64Size);
    
    CryptBinaryToStringA(pData, pdwDataSize, CRYPT_STRING_BASE64 , pBase64, &dwBase64Size);
    
    The result pBase64 contains the base64 string but with 'null' or invalid characters.
    

Answers

  • I developed a simple function BinaryToBase64 which takes as input a pointer to binary data and its size in bytes, and returns a CString instance containing the base64 string.
    (AtlThrow is used to signal errors.)
    This function is a simple wrapper to CryptBinaryToString function (using CRYPT_STRING_BASE64 flag).

    Considering that the CRYPT_STRING_NOCRLF flag is not supported on Windows Server 2003 and Windows XP, I developed a simple function to remove CR/LF pairs from strings.

    You can copy and paste the following compilable C++ code in an empty Win32 project created with Visual Studio 2008:

    //////////////////////////////////////////////////////////////////////////
    //
    // TestBase64.cpp
    //
    // by Giovanni Dicanio <giovanni DOT dicanio AT gmail.com>
    //
    // 2009, October 25th
    //
    //////////////////////////////////////////////////////////////////////////
    
    
    
    //========================================================================
    //                          INCLUDES
    //========================================================================
    
    
    #define WIN32_LEAN_AND_MEAN
    #define STRICT
    #include <Windows.h>        // Win32 Platform SDK
    #include <WinCrypt.h>       // CryptBinaryString function
    
    #include <atlbase.h>        // ATL library
    #include <atlstr.h>         // CString class from ATL
    
    
    #pragma comment(lib, "Crypt32.lib")
    
    
    
    //========================================================================
    //                    FUNCTION IMPLEMENTATIONS
    //========================================================================
    
    
    //------------------------------------------------------------------------
    // Converts binary data to a Base64 string.
    //------------------------------------------------------------------------
    CString BinaryToBase64(
        __in const BYTE * pbBinary, 
        __in DWORD cbBinary )
    {
        // Check input pointer
        ATLASSERT( pbBinary != NULL );
        if ( pbBinary == NULL )
            AtlThrow( E_POINTER );
    
        // Check input size
        ATLASSERT( cbBinary != 0 );
        if ( cbBinary == 0 )
            AtlThrow( E_INVALIDARG );
    
        // Request size of Base64 string
        DWORD cchBase64;
        if ( ! CryptBinaryToString(
            pbBinary,
            cbBinary,
            CRYPT_STRING_BASE64,
            NULL,
            &cchBase64
            ) )
        {
            AtlThrowLastWin32();
        }
    
        // Allocate a string with required size
        CString strBase64;
        LPTSTR pszBase64 = strBase64.GetBuffer( cchBase64 );
        ATLASSERT( pszBase64 != NULL );
    
        // Convert binary data to Base64
        if ( ! CryptBinaryToString(
            pbBinary,
            cbBinary,
            CRYPT_STRING_BASE64,
            pszBase64,
            &cchBase64
            ) )
        {
            AtlThrowLastWin32();
        }
    
        // Release CString buffer
        strBase64.ReleaseBuffer();
    
        // Return the converted string
        return strBase64;
    }
    
    
    //------------------------------------------------------------------------
    // Given an input string, removes the return/line feed (CR/LF) pairs
    // from it.
    // If the input string is NULL, just returns an empty string.
    //------------------------------------------------------------------------
    CString StripNewLines( __in LPCTSTR pszSource )
    {
        // Check input string pointer: 
        // returns empty string if input is NULL or empty.
        if ( ( pszSource == NULL ) || ( *pszSource == 0 ) )
            return TEXT("");
    
        // String without CR/LF pairs
        CString strResult;
     
        // Pointer to characters in input string
        const TCHAR * pchSource = pszSource;
    
        // Scan input string
        while ( *pchSource )
        {
            // Copy character to destination string if it is not a CR/LF (0x0D/0x0A) pair
            if ( *pchSource != 0x0D )
            {
                strResult.AppendChar( *pchSource );
    
                // Move to next character
                ++pchSource;
            }
            else
            {
                // We should have a LF (0x0A) following it
                ATLASSERT( *(pchSource + 1) == 0x0A );
    
                // Skip CR/LF
                pchSource++;
                pchSource++;
            }
        }
    
        // Return string without CR/LF pairs
        return strResult;
    }
    
    
    //------------------------------------------------------------------------
    // A simple test for BinaryToBase64 function.
    //------------------------------------------------------------------------
    void Test()
    {
        // Message copied from Wikipedia entry about Base64:
        // http://en.wikipedia.org/wiki/Base64
        //
        char szMessage[] = "Man is distinguished, not only by his reason, " \
            "but by this singular passion from other animals, which is a " \
            "lust of the mind, that by a perseverance of delight in the " \
            "continued and indefatigable generation of knowledge, exceeds " \
            "the short vehemence of any carnal pleasure.";
    
    
        //
        // Convert text to base64
        //
        CString strBase64 = BinaryToBase64( 
            reinterpret_cast<BYTE *>(szMessage), 
            sizeof(szMessage) - 1 // -1 to exclude terminating \0
        );
    
    
        //
        // Show base64 string
        //
    
        MessageBox( NULL, CA2T(szMessage), TEXT("Original String:"), MB_OK );
        // MessageBox(NULL, strBase64, TEXT("Base64 String:"), MB_OK);
        MessageBox( NULL, StripNewLines(strBase64), TEXT("Base64 String:"), MB_OK );
    }
    
    
    
    //------------------------------------------------------------------------
    // Win32 App Entry-point.
    //------------------------------------------------------------------------
    int WINAPI WinMain(      
        HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR lpCmdLine,
        int nCmdShow
    )
    {
        // Run the test
        Test();
    
        return 0;
    }
    
    
    //////////////////////////////////////////////////////////////////////////
    
    

    HTH,
    Giovanni

    • Marked as answer by

      Sunday, October 25, 2009 11:42 AM

    • Edited by
      Giovanni Dicanio
      Sunday, October 25, 2009 4:36 PM
      Renamed local variable in ‘StripNewLines’ function from ‘pcchSource’ to ‘pchSource’.

Я пытаюсь вывести исходную форму base64 импортированного открытого ключа RSA, используя функции Windows CryptoAPI. Используя CryptBinaryToString с флагом CRYPT_STRING_BASE64HEADER, выходной заголовок будет читать «BEGIN CERTIFICATE» вместо ожидаемого «BEGIN PUBLIC KEY».

Не станет ли это проблематичным, если я экспортирую вывод и повторно импортирую его с разными заголовками? Если так, что я делаю не так?

Вот как был импортирован открытый ключ.

Открытый ключ хранится в файле pubkey.pem в следующем формате PEM:

-----BEGIN PUBLIC KEY-----
[REDACTED]
-----END PUBLIC KEY-----

Файл читается в буфер с помощью CreateFile/ReadFile. PEM преобразован в двоичный файл с использованием CryptStringToBinaryA. Двоичный файл декодируется в X509_PUBLIC_KEY_INFO с использованием CryptDecodeObjectEx. Структура PubKeyInfo декодируется в RSA_CSP_PUBLICKEYBLOB (та же функция, что и выше).

Эта часть прекрасно работает (можно импортировать ключ и шифровать данные с помощью CryptImportKey, CryptEncrypt и т.д.).

Вот код, который я собрал, чтобы попытаться вернуть необработанный блоб обратно в формат PEM base64. Я удалил большинство проверок на ошибки, чтобы избежать головной боли.

pbTmp и cbTmp — это временный буфер для хранения вывода и размера соответственно. pBinaryKey — это необработанный двоичный объект с открытым ключом (импортированный ранее). pBuffer — это выходной буфер (предполагается, что он имеет правильный размер). ulDataLen — это размер выходного буфера.

CryptEncodeObjectEx(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, pBinaryKey, 0, NULL, NULL, &cbTmp)
pbTmp = malloc(cbTmp);
CryptEncodeObjectEx(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, pBinaryKey, 0, NULL, pbTmp, &cbTmp)
CryptBinaryToStringA(pbTmp, cbTmp, CRYPT_STRING_BASE64HEADER, NULL, &ulDataLen)
CryptBinaryToStringA(pbTmp, cbTmp, CRYPT_STRING_BASE64HEADER, pBuffer, &ulDataLen)

Получающийся буфер заканчивается этим:

-----BEGIN CERTIFICATE-----
[REDACTED; DIFFERENT FROM ORIGINAL PUBLIC KEY]
-----END CERTIFICATE-----

Add-Type MemberDefinition @’ [DllImport(«crypt32.dll», CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CryptStringToBinary( [MarshalAs(UnmanagedType.LPWStr)] string pszString, uint cchString, CRYPT_STRING_FLAGS dwFlags, byte[] pbBinary, ref uint pcbBinary, uint pdwSkip, ref uint pdwFlags); [DllImport(«Crypt32.dll», CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool CryptBinaryToString( byte[] pbBinary, uint cbBinary, CRYPT_STRING_FLAGS dwFlags, StringBuilder pszString, ref int pcchString); [System.Flags] public enum CRYPT_STRING_FLAGS: uint { // Base64, with certificate beginning and ending headers. Base64Header = 0x00000000, // Base64, without headers. Base64 = 0x00000001, // Pure binary copy. Binary = 0x00000002, // Base64, with request beginning and ending headers. Base64RequestHeader = 0x00000003, // Hexadecimal only format. Hex = 0x00000004, // Hexadecimal format with ASCII character display. HexASCII = 0x00000005, // Tries the following, in order: Base64Header, Base64 Base64Any = 0x00000006, // Tries the following, in order: Base64Header, Base64, Binary Any = 0x00000007, // Tries the following, in order: HexAddr, HexASCIIAddr, Hex, HexRaw, HexASCII HexAny = 0x00000008, // Base64, with X.509 certificate revocation list (CRL) beginning and ending headers. Base64X509ClrHeader = 0x00000009, // Hex, with address display. HexAddr = 0x0000000a, // Hex, with ASCII character and address display. HexASCIIAddr = 0x0000000b, // A raw hexadecimal string. Windows Server 2003 and Windows XP: This value is not supported. HexRaw = 0x0000000c, // Set this flag for Base64 data to specify that the end of the binary data contain only white space and at most three equals «=» signs. // Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP: This value is not supported. Strict = 0x20000000, // Do not append any new line characters to the encoded string. The default behavior is to use a carriage return/line feed (CR/LF) pair (0x0D/0x0A) to represent a new line. // Windows Server 2003 and Windows XP: This value is not supported. NoCrLf = 0x40000000, // Only use the line feed (LF) character (0x0A) for a new line. The default behavior is to use a CR/LF pair (0x0D/0x0A) to represent a new line. NoCr = 0x80000000 } ‘@ Namespace Win32 Name Native UsingNamespace System.Text function Invoke-CryptStringToBinary { <# .SYNOPSIS Wrapper for the Win32 native function CryptStringToBinary. .DESCRIPTION The CryptStringToBinary function converts a formatted string into an array of bytes. .EXAMPLE Invoke-CryptStringToBinary -InputString $string -Format HexAny .INPUTS System.String .OUTPUTS System.Array .NOTES NOTE! This function is based on the work of Vadims Podāns (https://www.sysadmins.lv/blog-en/convert-data-between-binary-hex-and-base64-in-powershell.aspx) Author: Øyvind Kallstad Date: 08.02.2016 Version: 1.0 .LINK https://www.sysadmins.lv/blog-en/convert-data-between-binary-hex-and-base64-in-powershell.aspx .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa380285(v=vs.85).aspx .LINK https://communary.wordpress.com/ #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] [Alias(String)] [ValidateNotNullOrEmpty()] [string] $InputString, # Indicates the format of the string to be converted. [Parameter(Mandatory = $true)] [Win32.Native+CRYPT_STRING_FLAGS] $Format ) # Will hold the size of the byte array $pcbBinary = 0 # Will hold the actual flags used in the conversion $pwdFlags = 0 # Call native method to convert if ([Win32.Native]::CryptStringToBinary($InputString, $InputString.Length, $Format, $null, [ref]$pcbBinary, 0, [ref]$pwdFlags)) { $outputArray = New-Object TypeName byte[] ArgumentList $pcbBinary [void][Win32.Native]::CryptStringToBinary($InputString, $InputString.Length, $Format, $outputArray, [ref]$pcbBinary, 0, [ref]$pwdFlags) Write-Output $outputArray } else { Write-Warning $((New-Object ComponentModel.Win32Exception ([Runtime.InteropServices.Marshal]::GetLastWin32Error())).Message) } } function Invoke-CryptBinaryToString { <# .SYNOPSIS Wrapper for the Win32 native function CryptBinaryToString. .DESCRIPTION The CryptBinaryToString function converts an array of bytes into a formatted string. .EXAMPLE Invoke-CryptBinaryToString $array -Format HexASCIIAddr .INPUTS System.Array .OUTPUTS System.String .NOTES NOTE! This function is based on the work of Vadims Podāns (https://www.sysadmins.lv/blog-en/convert-data-between-binary-hex-and-base64-in-powershell.aspx) Author: Øyvind Kallstad Date: 08.02.2016 Version: 1.0 .LINK https://www.sysadmins.lv/blog-en/convert-data-between-binary-hex-and-base64-in-powershell.aspx .LINK https://msdn.microsoft.com/en-us/library/windows/desktop/aa379887(v=vs.85).aspx .LINK https://communary.wordpress.com/ #> [CmdletBinding()] param ( [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] [byte[]] $InputObject, # Specifies the format of the resulting formatted string. [Parameter(Mandatory = $true)] [Win32.Native+CRYPT_STRING_FLAGS] $Format, # Do not append any new line characters to the encoded string. The default behavior is to use a carriage return/line feed (CR/LF) pair to represent a new line. [Parameter()] [switch] $NoCrLf, # Only use the line feed (LF) character for a new line. The default behavior is to use a CR/LF pair to represent a new line. [Parameter()] [switch] $NoCr ) BEGIN { [Win32.Native+CRYPT_STRING_FLAGS]$formatFlags = $Format if ($NoCrLf) { $formatFlags = $formatFlags -bor [Win32.Native+CRYPT_STRING_FLAGS]::NoCrLf } if ($NoCr) { $formatFlags = $formatFlags -bor [Win32.Native+CRYPT_STRING_FLAGS]::NoCr } # Will hold the size of the output string $pcchString = 0 # Silly workaround to support input from the pipeline # We need to catch all items of the pipeline into a temporary array $tempArray = New-Object TypeName System.Collections.ArrayList } PROCESS { foreach ($input in $InputObject) { [void]$tempArray.Add($input) } } END { # Convert the temp array to a byte array [byte[]]$byteArray = $tempArray.ToArray([byte]) # Call native method to convert if ([Win32.Native]::CryptBinaryToString($byteArray, $byteArray.Length,$formatFlags, $null, [ref]$pcchString)) { $outputString = New-Object TypeName System.Text.StringBuilder ArgumentList $pcchString [void][Win32.Native]::CryptBinaryToString($byteArray, $byteArray.Length, $formatFlags, $outputString, [ref]$pcchString) Write-Output $outputString.ToString() } else { Write-Warning $((New-Object ComponentModel.Win32Exception ([Runtime.InteropServices.Marshal]::GetLastWin32Error())).Message) } } }
  • Remove From My Forums
  • Question

  • Code Snippet

    Private Sub ConvertBase64() ‘fileName As String)
    Dim byteBuffer() As Byte
    Dim outputLength As Long
    Dim strBase64 As String
    Dim inputStream As Object
    Dim fileName As String
    Dim result As Long

    fileName = «c:\test.txt»
    Set inputStream = CreateObject(«ADODB.Stream»)
    inputStream.Type = 1 ‘adTypeBinary
    inputStream.Open
    inputStream.LoadFromFile fileName
    ReDim byteBuffer(inputStream.Size)
    byteBuffer = inputStream.Read(-1) ‘adReadAll

    result = CryptBinaryToString(byteBuffer(0), _
    UBound(byteBuffer) + 1, _
    CRYPT_STRING_BASE64, _
    vbNullString, _
    outputLength)

    strBase64 = Space$(outputLength)
    If CryptBinaryToString(byteBuffer(0), _
    UBound(byteBuffer) + 1, _
    CRYPT_STRING_BASE64, _
    strBase64, _
    outputLength) <> 0 Then
    MsgBox strBase64
    Else
    MsgBox «Error » & CStr(Err.LastDllError)
    End If
    End Sub

    On the marked string I’ve got:
    outputLength = 0
    result = 0
    Err.LastDllError = 234 (0x000000EA)

    my text file content: «abc»

    Why

    CryptBinaryToString returns outputLength = 0 ?

Понравилась статья? Поделить с друзьями:
  • Crypt32 ошибка получения автоматического обновления
  • Crypt32 dll ошибка
  • Crypt key is missing pgadmin ошибка
  • Credo dat код ошибки 1275
  • Cryengine ошибка unsupported graphics card detected