Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

beecrypt/base64.c

Go to the documentation of this file.
00001 
00007 /*
00008  * Copyright (c) 2000-2001 Virtual Unlimited B.V.
00009  *
00010  * Author: Bob Deblier <bob@virtualunlimited.com>
00011  *
00012  * This library is free software; you can redistribute it and/or
00013  * modify it under the terms of the GNU Lesser General Public
00014  * License as published by the Free Software Foundation; either
00015  * version 2.1 of the License, or (at your option) any later version.
00016  *
00017  * This library is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020  * Lesser General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU Lesser General Public
00023  * License along with this library; if not, write to the Free Software
00024  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00025  *
00026  */
00027 
00028 #include "system.h"
00029 #include "base64.h"
00030 #include "debug.h"
00031 
00032 /*@unchecked@*/
00033 static int _debug = 0;
00034 
00035 /*@unchecked@*/ /*@observer@*/
00036 static const char* to_b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00037 
00038 /* encode 64 characters per line */
00039 #define CHARS_PER_LINE  64
00040 
00041 /*@-boundswrite@*/
00042 char* b64enc(const memchunk* chunk)
00043 {
00044         int div = chunk->size / 3;
00045         int rem = chunk->size % 3;
00046         int chars = div*4 + rem + 1;
00047         int newlines = (chars + CHARS_PER_LINE - 1) / CHARS_PER_LINE;
00048 
00049         const byte* data = chunk->data;
00050         char* string = (char*) malloc(chars + newlines + 1);
00051 
00052         if (string)
00053         {
00054                 register char* buf = string;
00055 
00056                 chars = 0;
00057 
00058                 while (div > 0)
00059                 {
00060                         buf[0] = to_b64[ ((unsigned)data[0] >> 2) & 0x3f];
00061                         buf[1] = to_b64[(((unsigned)data[0] << 4) & 0x30) | (((unsigned)data[1] >> 4) & 0xf)];
00062                         buf[2] = to_b64[(((unsigned)data[1] << 2) & 0x3c) | (((unsigned)data[2] >> 6) & 0x3)];
00063                         buf[3] = to_b64[  (unsigned)data[2] & 0x3f];
00064                         data += 3;
00065                         buf += 4;
00066                         div--;
00067                         chars += 4;
00068                         if (chars == CHARS_PER_LINE)
00069                         {
00070                                 chars = 0;
00071                                 *(buf++) = '\n';
00072                         }
00073                 }
00074 
00075                 switch (rem)
00076                 {
00077                 case 2:
00078                         buf[0] = to_b64[ ((unsigned)data[0] >> 2) & 0x3f];
00079                         buf[1] = to_b64[(((unsigned)data[0] << 4) & 0x30) + (((unsigned)data[1] >> 4) & 0xf)];
00080                         buf[2] = to_b64[ ((unsigned)data[1] << 2) & 0x3c];
00081                         buf[3] = '=';
00082                         buf += 4;
00083                         chars += 4;
00084                         break;
00085                 case 1:
00086                         buf[0] = to_b64[ ((unsigned)data[0] >> 2) & 0x3f];
00087                         buf[1] = to_b64[ ((unsigned)data[0] << 4) & 0x30];
00088                         buf[2] = '=';
00089                         buf[3] = '=';
00090                         buf += 4;
00091                         chars += 4;
00092                         break;
00093                 }
00094 
00095         /*      *(buf++) = '\n'; This would result in a buffer overrun */
00096                 *buf = '\0';
00097         }
00098 
00099         /*@-dependenttrans@*/ /* FIX: buf = string makes string dependent */
00100         return string;
00101         /*@=dependenttrans@*/
00102 }
00103 /*@=boundswrite@*/
00104 
00105 /*@-boundswrite@*/
00106 memchunk* b64dec(const char* string)
00107 {
00108         /* return a decoded memchunk, or a null pointer in case of failure */
00109 
00110         memchunk* rc = 0;
00111 
00112         if (string)
00113         {
00114                 register int length = strlen(string);
00115 
00116                 /* do a format verification first */
00117                 if (length > 0)
00118                 {
00119                         register int count = 0, rem = 0;
00120                         register const char* tmp = string;
00121 
00122                         while (length > 0)
00123                         {
00124                                 register int skip = strspn(tmp, to_b64);
00125                                 count += skip;
00126                                 length -= skip;
00127                                 tmp += skip;
00128                                 if (length > 0)
00129                                 {
00130                                         register int i, vrfy = strcspn(tmp, to_b64);
00131 
00132                                         for (i = 0; i < vrfy; i++)
00133                                         {
00134                                                 if (isspace(tmp[i]))
00135                                                         /*@innercontinue@*/ continue;
00136 
00137                                                 if (tmp[i] == '=')
00138                                                 {
00139                                                         /* we should check if we're close to the end of the string */
00140                                                         rem = count % 4;
00141 
00142                                                         /* rem must be either 2 or 3, otherwise no '=' should be here */
00143                                                         if (rem < 2)
00144                                                                 return 0;
00145 
00146                                                         /* end-of-message recognized */
00147                                                         /*@innerbreak@*/ break;
00148                                                 }
00149                                                 else
00150                                                 {
00151                                                         /* Transmission error; RFC tells us to ignore this, but:
00152                                                          *  - the rest of the message is going to even more corrupt since we're sliding bits out of place
00153                                                          * If a message is corrupt, it should be dropped. Period.
00154                                                          */
00155 
00156                                                         return 0;
00157                                                 }
00158                                         }
00159 
00160                                         length -= vrfy;
00161                                         tmp += vrfy;
00162                                 }
00163                         }
00164 
00165                         rc = memchunkAlloc((count / 4) * 3 + (rem ? (rem - 1) : 0));
00166 
00167                         if (rc)
00168                         {
00169                                 if (count > 0)
00170                                 {
00171                                         register int i, qw = 0, tw = 0;
00172                                         register byte* data = rc->data;
00173 
00174                                         length = strlen(tmp = string);
00175 
00176                                         for (i = 0; i < length; i++)
00177                                         {
00178                                                 register char ch = string[i];
00179                                                 register byte bits;
00180 
00181                                                 if (isspace(ch))
00182                                                         continue;
00183 
00184                                                 bits = 0;
00185                                                 if ((ch >= 'A') && (ch <= 'Z'))
00186                                                 {
00187                                                         bits = (byte) (ch - 'A');
00188                                                 }
00189                                                 else if ((ch >= 'a') && (ch <= 'z'))
00190                                                 {
00191                                                         bits = (byte) (ch - 'a' + 26);
00192                                                 }
00193                                                 else if ((ch >= '0') && (ch <= '9'))
00194                                                 {
00195                                                         bits = (byte) (ch - '0' + 52);
00196                                                 }
00197                                                 else if (ch == '+')
00198                                                 {
00199                                                         bits = 62;
00200                                                 }
00201                                                 else if (ch == '/')
00202                                                 {
00203                                                         bits = 63;
00204                                                 }
00205                                                 else if (ch == '=')
00206                                                         break;
00207                                                 else
00208                                                         {};
00209 
00210                                                 switch (qw++)
00211                                                 {
00212                                                 case 0:
00213                                                         data[tw+0] = (bits << 2) & 0xfc;
00214                                                         /*@switchbreak@*/ break;
00215                                                 case 1:
00216                                                         data[tw+0] |= (bits >> 4) & 0x03;
00217                                                         data[tw+1] = (bits << 4) & 0xf0;
00218                                                         /*@switchbreak@*/ break;
00219                                                 case 2:
00220                                                         data[tw+1] |= (bits >> 2) & 0x0f;
00221                                                         data[tw+2] = (bits << 6) & 0xc0;
00222                                                         /*@switchbreak@*/ break;
00223                                                 case 3:
00224                                                         data[tw+2] |= bits & 0x3f;
00225                                                         /*@switchbreak@*/ break;
00226                                                 }
00227 
00228                                                 if (qw == 4)
00229                                                 {
00230                                                         qw = 0;
00231                                                         tw += 3;
00232                                                 }
00233                                         }
00234                                 }
00235                         }
00236                 }
00237         }
00238 
00239         return rc;
00240 }
00241 /*@=boundswrite@*/
00242 
00243 int b64encode_chars_per_line = B64ENCODE_CHARS_PER_LINE;
00244 
00245 const char * b64encode_eolstr = B64ENCODE_EOLSTR;
00246 
00247 /*@-boundswrite@*/
00248 /*@-internalglobs -modfilesys @*/
00249 char * b64encode (const void * data, int ns)
00250 {
00251     static char b64enc[] =
00252         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00253     const char *e;
00254     const unsigned char *s = data;
00255     unsigned char *t, *te;
00256     int nt;
00257     int lc;
00258     unsigned c;
00259 
00260     if (s == NULL)      return NULL;
00261     if (*s == '\0')     return calloc(1, sizeof(*t));
00262 
00263     if (ns == 0) ns = strlen(s);
00264     nt = ((ns + 2) / 3) * 4;
00265 
00266     /* Add additional bytes necessary for eol string(s). */
00267     if (b64encode_chars_per_line > 0 && b64encode_eolstr != NULL) {
00268         lc = (nt + b64encode_chars_per_line - 1) / b64encode_chars_per_line;
00269         if (((nt + b64encode_chars_per_line - 1) % b64encode_chars_per_line) != 0)
00270             ++lc;
00271         nt += lc * strlen(b64encode_eolstr);
00272     }
00273 
00274     t = te = malloc(nt + 1);
00275 
00276     lc = 0;
00277     if (te)
00278     while (ns) {
00279 
00280 if (_debug)
00281 fprintf(stderr, "%7u %02x %02x %02x -> %02x %02x %02x %02x\n",
00282 (unsigned)ns, (unsigned)s[0], (unsigned)s[1], (unsigned)s[2],
00283 (unsigned)(s[0] >> 2),
00284 (unsigned)((s[0] & 0x3) << 4) | (s[1] >> 4),
00285 (unsigned)((s[1] & 0xf) << 2) | (s[2] >> 6),
00286 (unsigned)(s[2]& 0x3f));
00287         c = *s++;
00288         *te++ = b64enc[ (c >> 2) ], lc++;
00289         *te++ = b64enc[ ((c & 0x3) << 4) | (*s >> 4) ], lc++;
00290         if (--ns == 0) {
00291             *te++ = '=';
00292             *te++ = '=';
00293             continue;
00294         }
00295         c = *s++;
00296         *te++ = b64enc[ ((c & 0xf) << 2) | (*s >> 6) ], lc++;
00297         if (--ns == 0) {
00298             *te++ = '=';
00299             continue;
00300         }
00301         *te++ = b64enc[ (int)(*s & 0x3f) ], lc++;
00302 
00303         /* Append eol string if desired. */
00304         if (b64encode_chars_per_line > 0 && b64encode_eolstr != NULL) {
00305             if (lc >= b64encode_chars_per_line) {
00306                 for (e = b64encode_eolstr; *e != '\0'; e++)
00307                     *te++ = *e;
00308                 lc = 0;
00309             }
00310         }
00311         s++;
00312         --ns;
00313     }
00314 
00315     if (te) {
00316         /* Append eol string if desired. */
00317         if (b64encode_chars_per_line > 0 && b64encode_eolstr != NULL) {
00318             if (lc != 0) {
00319                 for (e = b64encode_eolstr; *e != '\0'; e++)
00320                     *te++ = *e;
00321             }
00322         }
00323         *te = '\0';
00324     }
00325 
00326     /*@-mustfree -compdef @*/
00327     return t;
00328     /*@=mustfree =compdef @*/
00329 }
00330 /*@=globs =internalglobs =modfilesys @*/
00331 /*@=boundswrite@*/
00332 
00333 /*@-internalglobs -modfilesys @*/
00334 #define CRC24_INIT 0xb704ceL
00335 #define CRC24_POLY 0x1864cfbL
00336 
00337 /*@-boundsread@*/
00338 char * b64crc (const unsigned char * data, int ns)
00339 {
00340     const unsigned char *s = data;
00341     uint32 crc = CRC24_INIT;
00342 
00343     while (ns-- > 0) {
00344         int i;
00345         crc ^= (*s++) << 16;
00346         for (i = 0; i < 8; i++) {
00347             crc <<= 1;
00348             if (crc & 0x1000000)
00349                 crc ^= CRC24_POLY;
00350         }
00351     }
00352     crc &= 0xffffff;
00353     /*@-unrecog@*/ /* FIX: include endianness.h? */
00354     #if !WORDS_BIGENDIAN
00355     crc = swapu32(crc);
00356     #endif
00357     /*@=unrecog@*/
00358     data = (byte *)&crc;
00359     data++;
00360     ns = 3;
00361     return b64encode(data, ns);
00362 }
00363 /*@=boundsread@*/
00364 /*@=internalglobs =modfilesys @*/
00365 
00366 const char * b64decode_whitespace = B64DECODE_WHITESPACE;
00367 
00368 /*@-internalglobs -modfilesys @*/
00369 /*@-boundswrite@*/
00370 int b64decode (const char * s, void ** datap, int *lenp)
00371 {
00372     unsigned char b64dec[256];
00373     const unsigned char *t;
00374     unsigned char *te;
00375     int ns, nt;
00376     unsigned a, b, c, d;
00377 
00378     if (s == NULL)      return 1;
00379 
00380     /* Setup character lookup tables. */
00381     memset(b64dec, 0x80, sizeof(b64dec));
00382     for (c = 'A'; c <= 'Z'; c++)
00383         b64dec[ c ] = 0 + (c - 'A');
00384     for (c = 'a'; c <= 'z'; c++)
00385         b64dec[ c ] = 26 + (c - 'a');
00386     for (c = '0'; c <= '9'; c++)
00387         b64dec[ c ] = 52 + (c - '0');
00388     b64dec[(unsigned)'+'] = 62;
00389     b64dec[(unsigned)'/'] = 63;
00390     b64dec[(unsigned)'='] = 0;
00391 
00392     /* Mark whitespace characters. */
00393     if (b64decode_whitespace) {
00394         const char *e;
00395         for (e = b64decode_whitespace; *e != '\0'; e++) {
00396             if (b64dec[ (unsigned)*e ] == 0x80)
00397                 b64dec[ (unsigned)*e ] = 0x81;
00398         }
00399     }
00400     
00401     /* Validate input buffer */
00402     ns = 0;
00403     for (t = s; *t != '\0'; t++) {
00404         switch (b64dec[ (unsigned)*t ]) {
00405         case 0x80:      /* invalid chararcter */
00406 if (_debug)
00407 fprintf(stderr, "--- b64decode %c(%02x) %02x\n", *t, (unsigned)(*t & 0xff), (unsigned)b64dec[ (unsigned)*t ]);
00408             return 3;
00409             /*@notreached@*/ /*@switchbreak@*/ break;
00410         case 0x81:      /* white space */
00411             /*@switchbreak@*/ break;
00412         default:
00413             ns++;
00414             /*@switchbreak@*/ break;
00415         }
00416     }
00417     
00418     if (ns & 0x3)       return 2;
00419 
00420     nt = (ns / 4) * 3;
00421     t = te = malloc(nt + 1);
00422 
00423     while (ns > 0) {
00424 
00425         /* Get next 4 characters, ignoring whitespace. */
00426         while ((a = b64dec[ (unsigned)*s++ ]) == 0x81)
00427             {};
00428         while ((b = b64dec[ (unsigned)*s++ ]) == 0x81)
00429             {};
00430         while ((c = b64dec[ (unsigned)*s++ ]) == 0x81)
00431             {};
00432         while ((d = b64dec[ (unsigned)*s++ ]) == 0x81)
00433             {};
00434 
00435 if (_debug)
00436 fprintf(stderr, "%7u %02x %02x %02x %02x -> %02x %02x %02x\n",
00437 (unsigned)ns, a, b, c, d,
00438 (((a << 2) | (b >> 4)) & 0xff),
00439 (((b << 4) | (c >> 2)) & 0xff),
00440 (((c << 6) | d) & 0xff));
00441 
00442         ns -= 4;
00443         *te++ = (a << 2) | (b >> 4);
00444         if (s[-2] == '=') break;
00445         *te++ = (b << 4) | (c >> 2);
00446         if (s[-1] == '=') break;
00447         *te++ = (c << 6) | d;
00448     }
00449 
00450     if (ns != 0) {              /* XXX can't happen, just in case */
00451         if (t) free((void *)t);
00452         return 1;
00453     }
00454     if (lenp)
00455         *lenp = (te - t);
00456 
00457     if (datap)
00458         *datap = (void *)t;
00459     else
00460         if (t) free((void *)t);
00461     else
00462         {};
00463 
00464     return 0;
00465 }
00466 /*@=boundswrite@*/
00467 /*@=globs =internalglobs =modfilesys @*/

Generated on Tue Sep 17 15:59:43 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002