ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

base64.c
Go to the documentation of this file.
00001 /*
00002  * base64 encoder/decoder
00003  *
00004  * Copyright 2005 by Kai Blin
00005  * Copyright 2006 Juan Lang
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 #include <stdarg.h>
00023 #include "windef.h"
00024 #include "winbase.h"
00025 #include "winerror.h"
00026 #include "wincrypt.h"
00027 #include "wine/debug.h"
00028 #include "wine/unicode.h"
00029 
00030 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
00031 
00032 #define CERT_HEADER          "-----BEGIN CERTIFICATE-----"
00033 #define CERT_HEADER_START    "-----BEGIN"
00034 #define CERT_DELIMITER       "-----"
00035 #define CERT_TRAILER         "-----END CERTIFICATE-----"
00036 #define CERT_TRAILER_START   "-----END"
00037 #define CERT_REQUEST_HEADER  "-----BEGIN NEW CERTIFICATE REQUEST-----"
00038 #define CERT_REQUEST_TRAILER "-----END NEW CERTIFICATE REQUEST-----"
00039 #define X509_HEADER          "-----BEGIN X509 CRL-----"
00040 #define X509_TRAILER         "-----END X509 CRL-----"
00041 
00042 static const WCHAR CERT_HEADER_W[] = {
00043 '-','-','-','-','-','B','E','G','I','N',' ','C','E','R','T','I','F','I','C',
00044 'A','T','E','-','-','-','-','-',0 };
00045 static const WCHAR CERT_HEADER_START_W[] = {
00046 '-','-','-','-','-','B','E','G','I','N',0 };
00047 static const WCHAR CERT_DELIMITER_W[] = {
00048 '-','-','-','-','-',0 };
00049 static const WCHAR CERT_TRAILER_W[] = {
00050 '-','-','-','-','-','E','N','D',0 };
00051 static const WCHAR CERT_TRAILER_START_W[] = {
00052 '-','-','-','-','-','E','N','D',' ','C','E','R','T','I','F','I','C','A','T',
00053 'E','-','-','-','-','-',0 };
00054 static const WCHAR CERT_REQUEST_HEADER_W[] = {
00055 '-','-','-','-','-','B','E','G','I','N',' ','N','E','W',' ','C','E','R','T',
00056 'I','F','I','C','A','T','E','R','E','Q','U','E','S','T','-','-','-','-','-',0 };
00057 static const WCHAR CERT_REQUEST_TRAILER_W[] = {
00058 '-','-','-','-','-','E','N','D',' ','N','E','W',' ','C','E','R','T','I','F',
00059 'I','C','A','T','E','R','E','Q','U','E','S','T','-','-','-','-','-',0 };
00060 static const WCHAR X509_HEADER_W[] = {
00061 '-','-','-','-','-','B','E','G','I','N',' ','X','5','0','9',' ','C','R','L',
00062 '-','-','-','-','-',0 };
00063 static const WCHAR X509_TRAILER_W[] = {
00064 '-','-','-','-','-','E','N','D',' ','X','5','0','9',' ','C','R','L','-','-',
00065 '-','-','-',0 };
00066 
00067 static const char b64[] =
00068 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00069 
00070 typedef BOOL (*BinaryToStringAFunc)(const BYTE *pbBinary,
00071  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString);
00072 typedef BOOL (*BinaryToStringWFunc)(const BYTE *pbBinary,
00073  DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString);
00074 
00075 static BOOL EncodeBinaryToBinaryA(const BYTE *pbBinary,
00076  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
00077 {
00078     BOOL ret = TRUE;
00079 
00080     if (*pcchString < cbBinary)
00081     {
00082         if (!pszString)
00083             *pcchString = cbBinary;
00084         else
00085         {
00086             SetLastError(ERROR_INSUFFICIENT_BUFFER);
00087             *pcchString = cbBinary;
00088             ret = FALSE;
00089         }
00090     }
00091     else
00092     {
00093         if (cbBinary)
00094             memcpy(pszString, pbBinary, cbBinary);
00095         *pcchString = cbBinary;
00096     }
00097     return ret;
00098 }
00099 
00100 static LONG encodeBase64A(const BYTE *in_buf, int in_len, LPCSTR sep,
00101  char* out_buf, DWORD *out_len)
00102 {
00103     int div, i;
00104     const BYTE *d = in_buf;
00105     int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
00106     DWORD needed;
00107     LPSTR ptr;
00108 
00109     TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
00110     needed = bytes + pad_bytes + 1;
00111     needed += (needed / 64 + 1) * strlen(sep);
00112 
00113     if (needed > *out_len)
00114     {
00115         *out_len = needed;
00116         return ERROR_INSUFFICIENT_BUFFER;
00117     }
00118     else
00119         *out_len = needed;
00120 
00121     /* Three bytes of input give 4 chars of output */
00122     div = in_len / 3;
00123 
00124     ptr = out_buf;
00125     i = 0;
00126     while (div > 0)
00127     {
00128         if (i && i % 64 == 0)
00129         {
00130             strcpy(ptr, sep);
00131             ptr += strlen(sep);
00132         }
00133         /* first char is the first 6 bits of the first byte*/
00134         *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
00135         /* second char is the last 2 bits of the first byte and the first 4
00136          * bits of the second byte */
00137         *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
00138         /* third char is the last 4 bits of the second byte and the first 2
00139          * bits of the third byte */
00140         *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
00141         /* fourth char is the remaining 6 bits of the third byte */
00142         *ptr++ = b64[   d[2]       & 0x3f];
00143         i += 4;
00144         d += 3;
00145         div--;
00146     }
00147 
00148     switch(pad_bytes)
00149     {
00150         case 1:
00151             /* first char is the first 6 bits of the first byte*/
00152             *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
00153             /* second char is the last 2 bits of the first byte and the first 4
00154              * bits of the second byte */
00155             *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
00156             /* third char is the last 4 bits of the second byte padded with
00157              * two zeroes */
00158             *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
00159             /* fourth char is a = to indicate one byte of padding */
00160             *ptr++ = '=';
00161             break;
00162         case 2:
00163             /* first char is the first 6 bits of the first byte*/
00164             *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
00165             /* second char is the last 2 bits of the first byte padded with
00166              * four zeroes*/
00167             *ptr++ = b64[ ((d[0] << 4) & 0x30)];
00168             /* third char is = to indicate padding */
00169             *ptr++ = '=';
00170             /* fourth char is = to indicate padding */
00171             *ptr++ = '=';
00172             break;
00173     }
00174     strcpy(ptr, sep);
00175 
00176     return ERROR_SUCCESS;
00177 }
00178 
00179 static BOOL BinaryToBase64A(const BYTE *pbBinary,
00180  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
00181 {
00182     static const char crlf[] = "\r\n", lf[] = "\n";
00183     BOOL ret = TRUE;
00184     LPCSTR header = NULL, trailer = NULL, sep;
00185     DWORD charsNeeded;
00186 
00187     if (dwFlags & CRYPT_STRING_NOCR)
00188         sep = lf;
00189     else if (dwFlags & CRYPT_STRING_NOCRLF)
00190         sep = "";
00191     else
00192         sep = crlf;
00193     switch (dwFlags & 0x0fffffff)
00194     {
00195     case CRYPT_STRING_BASE64:
00196         /* no header or footer */
00197         break;
00198     case CRYPT_STRING_BASE64HEADER:
00199         header = CERT_HEADER;
00200         trailer = CERT_TRAILER;
00201         break;
00202     case CRYPT_STRING_BASE64REQUESTHEADER:
00203         header = CERT_REQUEST_HEADER;
00204         trailer = CERT_REQUEST_TRAILER;
00205         break;
00206     case CRYPT_STRING_BASE64X509CRLHEADER:
00207         header = X509_HEADER;
00208         trailer = X509_TRAILER;
00209         break;
00210     }
00211 
00212     charsNeeded = 0;
00213     encodeBase64A(pbBinary, cbBinary, sep, NULL, &charsNeeded);
00214     if (header)
00215         charsNeeded += strlen(header) + strlen(sep);
00216     if (trailer)
00217         charsNeeded += strlen(trailer) + strlen(sep);
00218     if (charsNeeded <= *pcchString)
00219     {
00220         LPSTR ptr = pszString;
00221         DWORD size = charsNeeded;
00222 
00223         if (header)
00224         {
00225             strcpy(ptr, header);
00226             ptr += strlen(ptr);
00227             strcpy(ptr, sep);
00228             ptr += strlen(sep);
00229         }
00230         encodeBase64A(pbBinary, cbBinary, sep, ptr, &size);
00231         ptr += size - 1;
00232         if (trailer)
00233         {
00234             strcpy(ptr, trailer);
00235             ptr += strlen(ptr);
00236             strcpy(ptr, sep);
00237         }
00238         *pcchString = charsNeeded - 1;
00239     }
00240     else if (pszString)
00241     {
00242         *pcchString = charsNeeded;
00243         SetLastError(ERROR_INSUFFICIENT_BUFFER);
00244         ret = FALSE;
00245     }
00246     else
00247         *pcchString = charsNeeded;
00248     return ret;
00249 }
00250 
00251 BOOL WINAPI CryptBinaryToStringA(const BYTE *pbBinary,
00252  DWORD cbBinary, DWORD dwFlags, LPSTR pszString, DWORD *pcchString)
00253 {
00254     BinaryToStringAFunc encoder = NULL;
00255 
00256     TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
00257      pcchString);
00258 
00259     if (!pbBinary)
00260     {
00261         SetLastError(ERROR_INVALID_PARAMETER);
00262         return FALSE;
00263     }
00264     if (!pcchString)
00265     {
00266         SetLastError(ERROR_INVALID_PARAMETER);
00267         return FALSE;
00268     }
00269 
00270     switch (dwFlags & 0x0fffffff)
00271     {
00272     case CRYPT_STRING_BINARY:
00273         encoder = EncodeBinaryToBinaryA;
00274         break;
00275     case CRYPT_STRING_BASE64:
00276     case CRYPT_STRING_BASE64HEADER:
00277     case CRYPT_STRING_BASE64REQUESTHEADER:
00278     case CRYPT_STRING_BASE64X509CRLHEADER:
00279         encoder = BinaryToBase64A;
00280         break;
00281     case CRYPT_STRING_HEX:
00282     case CRYPT_STRING_HEXASCII:
00283     case CRYPT_STRING_HEXADDR:
00284     case CRYPT_STRING_HEXASCIIADDR:
00285         FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
00286         /* fall through */
00287     default:
00288         SetLastError(ERROR_INVALID_PARAMETER);
00289         return FALSE;
00290     }
00291     return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
00292 }
00293 
00294 static LONG encodeBase64W(const BYTE *in_buf, int in_len, LPCWSTR sep,
00295  WCHAR* out_buf, DWORD *out_len)
00296 {
00297     int div, i;
00298     const BYTE *d = in_buf;
00299     int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0;
00300     DWORD needed;
00301     LPWSTR ptr;
00302 
00303     TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes);
00304     needed = bytes + pad_bytes + 1;
00305     needed += (needed / 64 + 1) * strlenW(sep);
00306 
00307     if (needed > *out_len)
00308     {
00309         *out_len = needed;
00310         return ERROR_INSUFFICIENT_BUFFER;
00311     }
00312     else
00313         *out_len = needed;
00314 
00315     /* Three bytes of input give 4 chars of output */
00316     div = in_len / 3;
00317 
00318     ptr = out_buf;
00319     i = 0;
00320     while (div > 0)
00321     {
00322         if (i && i % 64 == 0)
00323         {
00324             strcpyW(ptr, sep);
00325             ptr += strlenW(sep);
00326         }
00327         /* first char is the first 6 bits of the first byte*/
00328         *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
00329         /* second char is the last 2 bits of the first byte and the first 4
00330          * bits of the second byte */
00331         *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
00332         /* third char is the last 4 bits of the second byte and the first 2
00333          * bits of the third byte */
00334         *ptr++ = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)];
00335         /* fourth char is the remaining 6 bits of the third byte */
00336         *ptr++ = b64[   d[2]       & 0x3f];
00337         i += 4;
00338         d += 3;
00339         div--;
00340     }
00341 
00342     switch(pad_bytes)
00343     {
00344         case 1:
00345             /* first char is the first 6 bits of the first byte*/
00346             *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
00347             /* second char is the last 2 bits of the first byte and the first 4
00348              * bits of the second byte */
00349             *ptr++ = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)];
00350             /* third char is the last 4 bits of the second byte padded with
00351              * two zeroes */
00352             *ptr++ = b64[ ((d[1] << 2) & 0x3c) ];
00353             /* fourth char is a = to indicate one byte of padding */
00354             *ptr++ = '=';
00355             break;
00356         case 2:
00357             /* first char is the first 6 bits of the first byte*/
00358             *ptr++ = b64[ ( d[0] >> 2) & 0x3f ];
00359             /* second char is the last 2 bits of the first byte padded with
00360              * four zeroes*/
00361             *ptr++ = b64[ ((d[0] << 4) & 0x30)];
00362             /* third char is = to indicate padding */
00363             *ptr++ = '=';
00364             /* fourth char is = to indicate padding */
00365             *ptr++ = '=';
00366             break;
00367     }
00368     strcpyW(ptr, sep);
00369 
00370     return ERROR_SUCCESS;
00371 }
00372 
00373 static BOOL BinaryToBase64W(const BYTE *pbBinary,
00374  DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
00375 {
00376     static const WCHAR crlf[] = { '\r','\n',0 }, lf[] = { '\n',0 }, empty[] = {0};
00377     BOOL ret = TRUE;
00378     LPCWSTR header = NULL, trailer = NULL, sep;
00379     DWORD charsNeeded;
00380 
00381     if (dwFlags & CRYPT_STRING_NOCR)
00382         sep = lf;
00383     else if (dwFlags & CRYPT_STRING_NOCRLF)
00384         sep = empty;
00385     else
00386         sep = crlf;
00387     switch (dwFlags & 0x0fffffff)
00388     {
00389     case CRYPT_STRING_BASE64:
00390         /* no header or footer */
00391         break;
00392     case CRYPT_STRING_BASE64HEADER:
00393         header = CERT_HEADER_W;
00394         trailer = CERT_TRAILER_W;
00395         break;
00396     case CRYPT_STRING_BASE64REQUESTHEADER:
00397         header = CERT_REQUEST_HEADER_W;
00398         trailer = CERT_REQUEST_TRAILER_W;
00399         break;
00400     case CRYPT_STRING_BASE64X509CRLHEADER:
00401         header = X509_HEADER_W;
00402         trailer = X509_TRAILER_W;
00403         break;
00404     }
00405 
00406     charsNeeded = 0;
00407     encodeBase64W(pbBinary, cbBinary, sep, NULL, &charsNeeded);
00408     if (header)
00409         charsNeeded += strlenW(header) + strlenW(sep);
00410     if (trailer)
00411         charsNeeded += strlenW(trailer) + strlenW(sep);
00412     if (charsNeeded <= *pcchString)
00413     {
00414         LPWSTR ptr = pszString;
00415         DWORD size = charsNeeded;
00416 
00417         if (header)
00418         {
00419             strcpyW(ptr, header);
00420             ptr += strlenW(ptr);
00421             strcpyW(ptr, sep);
00422             ptr += strlenW(sep);
00423         }
00424         encodeBase64W(pbBinary, cbBinary, sep, ptr, &size);
00425         ptr += size - 1;
00426         if (trailer)
00427         {
00428             strcpyW(ptr, trailer);
00429             ptr += strlenW(ptr);
00430             strcpyW(ptr, sep);
00431         }
00432         *pcchString = charsNeeded - 1;
00433     }
00434     else if (pszString)
00435     {
00436         *pcchString = charsNeeded;
00437         SetLastError(ERROR_INSUFFICIENT_BUFFER);
00438         ret = FALSE;
00439     }
00440     else
00441         *pcchString = charsNeeded;
00442     return ret;
00443 }
00444 
00445 BOOL WINAPI CryptBinaryToStringW(const BYTE *pbBinary,
00446  DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, DWORD *pcchString)
00447 {
00448     BinaryToStringWFunc encoder = NULL;
00449 
00450     TRACE("(%p, %d, %08x, %p, %p)\n", pbBinary, cbBinary, dwFlags, pszString,
00451      pcchString);
00452 
00453     if (!pbBinary)
00454     {
00455         SetLastError(ERROR_INVALID_PARAMETER);
00456         return FALSE;
00457     }
00458     if (!pcchString)
00459     {
00460         SetLastError(ERROR_INVALID_PARAMETER);
00461         return FALSE;
00462     }
00463 
00464     switch (dwFlags & 0x0fffffff)
00465     {
00466     case CRYPT_STRING_BASE64:
00467     case CRYPT_STRING_BASE64HEADER:
00468     case CRYPT_STRING_BASE64REQUESTHEADER:
00469     case CRYPT_STRING_BASE64X509CRLHEADER:
00470         encoder = BinaryToBase64W;
00471         break;
00472     case CRYPT_STRING_BINARY:
00473     case CRYPT_STRING_HEX:
00474     case CRYPT_STRING_HEXASCII:
00475     case CRYPT_STRING_HEXADDR:
00476     case CRYPT_STRING_HEXASCIIADDR:
00477         FIXME("Unimplemented type %d\n", dwFlags & 0x0fffffff);
00478         /* fall through */
00479     default:
00480         SetLastError(ERROR_INVALID_PARAMETER);
00481         return FALSE;
00482     }
00483     return encoder(pbBinary, cbBinary, dwFlags, pszString, pcchString);
00484 }
00485 
00486 static inline BYTE decodeBase64Byte(int c)
00487 {
00488     BYTE ret;
00489 
00490     if (c >= 'A' && c <= 'Z')
00491         ret = c - 'A';
00492     else if (c >= 'a' && c <= 'z')
00493         ret = c - 'a' + 26;
00494     else if (c >= '0' && c <= '9')
00495         ret = c - '0' + 52;
00496     else if (c == '+')
00497         ret = 62;
00498     else if (c == '/')
00499         ret = 63;
00500     else
00501         ret = 64;
00502     return ret;
00503 }
00504 
00505 static LONG decodeBase64Block(const char *in_buf, int in_len,
00506  const char **nextBlock, PBYTE out_buf, DWORD *out_len)
00507 {
00508     int len = in_len;
00509     const char *d = in_buf;
00510     int  ip0, ip1, ip2, ip3;
00511 
00512     if (len < 4)
00513         return ERROR_INVALID_DATA;
00514 
00515     if (d[2] == '=')
00516     {
00517         if ((ip0 = decodeBase64Byte(d[0])) > 63)
00518             return ERROR_INVALID_DATA;
00519         if ((ip1 = decodeBase64Byte(d[1])) > 63)
00520             return ERROR_INVALID_DATA;
00521 
00522         if (out_buf)
00523             out_buf[0] = (ip0 << 2) | (ip1 >> 4);
00524         *out_len = 1;
00525     }
00526     else if (d[3] == '=')
00527     {
00528         if ((ip0 = decodeBase64Byte(d[0])) > 63)
00529             return ERROR_INVALID_DATA;
00530         if ((ip1 = decodeBase64Byte(d[1])) > 63)
00531             return ERROR_INVALID_DATA;
00532         if ((ip2 = decodeBase64Byte(d[2])) > 63)
00533             return ERROR_INVALID_DATA;
00534 
00535         if (out_buf)
00536         {
00537             out_buf[0] = (ip0 << 2) | (ip1 >> 4);
00538             out_buf[1] = (ip1 << 4) | (ip2 >> 2);
00539         }
00540         *out_len = 2;
00541     }
00542     else
00543     {
00544         if ((ip0 = decodeBase64Byte(d[0])) > 63)
00545             return ERROR_INVALID_DATA;
00546         if ((ip1 = decodeBase64Byte(d[1])) > 63)
00547             return ERROR_INVALID_DATA;
00548         if ((ip2 = decodeBase64Byte(d[2])) > 63)
00549             return ERROR_INVALID_DATA;
00550         if ((ip3 = decodeBase64Byte(d[3])) > 63)
00551             return ERROR_INVALID_DATA;
00552 
00553         if (out_buf)
00554         {
00555             out_buf[0] = (ip0 << 2) | (ip1 >> 4);
00556             out_buf[1] = (ip1 << 4) | (ip2 >> 2);
00557             out_buf[2] = (ip2 << 6) |  ip3;
00558         }
00559         *out_len = 3;
00560     }
00561     if (len >= 6 && d[4] == '\r' && d[5] == '\n')
00562         *nextBlock = d + 6;
00563     else if (len >= 5 && d[4] == '\n')
00564         *nextBlock = d + 5;
00565     else if (len >= 4 && d[4])
00566         *nextBlock = d + 4;
00567     else
00568         *nextBlock = NULL;
00569     return ERROR_SUCCESS;
00570 }
00571 
00572 /* Unlike CryptStringToBinaryA, cchString is guaranteed to be the length of the
00573  * string to convert.
00574  */
00575 typedef LONG (*StringToBinaryAFunc)(LPCSTR pszString, DWORD cchString,
00576  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
00577 
00578 static LONG Base64ToBinaryA(LPCSTR pszString, DWORD cchString,
00579  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
00580 {
00581     LONG ret = ERROR_SUCCESS;
00582     const char *nextBlock;
00583     DWORD outLen = 0;
00584 
00585     nextBlock = pszString;
00586     while (nextBlock && !ret)
00587     {
00588         DWORD len = 0;
00589 
00590         ret = decodeBase64Block(nextBlock, cchString - (nextBlock - pszString),
00591          &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
00592         if (!ret)
00593             outLen += len;
00594         if (cchString - (nextBlock - pszString) <= 0)
00595             nextBlock = NULL;
00596     }
00597     *pcbBinary = outLen;
00598     if (!ret)
00599     {
00600         if (pdwSkip)
00601             *pdwSkip = 0;
00602         if (pdwFlags)
00603             *pdwFlags = CRYPT_STRING_BASE64;
00604     }
00605     else if (ret == ERROR_INSUFFICIENT_BUFFER)
00606     {
00607         if (!pbBinary)
00608             ret = ERROR_SUCCESS;
00609     }
00610     return ret;
00611 }
00612 
00613 static LONG Base64WithHeaderAndTrailerToBinaryA(LPCSTR pszString,
00614  DWORD cchString, LPCSTR header, LPCSTR trailer, BYTE *pbBinary,
00615  DWORD *pcbBinary, DWORD *pdwSkip, BOOL exactHeaderAndTrailerMatch)
00616 {
00617     LONG ret;
00618 
00619     LPCSTR headerBegins;
00620     LPCSTR dataBegins;
00621     LPCSTR trailerBegins;
00622     size_t dataLength;
00623 
00624     if ((strlen(header) + strlen(trailer)) > cchString)
00625     {
00626         return ERROR_INVALID_DATA;
00627     }
00628 
00629     if (!(headerBegins = strstr(pszString, header)))
00630     {
00631         TRACE("Can't find %s in %s.\n", header, pszString);
00632         return ERROR_INVALID_DATA;
00633     }
00634 
00635     dataBegins = headerBegins + strlen(header);
00636     if (!exactHeaderAndTrailerMatch)
00637     {
00638         if ((dataBegins = strstr(dataBegins, CERT_DELIMITER)))
00639         {
00640             dataBegins += strlen(CERT_DELIMITER);
00641         }
00642         else
00643         {
00644             return ERROR_INVALID_DATA;
00645         }
00646     }
00647     if (*dataBegins == '\r') dataBegins++;
00648     if (*dataBegins == '\n') dataBegins++;
00649 
00650     if (exactHeaderAndTrailerMatch)
00651     {
00652         trailerBegins = pszString + cchString - strlen(trailer);
00653         if (pszString[cchString - 1] == '\n') trailerBegins--;
00654         if (pszString[cchString - 2] == '\r') trailerBegins--;
00655 
00656         if (*(trailerBegins-1) == '\n') trailerBegins--;
00657         if (*(trailerBegins-1) == '\r') trailerBegins--;
00658 
00659         if (!strncmp(trailerBegins, trailer, strlen(trailer)))
00660         {
00661             return ERROR_INVALID_DATA;
00662         }
00663     }
00664     else
00665     {
00666         if (!(trailerBegins = strstr(dataBegins, trailer)))
00667         {
00668             return ERROR_INVALID_DATA;
00669         }
00670         if (*(trailerBegins-1) == '\n') trailerBegins--;
00671         if (*(trailerBegins-1) == '\r') trailerBegins--;
00672     }
00673 
00674     if (pdwSkip)
00675        *pdwSkip = headerBegins - pszString;
00676 
00677     dataLength = trailerBegins - dataBegins;
00678 
00679     ret = Base64ToBinaryA(dataBegins, dataLength, pbBinary, pcbBinary, NULL,
00680           NULL);
00681 
00682     return ret;
00683 }
00684 
00685 static LONG Base64HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
00686  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
00687 {
00688     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
00689      CERT_HEADER_START, CERT_TRAILER_START, pbBinary, pcbBinary, pdwSkip, FALSE);
00690 
00691     if (!ret && pdwFlags)
00692         *pdwFlags = CRYPT_STRING_BASE64HEADER;
00693     return ret;
00694 }
00695 
00696 static LONG Base64RequestHeaderToBinaryA(LPCSTR pszString, DWORD cchString,
00697  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
00698 {
00699     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
00700      CERT_REQUEST_HEADER, CERT_REQUEST_TRAILER, pbBinary, pcbBinary, pdwSkip, TRUE);
00701 
00702     if (!ret && pdwFlags)
00703         *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
00704     return ret;
00705 }
00706 
00707 static LONG Base64X509HeaderToBinaryA(LPCSTR pszString, DWORD cchString,
00708  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
00709 {
00710     LONG ret = Base64WithHeaderAndTrailerToBinaryA(pszString, cchString,
00711      X509_HEADER, X509_TRAILER, pbBinary, pcbBinary, pdwSkip, TRUE);
00712 
00713     if (!ret && pdwFlags)
00714         *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
00715     return ret;
00716 }
00717 
00718 static LONG Base64AnyToBinaryA(LPCSTR pszString, DWORD cchString,
00719  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
00720 {
00721     LONG ret;
00722 
00723     ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
00724      pdwSkip, pdwFlags);
00725     if (ret == ERROR_INVALID_DATA)
00726         ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
00727          pdwSkip, pdwFlags);
00728     return ret;
00729 }
00730 
00731 static LONG DecodeBinaryToBinaryA(LPCSTR pszString, DWORD cchString,
00732  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
00733 {
00734     LONG ret = ERROR_SUCCESS;
00735 
00736     if (*pcbBinary < cchString)
00737     {
00738         if (!pbBinary)
00739             *pcbBinary = cchString;
00740         else
00741         {
00742             ret = ERROR_INSUFFICIENT_BUFFER;
00743             *pcbBinary = cchString;
00744         }
00745     }
00746     else
00747     {
00748         if (cchString)
00749             memcpy(pbBinary, pszString, cchString);
00750         *pcbBinary = cchString;
00751     }
00752     return ret;
00753 }
00754 
00755 static LONG DecodeAnyA(LPCSTR pszString, DWORD cchString,
00756  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
00757 {
00758     LONG ret;
00759 
00760     ret = Base64HeaderToBinaryA(pszString, cchString, pbBinary, pcbBinary,
00761      pdwSkip, pdwFlags);
00762     if (ret == ERROR_INVALID_DATA)
00763         ret = Base64ToBinaryA(pszString, cchString, pbBinary, pcbBinary,
00764          pdwSkip, pdwFlags);
00765     if (ret == ERROR_INVALID_DATA)
00766         ret = DecodeBinaryToBinaryA(pszString, cchString, pbBinary, pcbBinary,
00767          pdwSkip, pdwFlags);
00768     return ret;
00769 }
00770 
00771 BOOL WINAPI CryptStringToBinaryA(LPCSTR pszString,
00772  DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
00773  DWORD *pdwSkip, DWORD *pdwFlags)
00774 {
00775     StringToBinaryAFunc decoder;
00776     LONG ret;
00777 
00778     TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_a(pszString),
00779      cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
00780 
00781     if (!pszString)
00782     {
00783         SetLastError(ERROR_INVALID_PARAMETER);
00784         return FALSE;
00785     }
00786     /* Only the bottom byte contains valid types */
00787     if (dwFlags & 0xfffffff0)
00788     {
00789         SetLastError(ERROR_INVALID_DATA);
00790         return FALSE;
00791     }
00792     switch (dwFlags)
00793     {
00794     case CRYPT_STRING_BASE64_ANY:
00795         decoder = Base64AnyToBinaryA;
00796         break;
00797     case CRYPT_STRING_BASE64:
00798         decoder = Base64ToBinaryA;
00799         break;
00800     case CRYPT_STRING_BASE64HEADER:
00801         decoder = Base64HeaderToBinaryA;
00802         break;
00803     case CRYPT_STRING_BASE64REQUESTHEADER:
00804         decoder = Base64RequestHeaderToBinaryA;
00805         break;
00806     case CRYPT_STRING_BASE64X509CRLHEADER:
00807         decoder = Base64X509HeaderToBinaryA;
00808         break;
00809     case CRYPT_STRING_BINARY:
00810         decoder = DecodeBinaryToBinaryA;
00811         break;
00812     case CRYPT_STRING_ANY:
00813         decoder = DecodeAnyA;
00814         break;
00815     case CRYPT_STRING_HEX:
00816     case CRYPT_STRING_HEXASCII:
00817     case CRYPT_STRING_HEXADDR:
00818     case CRYPT_STRING_HEXASCIIADDR:
00819         FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
00820         /* fall through */
00821     default:
00822         SetLastError(ERROR_INVALID_PARAMETER);
00823         return FALSE;
00824     }
00825     if (!cchString)
00826         cchString = strlen(pszString);
00827     ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
00828     if (ret)
00829         SetLastError(ret);
00830     return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
00831 }
00832 
00833 static LONG decodeBase64BlockW(const WCHAR *in_buf, int in_len,
00834  const WCHAR **nextBlock, PBYTE out_buf, DWORD *out_len)
00835 {
00836     int len = in_len, i;
00837     const WCHAR *d = in_buf;
00838     int  ip0, ip1, ip2, ip3;
00839 
00840     if (len < 4)
00841         return ERROR_INVALID_DATA;
00842 
00843     i = 0;
00844     if (d[2] == '=')
00845     {
00846         if ((ip0 = decodeBase64Byte(d[0])) > 63)
00847             return ERROR_INVALID_DATA;
00848         if ((ip1 = decodeBase64Byte(d[1])) > 63)
00849             return ERROR_INVALID_DATA;
00850 
00851         if (out_buf)
00852             out_buf[i] = (ip0 << 2) | (ip1 >> 4);
00853         i++;
00854     }
00855     else if (d[3] == '=')
00856     {
00857         if ((ip0 = decodeBase64Byte(d[0])) > 63)
00858             return ERROR_INVALID_DATA;
00859         if ((ip1 = decodeBase64Byte(d[1])) > 63)
00860             return ERROR_INVALID_DATA;
00861         if ((ip2 = decodeBase64Byte(d[2])) > 63)
00862             return ERROR_INVALID_DATA;
00863 
00864         if (out_buf)
00865         {
00866             out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
00867             out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
00868         }
00869         i += 2;
00870     }
00871     else
00872     {
00873         if ((ip0 = decodeBase64Byte(d[0])) > 63)
00874             return ERROR_INVALID_DATA;
00875         if ((ip1 = decodeBase64Byte(d[1])) > 63)
00876             return ERROR_INVALID_DATA;
00877         if ((ip2 = decodeBase64Byte(d[2])) > 63)
00878             return ERROR_INVALID_DATA;
00879         if ((ip3 = decodeBase64Byte(d[3])) > 63)
00880             return ERROR_INVALID_DATA;
00881 
00882         if (out_buf)
00883         {
00884             out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4);
00885             out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2);
00886             out_buf[i + 2] = (ip2 << 6) |  ip3;
00887         }
00888         i += 3;
00889     }
00890     if (len >= 6 && d[4] == '\r' && d[5] == '\n')
00891         *nextBlock = d + 6;
00892     else if (len >= 5 && d[4] == '\n')
00893         *nextBlock = d + 5;
00894     else if (len >= 4 && d[4])
00895         *nextBlock = d + 4;
00896     else
00897         *nextBlock = NULL;
00898     *out_len = i;
00899     return ERROR_SUCCESS;
00900 }
00901 
00902 /* Unlike CryptStringToBinaryW, cchString is guaranteed to be the length of the
00903  * string to convert.
00904  */
00905 typedef LONG (*StringToBinaryWFunc)(LPCWSTR pszString, DWORD cchString,
00906  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags);
00907 
00908 static LONG Base64ToBinaryW(LPCWSTR pszString, DWORD cchString,
00909  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
00910 {
00911     LONG ret = ERROR_SUCCESS;
00912     const WCHAR *nextBlock;
00913     DWORD outLen = 0;
00914 
00915     nextBlock = pszString;
00916     while (nextBlock && !ret)
00917     {
00918         DWORD len = 0;
00919 
00920         ret = decodeBase64BlockW(nextBlock, cchString - (nextBlock - pszString),
00921          &nextBlock, pbBinary ? pbBinary + outLen : NULL, &len);
00922         if (!ret)
00923             outLen += len;
00924         if (cchString - (nextBlock - pszString) <= 0)
00925             nextBlock = NULL;
00926     }
00927     *pcbBinary = outLen;
00928     if (!ret)
00929     {
00930         if (pdwSkip)
00931             *pdwSkip = 0;
00932         if (pdwFlags)
00933             *pdwFlags = CRYPT_STRING_BASE64;
00934     }
00935     else if (ret == ERROR_INSUFFICIENT_BUFFER)
00936     {
00937         if (!pbBinary)
00938             ret = ERROR_SUCCESS;
00939     }
00940     return ret;
00941 }
00942 
00943 static LONG Base64WithHeaderAndTrailerToBinaryW(LPCWSTR pszString,
00944  DWORD cchString, LPCWSTR header, LPCWSTR trailer, BYTE *pbBinary,
00945  DWORD *pcbBinary, DWORD *pdwSkip, BOOL exactHeaderAndTrailerMatch)
00946 {
00947     LONG ret;
00948 
00949     LPCWSTR headerBegins;
00950     LPCWSTR dataBegins;
00951     LPCWSTR trailerBegins;
00952     size_t dataLength;
00953 
00954     if ((strlenW(header) + strlenW(trailer)) > cchString)
00955     {
00956         return ERROR_INVALID_DATA;
00957     }
00958 
00959     if (!(headerBegins = strstrW(pszString, header)))
00960     {
00961         TRACE("Can't find %s in %s.\n", debugstr_w(header), debugstr_w(pszString));
00962         return ERROR_INVALID_DATA;
00963     }
00964 
00965     dataBegins = headerBegins + strlenW(header);
00966     if (!exactHeaderAndTrailerMatch)
00967     {
00968         if ((dataBegins = strstrW(dataBegins, CERT_DELIMITER_W)))
00969         {
00970             dataBegins += strlenW(CERT_DELIMITER_W);
00971         }
00972         else
00973         {
00974             return ERROR_INVALID_DATA;
00975         }
00976     }
00977     if (*dataBegins == '\r') dataBegins++;
00978     if (*dataBegins == '\n') dataBegins++;
00979 
00980     if (exactHeaderAndTrailerMatch)
00981     {
00982         trailerBegins = pszString + cchString - strlenW(trailer);
00983         if (pszString[cchString - 1] == '\n') trailerBegins--;
00984         if (pszString[cchString - 2] == '\r') trailerBegins--;
00985 
00986         if (*(trailerBegins-1) == '\n') trailerBegins--;
00987         if (*(trailerBegins-1) == '\r') trailerBegins--;
00988 
00989         if (!strncmpW(trailerBegins, trailer, strlenW(trailer)))
00990         {
00991             return ERROR_INVALID_DATA;
00992         }
00993     }
00994     else
00995     {
00996         if (!(trailerBegins = strstrW(dataBegins, trailer)))
00997         {
00998             return ERROR_INVALID_DATA;
00999         }
01000         if (*(trailerBegins-1) == '\n') trailerBegins--;
01001         if (*(trailerBegins-1) == '\r') trailerBegins--;
01002     }
01003 
01004     if (pdwSkip)
01005        *pdwSkip = headerBegins - pszString;
01006 
01007     dataLength = trailerBegins - dataBegins;
01008 
01009     ret = Base64ToBinaryW(dataBegins, dataLength, pbBinary, pcbBinary, NULL,
01010           NULL);
01011 
01012     return ret;
01013 }
01014 
01015 static LONG Base64HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
01016  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
01017 {
01018     LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
01019      CERT_HEADER_START_W, CERT_TRAILER_START_W, pbBinary, pcbBinary,
01020      pdwSkip, FALSE);
01021 
01022     if (!ret && pdwFlags)
01023         *pdwFlags = CRYPT_STRING_BASE64HEADER;
01024     return ret;
01025 }
01026 
01027 static LONG Base64RequestHeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
01028  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
01029 {
01030     LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
01031      CERT_REQUEST_HEADER_W, CERT_REQUEST_TRAILER_W, pbBinary, pcbBinary,
01032      pdwSkip, TRUE);
01033 
01034     if (!ret && pdwFlags)
01035         *pdwFlags = CRYPT_STRING_BASE64REQUESTHEADER;
01036     return ret;
01037 }
01038 
01039 static LONG Base64X509HeaderToBinaryW(LPCWSTR pszString, DWORD cchString,
01040  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
01041 {
01042     LONG ret = Base64WithHeaderAndTrailerToBinaryW(pszString, cchString,
01043      X509_HEADER_W, X509_TRAILER_W, pbBinary, pcbBinary, pdwSkip, TRUE);
01044 
01045     if (!ret && pdwFlags)
01046         *pdwFlags = CRYPT_STRING_BASE64X509CRLHEADER;
01047     return ret;
01048 }
01049 
01050 static LONG Base64AnyToBinaryW(LPCWSTR pszString, DWORD cchString,
01051  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
01052 {
01053     LONG ret;
01054 
01055     ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
01056      pdwSkip, pdwFlags);
01057     if (ret == ERROR_INVALID_DATA)
01058         ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
01059          pdwSkip, pdwFlags);
01060     return ret;
01061 }
01062 
01063 static LONG DecodeBinaryToBinaryW(LPCWSTR pszString, DWORD cchString,
01064  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
01065 {
01066     LONG ret = ERROR_SUCCESS;
01067 
01068     if (*pcbBinary < cchString)
01069     {
01070         if (!pbBinary)
01071             *pcbBinary = cchString;
01072         else
01073         {
01074             ret = ERROR_INSUFFICIENT_BUFFER;
01075             *pcbBinary = cchString;
01076         }
01077     }
01078     else
01079     {
01080         if (cchString)
01081             memcpy(pbBinary, pszString, cchString * sizeof(WCHAR));
01082         *pcbBinary = cchString * sizeof(WCHAR);
01083     }
01084     return ret;
01085 }
01086 
01087 static LONG DecodeAnyW(LPCWSTR pszString, DWORD cchString,
01088  BYTE *pbBinary, DWORD *pcbBinary, DWORD *pdwSkip, DWORD *pdwFlags)
01089 {
01090     LONG ret;
01091 
01092     ret = Base64HeaderToBinaryW(pszString, cchString, pbBinary, pcbBinary,
01093      pdwSkip, pdwFlags);
01094     if (ret == ERROR_INVALID_DATA)
01095         ret = Base64ToBinaryW(pszString, cchString, pbBinary, pcbBinary,
01096          pdwSkip, pdwFlags);
01097     if (ret == ERROR_INVALID_DATA)
01098         ret = DecodeBinaryToBinaryW(pszString, cchString, pbBinary, pcbBinary,
01099          pdwSkip, pdwFlags);
01100     return ret;
01101 }
01102 
01103 BOOL WINAPI CryptStringToBinaryW(LPCWSTR pszString,
01104  DWORD cchString, DWORD dwFlags, BYTE *pbBinary, DWORD *pcbBinary,
01105  DWORD *pdwSkip, DWORD *pdwFlags)
01106 {
01107     StringToBinaryWFunc decoder;
01108     LONG ret;
01109 
01110     TRACE("(%s, %d, %08x, %p, %p, %p, %p)\n", debugstr_w(pszString),
01111      cchString, dwFlags, pbBinary, pcbBinary, pdwSkip, pdwFlags);
01112 
01113     if (!pszString)
01114     {
01115         SetLastError(ERROR_INVALID_PARAMETER);
01116         return FALSE;
01117     }
01118     /* Only the bottom byte contains valid types */
01119     if (dwFlags & 0xfffffff0)
01120     {
01121         SetLastError(ERROR_INVALID_DATA);
01122         return FALSE;
01123     }
01124     switch (dwFlags)
01125     {
01126     case CRYPT_STRING_BASE64_ANY:
01127         decoder = Base64AnyToBinaryW;
01128         break;
01129     case CRYPT_STRING_BASE64:
01130         decoder = Base64ToBinaryW;
01131         break;
01132     case CRYPT_STRING_BASE64HEADER:
01133         decoder = Base64HeaderToBinaryW;
01134         break;
01135     case CRYPT_STRING_BASE64REQUESTHEADER:
01136         decoder = Base64RequestHeaderToBinaryW;
01137         break;
01138     case CRYPT_STRING_BASE64X509CRLHEADER:
01139         decoder = Base64X509HeaderToBinaryW;
01140         break;
01141     case CRYPT_STRING_BINARY:
01142         decoder = DecodeBinaryToBinaryW;
01143         break;
01144     case CRYPT_STRING_ANY:
01145         decoder = DecodeAnyW;
01146         break;
01147     case CRYPT_STRING_HEX:
01148     case CRYPT_STRING_HEXASCII:
01149     case CRYPT_STRING_HEXADDR:
01150     case CRYPT_STRING_HEXASCIIADDR:
01151         FIXME("Unimplemented type %d\n", dwFlags & 0x7fffffff);
01152         /* fall through */
01153     default:
01154         SetLastError(ERROR_INVALID_PARAMETER);
01155         return FALSE;
01156     }
01157     if (!cchString)
01158         cchString = strlenW(pszString);
01159     ret = decoder(pszString, cchString, pbBinary, pcbBinary, pdwSkip, pdwFlags);
01160     if (ret)
01161         SetLastError(ret);
01162     return (ret == ERROR_SUCCESS) ? TRUE : FALSE;
01163 }

Generated on Sun May 27 2012 04:23:10 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.