/* * base64 encoder/decoder * * Copyright 2005 by Kai Blin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "windef.h" #include "winerror.h" #include "sspi.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(secur32); static const char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; SECURITY_STATUS encodeBase64(PBYTE in_buf, int in_len, char* out_buf, int max_len, int *out_len) { int div, i; PBYTE d = in_buf; int bytes = (in_len*8 + 5)/6, pad_bytes = (bytes % 4) ? 4 - (bytes % 4) : 0; TRACE("bytes is %d, pad bytes is %d\n", bytes, pad_bytes); *out_len = bytes + pad_bytes; if(bytes + pad_bytes + 1 > max_len) return SEC_E_BUFFER_TOO_SMALL; /* Three bytes of input give 4 chars of output */ div = in_len / 3; i = 0; while(div > 0) { /* first char is the first 6 bits of the first byte*/ out_buf[i + 0] = b64[ ( d[0] >> 2) & 0x3f ]; /* second char is the last 2 bits of the first byte and the first 4 * bits of the second byte */ out_buf[i + 1] = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)]; /* third char is the last 4 bits of the second byte and the first 2 * bits of the third byte */ out_buf[i + 2] = b64[ ((d[1] << 2) & 0x3c) | (d[2] >> 6 & 0x03)]; /* fourth char is the remaining 6 bits of the third byte */ out_buf[i + 3] = b64[ d[2] & 0x3f]; i += 4; d += 3; div--; } switch(pad_bytes) { case 1: /* first char is the first 6 bits of the first byte*/ out_buf[i + 0] = b64[ ( d[0] >> 2) & 0x3f ]; /* second char is the last 2 bits of the first byte and the first 4 * bits of the second byte */ out_buf[i + 1] = b64[ ((d[0] << 4) & 0x30) | (d[1] >> 4 & 0x0f)]; /* third char is the last 4 bits of the second byte padded with * two zeroes */ out_buf[i + 2] = b64[ ((d[1] >> 4) & 0x3c) ]; /* fourth char is a = to indicate one byte of padding */ out_buf[i + 3] = '='; out_buf[i + 4] = 0; break; case 2: /* first char is the first 6 bits of the first byte*/ out_buf[i + 0] = b64[ ( d[0] >> 2) & 0x3f ]; /* second char is the last 2 bits of the first byte padded with * four zeroes*/ out_buf[i + 1] = b64[ ((d[0] << 4) & 0x30)]; /* third char is = to indicate padding */ out_buf[i + 2] = '='; /* fourth char is = to indicate padding */ out_buf[i + 3] = '='; out_buf[i + 4] = 0; break; default: out_buf[i] = 0; } return SEC_E_OK; } static inline BYTE decode(char c) { if( c >= 'A' && c <= 'Z') return c - 'A'; if( c >= 'a' && c <= 'z') return c - 'a' + 26; if( c >= '0' && c <= '9') return c - '0' + 52; if( c == '+') return 62; if( c == '/') return 63; else return 64; } SECURITY_STATUS decodeBase64(char *in_buf, int in_len, PBYTE out_buf, int max_len, int *out_len) { int len = in_len, i; char *d = in_buf; int ip0, ip1, ip2, ip3; TRACE("in_len: %d\n", in_len); if((in_len % 4) != 0) return SEC_E_INVALID_TOKEN; if(in_len > max_len) return SEC_E_BUFFER_TOO_SMALL; i = 0; while(len > 4) { if((ip0 = decode(d[0])) > 63) return SEC_E_INVALID_TOKEN; if((ip1 = decode(d[1])) > 63) return SEC_E_INVALID_TOKEN; if((ip2 = decode(d[2])) > 63) return SEC_E_INVALID_TOKEN; if((ip3 = decode(d[3])) > 63) return SEC_E_INVALID_TOKEN; out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4); out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2); out_buf[i + 2] = (ip2 << 6) | ip3; len -= 4; i += 3; d += 4; } if(d[2] == '=') { if((ip0 = decode(d[0])) > 63) return SEC_E_INVALID_TOKEN; if((ip1 = decode(d[1])) > 63) return SEC_E_INVALID_TOKEN; out_buf[i] = (ip0 << 2) | (ip1 >> 4); i++; } else if(d[3] == '=') { if((ip0 = decode(d[0])) > 63) return SEC_E_INVALID_TOKEN; if((ip1 = decode(d[1])) > 63) return SEC_E_INVALID_TOKEN; if((ip2 = decode(d[2])) > 63) return SEC_E_INVALID_TOKEN; out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4); out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2); i += 2; } else { if((ip0 = decode(d[0])) > 63) return SEC_E_INVALID_TOKEN; if((ip1 = decode(d[1])) > 63) return SEC_E_INVALID_TOKEN; if((ip2 = decode(d[2])) > 63) return SEC_E_INVALID_TOKEN; if((ip3 = decode(d[3])) > 63) return SEC_E_INVALID_TOKEN; out_buf[i + 0] = (ip0 << 2) | (ip1 >> 4); out_buf[i + 1] = (ip1 << 4) | (ip2 >> 2); out_buf[i + 2] = (ip2 << 6) | ip3; i += 3; } *out_len = i; return SEC_E_OK; }