/**************************************************************************/
// base64.cpp -
/**************************************************************************/
/*
* Base64 decoder/decoder v0.3 - written by Michael Garratt(c)1998-2002
*
* Only decodes base64 strings less than 4KB as this was written
* to decode username:password info used in HTTP/1.0 as per RFC 1945
* wouldn't be hard to make it support any length... just wasn't
* required for what I wrote it for.
*
* This function now also handles url encoding.
*
* Use however you like just keep the copyright notice in file.
* #include <std.disclaimer>
*/
/**************************************************************************/
#include "websrv.h"
#include "include.h"
/**************************************************************************/
static int invalid;
/**************************************************************************/
char base64code[64]=
{
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
};
/**************************************************************************/
// takes a base64 character, returns its value
// from RFC 2045 Table 1 - The Base64 Alphabet
int getBase64Value(char code){
int val= (int)code;
int result;
if (val>='A' && val<='Z')
result= val-65;
else if (val>='a' && val<='z')
result= val-71;
else if (val>='0' && val<='9')
result= val+4;
else if (val=='+')
result=62;
else if (val=='/')
result=63;
else if (val=='=')
result=0;
else{
bugf("Invalid non base64 character %c (%d)", code, code);
invalid=true;
return 0;
}
return result;
}
/**************************************************************************/
char * decodeBase64(char *coded_with_linebreaks)
{
int i;
int j=0;
static char result[4100];
char d[4100];
char *s, *coded;
invalid=false;
i=str_len(coded_with_linebreaks);
if (i>4096){
bugf("base64 string to long to be a password.\n");
return NULL;
}
// copy coded_with_linebreaks, over to coded without newlines or spaces
s=coded_with_linebreaks;
coded=d;
while(*s){
if(!is_space(*s) && *s!='\n' && *s!='\r' ){
*coded++=*s++;
}else{
s++;
}
}
*coded='\0';
i=str_len(coded);
if (i%4!=0){
bugf("Not a valid base64 string - incorrect length.\n");
return NULL;
}
coded=d;
// go thru converting each 4 base64 bytes into 3 8bit bytes
for (; coded[0]!='\0'; coded+=4){
result[j++] = (char)(getBase64Value(coded[0])<<2
| getBase64Value(coded[1])>>4);
result[j++] = (char)(getBase64Value(coded[1])<<4
| getBase64Value(coded[2])>>2);
result[j++] = (char)(getBase64Value(coded[2])<<6
| getBase64Value(coded[3]));
}
if(invalid)
return NULL;
result[j]=0;
if (*(--coded)=='='){
if (j>0){
if (*(--coded)=='='){
result[j-2]='\0';
}else{
result[j-1]='\0';
}
}
}
return (result);
}
/**************************************************************************/
char * encodeBase64(char *plaintext, int len)
{
static char result[4100];
unsigned char *pt=(unsigned char *)plaintext;
int i;
int j=0;
int bytes;
if(len<0){
len=str_len(plaintext);
}
len-=2;
// go thru converting every 3 bytes into 4 base64 bytes
for (i=0; i < len; i+=3){
bytes= (pt[i]<<16)
+ (pt[i+1]<<8)
+ (pt[i+2]);
result[j++] = base64code[(bytes>>18) & 0x3F];
result[j++] = base64code[(bytes>>12) & 0x3F];
result[j++] = base64code[(bytes>>6) & 0x3F];
result[j++] = base64code[(bytes) & 0x3F];
if(i%57==54){
result[j++]='\r';
result[j++]='\n';
}
}
// pad the remaining characters
switch((i-len)%3){
case 2: // exact fit
break;
case 0: // two more characters to save
bytes= (pt[i]<<16) + (pt[i+1]<<8);
result[j++] = base64code[(bytes>>18) & 0x3F];
result[j++] = base64code[(bytes>>12) & 0x3F];
result[j++] = base64code[(bytes>>6) & 0x3F];
result[j++] = '=';
break;
case 1: // one more character to save
bytes= pt[i]<<16;
result[j++] = base64code[(bytes>>18) & 0x3F];
result[j++] = base64code[(bytes>>12) & 0x3F];
result[j++] = '=';
result[j++] = '=';
break;
break;
}
result[j]='\0';
return (result);
}
/**************************************************************************/
const char *url_encode_table[]={ // as per RFC1728
"%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07",
"%08", "%09", "%0A", "%0B", "%0C", "%0D", "%0E", "%0F",
"%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
"%18", "%19", "%1A", "%1B", "%1C", "%1D", "%1E", "%1F",
"+", "!", "%22", "%23", "$", "%25", "%26", "%27",
"(", ")", "*", "%2B", ",", "-", ".", "%2F",
"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "%3A", "%3B", "%3C", "%3D", "%3E", "%3F",
"%40", "A", "B", "C", "D", "E", "F", "G",
"H", "I", "J", "K", "L", "M", "N", "O",
"P", "Q", "R", "S", "T", "U", "V", "W",
"X", "Y", "Z", "%5B", "%5C", "%5D", "%5E", "_",
"%60", "a", "b", "c", "d", "e", "f", "g",
"h", "i", "j", "k", "l", "m", "n", "o",
"p", "q", "r", "s", "t", "u", "v", "w",
"x", "y", "z", "%7B", "%7C", "%7D", "%7E", "%7F",
"%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87",
"%88", "%89", "%8A", "%8B", "%8C", "%8D", "%8E", "%8F",
"%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97",
"%98", "%99", "%9A", "%9B", "%9C", "%9D", "%9E", "%9F",
"%A0", "%A1", "%A2", "%A3", "%A4", "%A5", "%A6", "%A7",
"%A8", "%A9", "%AA", "%AB", "%AC", "%AD", "%AE", "%AF",
"%B0", "%B1", "%B2", "%B3", "%B4", "%B5", "%B6", "%B7",
"%B8", "%B9", "%BA", "%BB", "%BC", "%BD", "%BE", "%BF",
"%C0", "%C1", "%C2", "%C3", "%C4", "%C5", "%C6", "%C7",
"%C8", "%C9", "%CA", "%CB", "%CC", "%CD", "%CE", "%CF",
"%D0", "%D1", "%D2", "%D3", "%D4", "%D5", "%D6", "%D7",
"%D8", "%D9", "%DA", "%DB", "%DC", "%DD", "%DE", "%DF",
"%E0", "%E1", "%E2", "%E3", "%E4", "%E5", "%E6", "%E7",
"%E8", "%E9", "%EA", "%EB", "%EC", "%ED", "%EE", "%EF",
"%F0", "%F1", "%F2", "%F3", "%F4", "%F5", "%F6", "%F7",
"%F8", "%F9", "%FA", "%FB", "%FC", "%FD", "%FE", "%FF"
};
/**************************************************************************/
char *url_encode_post_data(char *postdata)
{
static char *result; // managed result buffer
// nothing to do with empty strings
if( IS_NULLSTR(postdata)){
return "";
}
manage_dynamic_buffer(&result, str_len(postdata)*3+1); // maintain result so always has enough space
char *d=result; // dest
unsigned char *s; // src
const char *t; // text
for(s=(unsigned char*)postdata; *s; s++){
t=url_encode_table[*s];
while(*t){
*d++=*t++;
}
}
*d='\0'; // terminate the result
return result;
}
/**************************************************************************/