/**************************************************************************/ // 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; } /**************************************************************************/