Drizzled Public API Documentation

CSEncode.cc

00001 /* Copyright (C) 2008 PrimeBase Technologies GmbH, Germany
00002  *
00003  * PrimeBase S3Daemon
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
00018  *
00019  *  Created by Barry Leslie on 10/21/08.
00020  *
00021  */
00022  
00023 #include "CSConfig.h"
00024 #include <ctype.h>
00025 
00026 #include "CSGlobal.h"
00027 #include "CSString.h"
00028 
00029 #include "CSEncode.h"
00030 
00031 static const u_char base64URLMap[64] = {
00032   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 
00033   'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 
00034   'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 
00035   'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 
00036   'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 
00037   'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 
00038   'w', 'x', 'y', 'z', '0', '1', '2', '3', 
00039   '4', '5', '6', '7', '8', '9', '-', '_'
00040 };
00041 static const u_char base64STDMap[64] = {
00042   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 
00043   'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 
00044   'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 
00045   'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 
00046   'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 
00047   'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 
00048   'w', 'x', 'y', 'z', '0', '1', '2', '3', 
00049   '4', '5', '6', '7', '8', '9', '+', '/'
00050 };
00051  
00052 static const u_char decodeBase64Map[128] = {
00053   0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 
00054   0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 
00055   0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 
00056   0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 
00057   0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 
00058   0XFF, 0XFF, 0XFF, 0X3E, 0XFF, 0X3E, 0XFF, 0X3F, 
00059   0X34, 0X35, 0X36, 0X37, 0X38, 0X39, 0X3A, 0X3B, 
00060   0X3C, 0X3D, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 
00061   0XFF, 0X00, 0X01, 0X02, 0X03, 0X04, 0X05, 0X06, 
00062   0X07, 0X08, 0X09, 0X0A, 0X0B, 0X0C, 0X0D, 0X0E, 
00063   0X0F, 0X10, 0X11, 0X12, 0X13, 0X14, 0X15, 0X16, 
00064   0X17, 0X18, 0X19, 0XFF, 0XFF, 0XFF, 0XFF, 0X3F, 
00065   0XFF, 0X1A, 0X1B, 0X1C, 0X1D, 0X1E, 0X1F, 0X20, 
00066   0X21, 0X22, 0X23, 0X24, 0X25, 0X26, 0X27, 0X28, 
00067   0X29, 0X2A, 0X2B, 0X2C, 0X2D, 0X2E, 0X2F, 0X30, 
00068   0X31, 0X32, 0X33, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 
00069 };
00070 
00071 //------------------
00072 static bool base64Encoded(const u_char *data, size_t len, const u_char *vc)
00073 {
00074   if (len % 4)
00075     return false;
00076     
00077   size_t i = len;
00078   
00079   while ( i && data[i-1] == '=') i--;
00080   
00081   if ( (len - i) > 2)
00082     return false;
00083     
00084   for (; i ; i--, data++) {
00085     if (((*data < 'A') || (*data > 'Z')) &&
00086       ((*data < 'a') || (*data > 'z')) &&
00087       ((*data < '0') || (*data > '9')) &&
00088       ((*data != vc[0]) && (*data != vc[1])))
00089       return false;
00090   }
00091   
00092   return true; // Actually this isn't so much 'true' as 'maybe'
00093 }
00094 
00095 //------------------
00096 static char *genericBase64Encode(const void *data, size_t len, char *encode_buffer, size_t encode_buffer_len, const u_char base64Map[])
00097 {
00098   u_char *wptr, *rptr, *encoding;
00099   size_t size;
00100   enter_();
00101 
00102   size = ((len + 2) / 3) * 4 +1;
00103   if ((encode_buffer != NULL) && (encode_buffer_len < size)) 
00104     CSException::throwException(CS_CONTEXT, CS_ERR_GENERIC_ERROR, "Base64 encode buffer is too small.");
00105   
00106   if (encode_buffer)
00107     encoding = (u_char *) encode_buffer;
00108   else
00109     encoding = (u_char *) cs_malloc(size);
00110     
00111   size--;
00112   encoding[size] = 0;
00113   
00114   wptr= encoding;
00115   rptr = (u_char *) data;
00116   
00117   while (len/3) {   
00118     wptr[0] = base64Map[rptr[0] >>2];
00119     wptr[1] = base64Map[((rptr[0] & 0X03) <<4) + (rptr[1] >> 4)];
00120     wptr[2] = base64Map[((rptr[1] & 0X0F) <<2) + (rptr[2] >> 6)];
00121     wptr[3] = base64Map[(rptr[2] & 0X3F)];
00122     rptr += 3;
00123     wptr += 4;
00124     len -=3;
00125   }
00126   
00127   if (len) {
00128     wptr[0] = base64Map[rptr[0] >>2];
00129 
00130     if (len == 1) {
00131       wptr[1] = base64Map[(rptr[0] & 0x03) << 4]; 
00132       wptr[2] = wptr[3] = '=';
00133     } else {
00134       wptr[1] = base64Map[((rptr[0] & 0X03) <<4) + (rptr[1] >> 4)];
00135       wptr[2] = base64Map[(rptr[1] & 0X0F) <<2];
00136       wptr[3] = '=';
00137     }
00138     
00139   }
00140   
00141   return_((char*)encoding);
00142 }
00143 
00144 //------------------
00145 static void *genericBase64Decode(const char *data, size_t len, void *decode_buffer, size_t decode_buffer_len, const u_char base64Map[])
00146 {
00147   u_char *wptr, *rptr, *decoding;
00148   enter_();
00149 
00150   rptr = (u_char *) data;
00151 
00152   if (!base64Encoded(rptr, len, base64Map +62)) 
00153     CSException::throwException(CS_CONTEXT, CS_ERR_GENERIC_ERROR, "String was not Base64 encoded.");
00154   
00155   if ((decode_buffer != NULL) && (decode_buffer_len < ((len/ 4) * 3))) 
00156     CSException::throwException(CS_CONTEXT, CS_ERR_GENERIC_ERROR, "Base64 decoded buffer is too small.");
00157   
00158   if (decode_buffer)
00159     decoding = (u_char *) decode_buffer;
00160   else
00161     decoding = (u_char *) cs_malloc((len/ 4) * 3);
00162   
00163   wptr= decoding;
00164   
00165   while (rptr[len-1] == '=') 
00166     len--; 
00167 
00168   while (len/4) {   
00169     wptr[0] = ( ((decodeBase64Map[rptr[0]] << 2) & 0xFF) | ((decodeBase64Map[rptr[1]] >> 4) & 0x03) ); 
00170     wptr[1] = ( ((decodeBase64Map[rptr[1]] << 4) & 0xFF) | ((decodeBase64Map[rptr[2]] >> 2) & 0x0F) ); 
00171     wptr[2] = ( ((decodeBase64Map[rptr[2]] << 6) & 0xFF) | (decodeBase64Map[rptr[3]] & 0x3F) ); 
00172 
00173     rptr += 4;
00174     wptr += 3;
00175     len -=4;
00176   }
00177   
00178   if (len) {
00179     wptr[0] = ( ((decodeBase64Map[rptr[0]] << 2) & 0xFF) |  ((decodeBase64Map[rptr[1]] >> 4) & 0x03) ); 
00180     if (len == 2) 
00181       wptr[1] = ( ((decodeBase64Map[rptr[1]] << 4) & 0xFF) | ((decodeBase64Map[rptr[2]] >> 2) & 0x0F) ); 
00182   }
00183   
00184   return_(decoding);
00185 }
00186 
00187 //------------------
00188 char *base64Encode(const void *data, size_t len, char *encode_buffer, size_t encode_buffer_len)
00189 {
00190   return genericBase64Encode(data, len, encode_buffer, encode_buffer_len, base64STDMap);
00191 }
00192 
00193 //------------------
00194 void *base64Decode(const char *data, size_t len, void *decode_buffer, size_t decode_buffer_len)
00195 {
00196   return genericBase64Decode(data, len, decode_buffer, decode_buffer_len, base64STDMap);
00197 }
00198 
00199 //------------------
00200 char *base64UrlEncode(const void *data, size_t len, char *encode_buffer, size_t encode_buffer_len)
00201 {
00202   return genericBase64Encode(data, len, encode_buffer, encode_buffer_len, base64URLMap);
00203 }
00204 
00205 //------------------
00206 void *base64UrlDecode(const char *data, size_t len, void *decode_buffer, size_t decode_buffer_len)
00207 {
00208   return genericBase64Decode(data, len, decode_buffer, decode_buffer_len, base64URLMap);
00209 }
00210 
00211 #ifdef NOT_USED
00212 //-----------------------------------------------------
00213 void  hmac_md5(u_char *text, size_t text_len, u_char *key, size_t key_len, Md5Digest *digest)
00214 {
00215   CSMd5 md5;
00216   unsigned char k_ipad[65];    /* inner padding -
00217                   * key XORd with ipad
00218                   */
00219   unsigned char k_opad[65];    /* outer padding -
00220                   * key XORd with opad
00221                   */
00222   unsigned char tk[16];
00223   int i;
00224   
00225   /* if key is longer than 64 bytes reset it to key=MD5(key) */
00226   if (key_len > 64) {
00227     CSMd5 tmd5;
00228 
00229     md5.md5_init();
00230     md5.md5_append(key, key_len);
00231     md5.md5_digest(digest);
00232 
00233     key = digest->val;
00234     key_len = 16;
00235   }
00236 
00237   /* start out by storing key in pads */
00238   memset(k_ipad, 0, sizeof(k_ipad));
00239   memset(k_opad, 0, sizeof(k_opad));
00240 
00241   memcpy(k_ipad, key, key_len);
00242   memcpy(k_opad, key, key_len);
00243 
00244   /* XOR key with ipad and opad values */
00245   for (i=0; i<64; i++) {
00246     k_ipad[i] ^= 0x36;
00247     k_opad[i] ^= 0x5c;
00248   }
00249   /*
00250    * perform inner encoding
00251    */
00252   md5.md5_init();
00253   md5.md5_append(k_ipad, 64);
00254   md5.md5_append(text, strlen(text));
00255   md5.md5_digest(digest);
00256 
00257   /*
00258    * perform outer encoding
00259    */
00260   md5.md5_init();
00261   md5.md5_append(k_opad, 64);
00262   md5.md5_append((u_char*)digest, 16);
00263   md5.md5_digest(digest);
00264   
00265 }
00266 
00267 #endif // NOT_USED
00268 
00269 //-----------------------------------------------------
00270 void  hmac_sha1(const char *text, const char *key, Sha1Digest *digest)
00271 {
00272   CSSha1 sha1;
00273   size_t key_len = strlen(key);
00274   unsigned char k_ipad[65];    /* inner padding -
00275                   * key XORd with ipad
00276                   */
00277   unsigned char k_opad[65];    /* outer padding -
00278                   * key XORd with opad
00279                   */
00280   int i;
00281   
00282   /* if key is longer than 64 bytes reset it to key=MD5(key) */
00283   if (key_len > 64) {
00284     CSMd5 tmd5;
00285 
00286     sha1.sha1_reset();
00287     sha1.sha1_input(key, key_len);
00288     sha1.sha1_digest(digest);
00289 
00290     key = (char *) digest->val;
00291     key_len = 16;
00292   }
00293 
00294   /* start out by storing key in pads */
00295   memset(k_ipad, 0, sizeof(k_ipad));
00296   memset(k_opad, 0, sizeof(k_opad));
00297 
00298   memcpy(k_ipad, key, key_len);
00299   memcpy(k_opad, key, key_len);
00300 
00301   /* XOR key with ipad and opad values */
00302   for (i=0; i<64; i++) {
00303     k_ipad[i] ^= 0x36;
00304     k_opad[i] ^= 0x5c;
00305   }
00306 
00307   /*
00308    * perform inner encoding
00309    */
00310   sha1.sha1_reset();
00311   sha1.sha1_input(k_ipad, 64);
00312   sha1.sha1_input(text, strlen(text));
00313   sha1.sha1_digest(digest);
00314 
00315 
00316   /*
00317    * perform outer encoding
00318    */
00319   sha1.sha1_reset();
00320   sha1.sha1_input(k_opad, 64);
00321   sha1.sha1_input(digest, 20);
00322   sha1.sha1_digest(digest);
00323 }
00324 
00325 
00326 //-----------------------------------------------------
00327 CSString *signature(const char *text, const char *key)
00328 {
00329   Sha1Digest digest;
00330   char *encoding;
00331   CSString *signed_str;
00332   
00333   memset(&digest, 0, sizeof(digest));
00334   hmac_sha1(text, key, &digest);
00335 
00336   encoding = base64Encode(digest.val, SHA1_HASH_SIZE);
00337   signed_str = CSString::newString(encoding);
00338   cs_free(encoding);
00339   return signed_str;
00340 }
00341 
00342 
00343 //-----------------------------------------------------
00344 // Encode url unsafe characters
00345 CSString *urlEncode(CSString *src)
00346 {
00347   const char *hex = "0123456789ABCDEF", *start, *ptr;
00348   char encoded[3];
00349   CSStringBuffer *url;
00350   
00351   enter_();
00352   push_(src);
00353   
00354   new_(url, CSStringBuffer(10));
00355   push_(url);
00356   
00357   start = ptr = src->getCString();
00358   encoded[0] = '%';
00359   
00360   while(*ptr) {
00361     if (!isalnum(*ptr)) {
00362       switch (*ptr) {
00363         case '.':
00364         case '!':
00365         case '*':
00366         case '~':
00367         case '\'':
00368         case '(':
00369         case ')':
00370         case '_':
00371         case '-':
00372         case '/':
00373           break;
00374         default:
00375           url->append(start, ptr-start);
00376           start = ptr +1;
00377           encoded[1] = hex[*ptr/16];
00378           encoded[2] = hex[*ptr%16];        
00379           url->append(encoded, 3);
00380       }
00381     }
00382     ptr++;    
00383   }
00384   url->append(start, ptr-start);  
00385   
00386   CSString *safe_str = CSString::newString(url->getCString());
00387   
00388   release_(url);
00389   release_(src);
00390   return_(safe_str);
00391 }