You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
838 lines
20 KiB
838 lines
20 KiB
//+--------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
//
|
|
// File: pkifmt.cpp
|
|
//
|
|
// Contents: data format conversion
|
|
//
|
|
// History: 25-Jul-96 vich created
|
|
// 2/2000 xtan moved from certsrv to pki
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include <windows.h>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <wincrypt.h>
|
|
|
|
#include <dbgdef.h>
|
|
#include "pkifmt.h"
|
|
|
|
|
|
#if DBG
|
|
# ifdef UNICODE
|
|
# define _DecodeCertSub _DecodeCertSubW
|
|
# else
|
|
# define _DecodeCertSub _DecodeCertSubA
|
|
# endif
|
|
#endif //DBG
|
|
|
|
|
|
DWORD
|
|
_DecodeCertSub(
|
|
IN TCHAR const *pchIn,
|
|
IN DWORD cchIn,
|
|
IN DWORD Flags,
|
|
IN OUT BYTE *pbOut,
|
|
IN OUT DWORD *pcbOut,
|
|
OUT OPTIONAL DWORD *pdwSkip)
|
|
{
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
DWORD cbOut = 0;
|
|
|
|
if (NULL != pbOut)
|
|
{
|
|
cbOut = *pcbOut;
|
|
}
|
|
|
|
switch (Flags)
|
|
{
|
|
case CRYPT_STRING_BASE64HEADER:
|
|
case CRYPT_STRING_BASE64REQUESTHEADER:
|
|
case CRYPT_STRING_BASE64X509CRLHEADER:
|
|
{
|
|
TCHAR const *pchInEnd;
|
|
DWORD cchHeader;
|
|
DWORD cchSkip;
|
|
|
|
pchInEnd = &pchIn[cchIn];
|
|
|
|
// Skip to the starting '-----....' then skip that line.
|
|
|
|
dwErr = ERROR_INVALID_DATA;
|
|
cchHeader = SizeBase64Header(pchIn, cchIn, TRUE, &cchSkip);
|
|
if (MAXDWORD == cchHeader)
|
|
{
|
|
goto SizeBase64HeaderStartError;
|
|
}
|
|
if (NULL != pdwSkip)
|
|
{
|
|
*pdwSkip = cchHeader; //for return
|
|
}
|
|
pchIn += cchHeader + cchSkip;
|
|
cchHeader = SizeBase64Header(
|
|
pchIn,
|
|
SAFE_SUBTRACT_POINTERS(pchInEnd, pchIn),
|
|
FALSE,
|
|
&cchSkip);
|
|
if (MAXDWORD == cchHeader)
|
|
{
|
|
goto SizeBase64HeaderEndError;
|
|
}
|
|
cchIn = cchHeader;
|
|
Flags = CRYPT_STRING_BASE64; // headers have been removed...
|
|
// FALLTHROUGH
|
|
}
|
|
|
|
case CRYPT_STRING_BASE64:
|
|
dwErr = Base64Decode(pchIn, cchIn, pbOut, &cbOut);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
#if DBG
|
|
if (ERROR_INVALID_DATA != dwErr)
|
|
{
|
|
DbgPrintf(DBG_SS_TRACE,
|
|
"Base64Decode err = 0x%x\n", dwErr);
|
|
}
|
|
#endif //DBG
|
|
goto Base64DecodeError;
|
|
}
|
|
break;
|
|
|
|
case CRYPT_STRING_HEX:
|
|
case CRYPT_STRING_HEXASCII:
|
|
case CRYPT_STRING_HEXADDR:
|
|
case CRYPT_STRING_HEXASCIIADDR:
|
|
dwErr = HexDecode(pchIn, cchIn, Flags, pbOut, &cbOut);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
#if DBG
|
|
if (ERROR_INVALID_DATA != dwErr)
|
|
{
|
|
DbgPrintf(DBG_SS_TRACE,
|
|
"HexDecode err = 0x%x\n", dwErr);
|
|
}
|
|
#endif //DBG
|
|
goto HexDecodeError;
|
|
}
|
|
break;
|
|
|
|
case CRYPT_STRING_BINARY:
|
|
if (NULL != pbOut)
|
|
{
|
|
//assert(sizeof(TCHAR) * cchIn == cbOut);
|
|
if (*pcbOut < cbOut)
|
|
{
|
|
*pcbOut = cbOut;
|
|
dwErr = ERROR_MORE_DATA;
|
|
goto MoreDataError;
|
|
}
|
|
CopyMemory(pbOut, (BYTE *) pchIn, cbOut);
|
|
}
|
|
else
|
|
{
|
|
cbOut = sizeof(TCHAR) * cchIn;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
dwErr = ERROR_INVALID_DATA; //hr = E_INVALIDARG
|
|
break;
|
|
}
|
|
*pcbOut = cbOut;
|
|
|
|
ErrorReturn:
|
|
return (dwErr);
|
|
|
|
SET_ERROR(MoreDataError, dwErr)
|
|
SET_ERROR(SizeBase64HeaderEndError, dwErr)
|
|
SET_ERROR(SizeBase64HeaderStartError, dwErr)
|
|
TRACE_ERROR(HexDecodeError)
|
|
TRACE_ERROR(Base64DecodeError)
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
CryptStringToBinaryA(
|
|
IN LPCSTR pszString,
|
|
IN DWORD cchString,
|
|
IN DWORD dwFlags,
|
|
IN OUT BYTE *pbBinary,
|
|
IN OUT DWORD *pcbBinary,
|
|
IN OUT DWORD *pdwSkip, //OPTIONAL
|
|
IN OUT DWORD *pdwFlags) //OPTIONAL
|
|
{
|
|
DWORD dwErr;
|
|
DWORD cbOut;
|
|
DWORD const *pFlags;
|
|
DWORD const *pFlagsEnd;
|
|
|
|
static DWORD s_aDecodeFlags[] = {
|
|
CRYPT_STRING_BASE64HEADER,
|
|
CRYPT_STRING_BASE64,
|
|
CRYPT_STRING_BINARY // must be last
|
|
};
|
|
|
|
static DWORD s_aHexDecodeFlags[] = {
|
|
CRYPT_STRING_HEXADDR,
|
|
CRYPT_STRING_HEXASCIIADDR,
|
|
CRYPT_STRING_HEX,
|
|
CRYPT_STRING_HEXASCII,
|
|
};
|
|
|
|
if (NULL == pszString)
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto InvalidDataError;
|
|
}
|
|
|
|
if (0 == cchString)
|
|
{
|
|
// assume null terminated string
|
|
cchString = strlen(pszString) + 1; //include null terminator
|
|
}
|
|
|
|
//init
|
|
if (NULL != pdwSkip)
|
|
{
|
|
*pdwSkip = 0;
|
|
}
|
|
if (NULL != pdwFlags)
|
|
{
|
|
*pdwFlags = 0;
|
|
}
|
|
if (NULL == pbBinary)
|
|
{
|
|
*pcbBinary = 0;
|
|
}
|
|
|
|
pFlags = &dwFlags;
|
|
pFlagsEnd = &pFlags[1];
|
|
if (CRYPT_STRING_BASE64_ANY == dwFlags || CRYPT_STRING_ANY == dwFlags)
|
|
{
|
|
pFlags = s_aDecodeFlags;
|
|
pFlagsEnd = &pFlags[sizeof(s_aDecodeFlags)/sizeof(s_aDecodeFlags[0])];
|
|
if (CRYPT_STRING_BASE64_ANY == dwFlags)
|
|
{
|
|
pFlagsEnd--; // Disallow CRYPT_STRING_BINARY
|
|
}
|
|
}
|
|
if (CRYPT_STRING_HEX_ANY == dwFlags)
|
|
{
|
|
pFlags = s_aHexDecodeFlags;
|
|
pFlagsEnd = &pFlags[sizeof(s_aHexDecodeFlags)/sizeof(s_aHexDecodeFlags[0])];
|
|
}
|
|
|
|
dwErr = ERROR_SUCCESS;
|
|
for ( ; pFlags < pFlagsEnd; pFlags++)
|
|
{
|
|
cbOut = *pcbBinary;
|
|
dwErr = _DecodeCertSub(
|
|
pszString,
|
|
cchString,
|
|
*pFlags,
|
|
pbBinary,
|
|
&cbOut,
|
|
pdwSkip);
|
|
if (ERROR_SUCCESS == dwErr)
|
|
{
|
|
//for return
|
|
*pcbBinary = cbOut;
|
|
if (NULL != pdwFlags)
|
|
{
|
|
*pdwFlags = *pFlags;
|
|
}
|
|
break;
|
|
}
|
|
#if DBG
|
|
if (ERROR_INVALID_DATA != dwErr)
|
|
{
|
|
DbgPrintf(DBG_SS_TRACE, "_DecodeCertSub err = 0x%x\n", dwErr);
|
|
}
|
|
#endif //DBG
|
|
}
|
|
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
goto DecodeCertSubError;
|
|
}
|
|
|
|
ErrorReturn:
|
|
return (ERROR_SUCCESS == dwErr);
|
|
|
|
SET_ERROR(DecodeCertSubError, dwErr)
|
|
SET_ERROR(InvalidDataError, dwErr)
|
|
}
|
|
|
|
DWORD
|
|
BinaryEncode(
|
|
IN BYTE const *pbIn,
|
|
IN DWORD cbIn,
|
|
OPTIONAL OUT TCHAR *pchOut,
|
|
IN OUT DWORD *pcchOut)
|
|
{
|
|
DWORD dwErr;
|
|
|
|
if (NULL != pchOut)
|
|
{
|
|
if (*pcchOut < cbIn)
|
|
{
|
|
dwErr = ERROR_MORE_DATA;
|
|
goto MoreDataError;
|
|
}
|
|
CopyMemory(pchOut, pbIn, cbIn);
|
|
}
|
|
|
|
dwErr = ERROR_SUCCESS;
|
|
ErrorReturn:
|
|
|
|
//get size any way
|
|
*pcchOut = cbIn;
|
|
|
|
return dwErr;
|
|
|
|
SET_ERROR(MoreDataError, dwErr)
|
|
}
|
|
|
|
static TCHAR const szBeginCert[] = TEXT("-----BEGIN CERTIFICATE-----");
|
|
static TCHAR const szEndCert[] = TEXT("-----END CERTIFICATE-----");
|
|
|
|
#define CB_BEGINCERT (sizeof(szBeginCert) - sizeof(TCHAR))
|
|
#define CB_ENDCERT (sizeof(szEndCert) - sizeof(TCHAR))
|
|
|
|
static TCHAR const szBeginCertRequest[] = TEXT("-----BEGIN NEW CERTIFICATE REQUEST-----");
|
|
static TCHAR const szEndCertRequest[] = TEXT("-----END NEW CERTIFICATE REQUEST-----");
|
|
|
|
#define CB_BEGINCERTREQUEST (sizeof(szBeginCertRequest) - sizeof(TCHAR))
|
|
#define CB_ENDCERTREQUEST (sizeof(szEndCertRequest) - sizeof(TCHAR))
|
|
|
|
static TCHAR const szBeginCRL[] = TEXT("-----BEGIN X509 CRL-----");
|
|
static TCHAR const szEndCRL[] = TEXT("-----END X509 CRL-----");
|
|
|
|
#define CB_BEGINCRL (sizeof(szBeginCRL) - sizeof(TCHAR))
|
|
#define CB_ENDCRL (sizeof(szEndCRL) - sizeof(TCHAR))
|
|
|
|
typedef struct _CERTHEADER
|
|
{
|
|
TCHAR const *pszBegin;
|
|
DWORD cbBegin;
|
|
TCHAR const *pszEnd;
|
|
DWORD cbEnd;
|
|
} CERTHEADER;
|
|
|
|
static CERTHEADER const CertHeaderCert =
|
|
{
|
|
szBeginCert,
|
|
CB_BEGINCERT,
|
|
szEndCert,
|
|
CB_ENDCERT
|
|
};
|
|
|
|
static CERTHEADER const CertHeaderCertRequest =
|
|
{
|
|
szBeginCertRequest,
|
|
CB_BEGINCERTREQUEST,
|
|
szEndCertRequest,
|
|
CB_ENDCERTREQUEST
|
|
};
|
|
|
|
static CERTHEADER const CertHeaderCRL =
|
|
{
|
|
szBeginCRL,
|
|
CB_BEGINCRL,
|
|
szEndCRL,
|
|
CB_ENDCRL
|
|
};
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
CryptBinaryToStringA(
|
|
IN CONST BYTE *pbBinary,
|
|
IN DWORD cbBinary,
|
|
IN DWORD dwFlags,
|
|
OUT LPSTR pszString,
|
|
OUT DWORD *pcchString)
|
|
{
|
|
DWORD dwErr;
|
|
TCHAR *pchEncode;
|
|
DWORD cchMax;
|
|
DWORD cchOut;
|
|
DWORD cbTotal;
|
|
CERTHEADER const *pCertHeader = NULL;
|
|
BOOL fNoCR = 0 != (CRYPT_STRING_NOCR & dwFlags);
|
|
DWORD cchnl = fNoCR? 1 : 2;
|
|
BOOL fBinaryCopy = FALSE;
|
|
|
|
if (NULL == pbBinary || 0 == cbBinary || NULL == pcchString)
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto InvalidDataError;
|
|
}
|
|
|
|
if (NULL == pszString)
|
|
{
|
|
*pcchString = 0;
|
|
}
|
|
|
|
switch (~CRYPT_STRING_NOCR & dwFlags)
|
|
{
|
|
case CRYPT_STRING_BASE64HEADER:
|
|
pCertHeader = &CertHeaderCert;
|
|
break;
|
|
|
|
case CRYPT_STRING_BASE64REQUESTHEADER:
|
|
pCertHeader = &CertHeaderCertRequest;
|
|
break;
|
|
|
|
case CRYPT_STRING_BASE64X509CRLHEADER:
|
|
pCertHeader = &CertHeaderCRL;
|
|
break;
|
|
}
|
|
|
|
pchEncode = pszString;
|
|
cchMax = *pcchString;
|
|
cchOut = cchMax;
|
|
|
|
if (NULL != pszString && NULL != pCertHeader)
|
|
{
|
|
// Make sure there's room for the BEGIN header and CR-LF sequence
|
|
|
|
if (pCertHeader->cbBegin + cchnl > cchMax)
|
|
{
|
|
dwErr = ERROR_MORE_DATA;
|
|
goto MoreDataError;
|
|
}
|
|
cchOut -= pCertHeader->cbBegin + cchnl;
|
|
CopyMemory(pchEncode, pCertHeader->pszBegin, pCertHeader->cbBegin);
|
|
pchEncode += pCertHeader->cbBegin/sizeof(TCHAR);
|
|
if (!fNoCR)
|
|
{
|
|
*pchEncode++ = '\r';
|
|
}
|
|
*pchEncode++ = '\n';
|
|
}
|
|
|
|
// first determine size
|
|
|
|
switch (~CRYPT_STRING_NOCR & dwFlags)
|
|
{
|
|
case CRYPT_STRING_BINARY:
|
|
dwErr = BinaryEncode(pbBinary, cbBinary, pchEncode, &cchOut);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
goto BinaryEncodeError;
|
|
}
|
|
fBinaryCopy = TRUE;
|
|
break;
|
|
|
|
case CRYPT_STRING_HEX:
|
|
case CRYPT_STRING_HEXASCII:
|
|
case CRYPT_STRING_HEXADDR:
|
|
case CRYPT_STRING_HEXASCIIADDR:
|
|
dwErr = HexEncode(pbBinary, cbBinary, dwFlags, pchEncode, &cchOut);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
goto HexEncodeError;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
dwErr = Base64Encode(pbBinary, cbBinary, dwFlags, pchEncode, &cchOut);
|
|
if (ERROR_SUCCESS != dwErr)
|
|
{
|
|
goto Base64EncodeError;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Compute total size, including the trailing '\0' character.
|
|
if (fBinaryCopy)
|
|
{
|
|
cbTotal = cchOut;
|
|
}
|
|
else
|
|
{
|
|
cbTotal = (cchOut + 1) * sizeof(CHAR);
|
|
}
|
|
|
|
// Add space for the BEGIN & END headers, if requested.
|
|
|
|
if (NULL != pCertHeader)
|
|
{
|
|
cbTotal += pCertHeader->cbBegin + pCertHeader->cbEnd;
|
|
if (!fNoCR)
|
|
{
|
|
cbTotal += 2 * sizeof(TCHAR); // for BEGIN & END '\r' chars
|
|
}
|
|
cbTotal += 2 * sizeof(TCHAR); // for BEGIN & END '\n' chars
|
|
}
|
|
|
|
if (fBinaryCopy)
|
|
{
|
|
*pcchString = cbTotal;
|
|
}
|
|
else
|
|
{
|
|
// if pszString is NULL, set size to include trailing '\0'
|
|
*pcchString = cbTotal / sizeof(CHAR);
|
|
}
|
|
|
|
if (NULL == pszString)
|
|
{
|
|
// only determine size, done
|
|
goto done;
|
|
}
|
|
|
|
if (NULL != pCertHeader)
|
|
{
|
|
cchOut += pCertHeader->cbBegin/sizeof(CHAR) + cchnl;
|
|
|
|
// Make sure there's room for the END header, CR-LF sequence, and '\0'
|
|
|
|
if (cchOut + pCertHeader->cbEnd + cchnl + 1 > cchMax)
|
|
{
|
|
dwErr = ERROR_MORE_DATA;
|
|
goto MoreDataError;
|
|
}
|
|
CopyMemory(&pszString[cchOut], pCertHeader->pszEnd, pCertHeader->cbEnd);
|
|
cchOut += pCertHeader->cbEnd/sizeof(CHAR);
|
|
if (!fNoCR)
|
|
{
|
|
pszString[cchOut++] = '\r';
|
|
}
|
|
pszString[cchOut++] = '\n';
|
|
}
|
|
|
|
if (!fBinaryCopy)
|
|
{
|
|
pszString[cchOut] = '\0';
|
|
assert((cchOut + 1) * sizeof(CHAR) == cbTotal);
|
|
|
|
// pszString is not NULL, don't include trailing '\0' in length
|
|
|
|
*pcchString = cchOut;
|
|
}
|
|
|
|
done:
|
|
dwErr = ERROR_SUCCESS;
|
|
|
|
ErrorReturn:
|
|
return(ERROR_SUCCESS == dwErr);
|
|
|
|
TRACE_ERROR(Base64EncodeError)
|
|
TRACE_ERROR(HexEncodeError)
|
|
TRACE_ERROR(BinaryEncodeError)
|
|
SET_ERROR(InvalidDataError, dwErr)
|
|
SET_ERROR(MoreDataError, dwErr)
|
|
}
|
|
|
|
|
|
static TCHAR const szBeginMatch[] = TEXT("-----BEGIN ");
|
|
static TCHAR const szEndMatch[] = TEXT("-----END ");
|
|
static TCHAR const szMinus[] = TEXT("-----");
|
|
|
|
#define CCH_BEGINMATCH sizeof(szBeginMatch)/sizeof(szBeginMatch[0]) - 1
|
|
#define CCH_ENDMATCH sizeof(szEndMatch)/sizeof(szEndMatch[0]) - 1
|
|
#define CCH_MINUS sizeof(szMinus)/sizeof(szMinus[0]) - 1
|
|
|
|
// Returns the count of characters up to the -----BEGIN/-----END delimiter,
|
|
// MAXDWORD on error.
|
|
//
|
|
// On successful return, *pcchSkip is the count of characters in the delimiter
|
|
// string.
|
|
|
|
DWORD
|
|
SizeBase64Header(
|
|
IN TCHAR const *pchIn,
|
|
IN DWORD cchIn,
|
|
IN BOOL fBegin,
|
|
OUT DWORD *pcchSkip)
|
|
{
|
|
DWORD cchHeader = MAXDWORD;
|
|
TCHAR const *pchT;
|
|
TCHAR const *pchT2;
|
|
TCHAR const *pchEnd;
|
|
TCHAR const *pchMatch;
|
|
DWORD cchMatch;
|
|
|
|
// Skip to the starting '-----....' & return count of skipped characters.
|
|
|
|
*pcchSkip = 0;
|
|
if (fBegin)
|
|
{
|
|
pchMatch = szBeginMatch;
|
|
cchMatch = CCH_BEGINMATCH;
|
|
}
|
|
else
|
|
{
|
|
pchMatch = szEndMatch;
|
|
cchMatch = CCH_ENDMATCH;
|
|
}
|
|
pchT = pchIn;
|
|
pchEnd = &pchIn[cchIn];
|
|
|
|
for (;;)
|
|
{
|
|
// Skip until we match the first character.
|
|
|
|
while (pchT < pchEnd && *pchT != *pchMatch)
|
|
{
|
|
pchT++;
|
|
}
|
|
|
|
if (&pchT[cchMatch] > pchEnd)
|
|
{
|
|
// no room for the "-----BEGIN "/"-----END " string
|
|
break;
|
|
}
|
|
if (0 == strncmp(pchT, pchMatch, cchMatch))
|
|
{
|
|
pchT2 = &pchT[cchMatch];
|
|
while (pchT2 < pchEnd && *pchT2 != szMinus[0])
|
|
{
|
|
pchT2++;
|
|
}
|
|
if (&pchT2[CCH_MINUS] > pchEnd)
|
|
{
|
|
// no room for the trailing "-----" string
|
|
break;
|
|
}
|
|
if (0 == strncmp(pchT2, szMinus, CCH_MINUS))
|
|
{
|
|
// Allow up to 2 extra leading minus signs
|
|
|
|
DWORD cchMinus = 0;
|
|
|
|
while (2 > cchMinus && pchT > pchIn)
|
|
{
|
|
if (TEXT('-') != *--pchT)
|
|
{
|
|
pchT++; // oops, went too far
|
|
break;
|
|
}
|
|
cchMinus++;
|
|
}
|
|
|
|
#if DBG
|
|
if (0 != cchMinus)
|
|
{
|
|
DbgPrintf(DBG_SS_TRACE,
|
|
"Ignored leading data: \"%.*" szFMTTSTR "\"\n",
|
|
cchMinus,
|
|
TEXT("--"));
|
|
}
|
|
#endif //DBG
|
|
|
|
cchHeader = SAFE_SUBTRACT_POINTERS(pchT, pchIn);
|
|
*pcchSkip = SAFE_SUBTRACT_POINTERS(pchT2, pchT) + CCH_MINUS;
|
|
#if DBG
|
|
#if 0
|
|
DbgPrintf(
|
|
DBG_SS_TRACE,
|
|
"Skipping(%u, %x, %x):\n[%.*" szFMTTSTR "]\n",
|
|
fBegin,
|
|
cchHeader,
|
|
*pcchSkip,
|
|
cchHeader,
|
|
pchIn);
|
|
#endif
|
|
#endif // DBG
|
|
break;
|
|
}
|
|
}
|
|
pchT++;
|
|
}
|
|
return(cchHeader);
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
CryptBinaryToStringW(
|
|
IN CONST BYTE *pbBinary,
|
|
IN DWORD cbBinary,
|
|
IN DWORD dwFlags,
|
|
OUT LPWSTR pwszString,
|
|
OUT DWORD *pcchString)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
BOOL fConversion = FALSE;
|
|
DWORD dwErr;
|
|
int len;
|
|
CHAR *pszString = NULL;
|
|
|
|
if (NULL == pwszString)
|
|
{
|
|
//only return size
|
|
fRet = CryptBinaryToStringA(
|
|
pbBinary,
|
|
cbBinary,
|
|
dwFlags,
|
|
NULL, //for size
|
|
pcchString);
|
|
}
|
|
else
|
|
{
|
|
if (0 == *pcchString)
|
|
{
|
|
//must bigger than 0
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto InvalidDataError;
|
|
}
|
|
|
|
if (CRYPT_STRING_BINARY == (~CRYPT_STRING_NOCR & dwFlags))
|
|
{
|
|
//no conversion needed
|
|
pszString = (CHAR*)pwszString;
|
|
}
|
|
else
|
|
{
|
|
pszString = (CHAR*)LocalAlloc(LMEM_FIXED, *pcchString * sizeof(CHAR));
|
|
if (NULL == pszString)
|
|
{
|
|
goto LocalAllocError;
|
|
}
|
|
fConversion = TRUE;
|
|
}
|
|
|
|
fRet = CryptBinaryToStringA(
|
|
pbBinary,
|
|
cbBinary,
|
|
dwFlags,
|
|
pszString,
|
|
pcchString);
|
|
if (!fRet)
|
|
{
|
|
goto CryptBinaryToStringAError;
|
|
}
|
|
//pszString in above call is not NULL, so pcchString can be 1 smaller
|
|
//then IN size after the call for exlucding NULL
|
|
|
|
if (fConversion)
|
|
{
|
|
len = MultiByteToWideChar(
|
|
GetACP(),
|
|
0,
|
|
pszString,
|
|
(*pcchString + 1) * sizeof(CHAR),
|
|
pwszString,
|
|
*pcchString + 1);
|
|
//add 1 to *pcchString to include NULL for the conversion
|
|
//but keep *pcchString for return
|
|
if (0 == len)
|
|
{
|
|
fRet = FALSE;
|
|
goto MultiByteToWideCharError;
|
|
}
|
|
assert(len == (int)(*pcchString + 1));
|
|
}
|
|
}
|
|
|
|
ErrorReturn:
|
|
if (fConversion && NULL != pszString)
|
|
{
|
|
LocalFree(pszString);
|
|
}
|
|
return fRet;
|
|
|
|
TRACE_ERROR(MultiByteToWideCharError)
|
|
TRACE_ERROR(CryptBinaryToStringAError)
|
|
TRACE_ERROR(LocalAllocError)
|
|
SET_ERROR(InvalidDataError, dwErr)
|
|
}
|
|
|
|
|
|
#define NOTEPAD_UNICODE_SPECIAL_WCHAR L'\xfeff'
|
|
|
|
BOOL
|
|
WINAPI
|
|
CryptStringToBinaryW(
|
|
IN LPCWSTR pwszString,
|
|
IN DWORD cchString,
|
|
IN DWORD dwFlags,
|
|
IN OUT BYTE *pbBinary,
|
|
IN OUT DWORD *pcbBinary,
|
|
IN OUT DWORD *pdwSkip, //OPTIONAL
|
|
IN OUT DWORD *pdwFlags) //OPTIONAL
|
|
{
|
|
BOOL fRet = FALSE;
|
|
BOOL fFree = FALSE;
|
|
DWORD dwErr;
|
|
CHAR *pszString = NULL;
|
|
|
|
if (NULL == pwszString || NULL == pcbBinary)
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto InvalidDataError;
|
|
}
|
|
|
|
if (dwFlags == CRYPT_STRING_BINARY)
|
|
{
|
|
//its binary, no conversion
|
|
pszString = (CHAR*)pwszString;
|
|
}
|
|
else
|
|
{
|
|
if (0 == cchString)
|
|
{
|
|
//assume null terminated string
|
|
cchString = wcslen(pwszString) + 1;
|
|
}
|
|
|
|
// Check for the special Notepad UNICODE character inserted at the
|
|
// beginning and skip past it if present.
|
|
if (0 < cchString && NOTEPAD_UNICODE_SPECIAL_WCHAR == *pwszString)
|
|
{
|
|
cchString--;
|
|
pwszString++;
|
|
}
|
|
|
|
pszString = (CHAR*)LocalAlloc(LMEM_FIXED, cchString * sizeof(CHAR));
|
|
if (NULL == pszString)
|
|
{
|
|
dwErr = ERROR_OUTOFMEMORY;
|
|
goto LocalAllocError;
|
|
}
|
|
|
|
fFree = TRUE;
|
|
if (0 == WideCharToMultiByte(
|
|
GetACP(),
|
|
0,
|
|
pwszString,
|
|
cchString,
|
|
pszString,
|
|
cchString,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
goto WideCharToMultiByteError;
|
|
}
|
|
}
|
|
|
|
fRet = CryptStringToBinaryA(
|
|
pszString,
|
|
cchString,
|
|
dwFlags,
|
|
pbBinary,
|
|
pcbBinary,
|
|
pdwSkip,
|
|
pdwFlags);
|
|
if (!fRet)
|
|
{
|
|
goto CryptStringToBinaryAError;
|
|
}
|
|
|
|
ErrorReturn:
|
|
if (fFree && NULL != pszString)
|
|
{
|
|
LocalFree(pszString);
|
|
}
|
|
return fRet;
|
|
|
|
TRACE_ERROR(CryptStringToBinaryAError)
|
|
SET_ERROR(LocalAllocError, dwErr)
|
|
SET_ERROR(InvalidDataError, dwErr)
|
|
TRACE_ERROR(WideCharToMultiByteError)
|
|
}
|