Updated init script.
[dtbartle/bnbt.git] / base64.cpp
1 /*---------------------------------------------------------------------------*/\r
2 /* base64                                                                    */\r
3 /* ======                                                                    */\r
4 /*                                                                           */\r
5 /* Base64 is a stand-alone C program to encode 7-Bit ASCII strings into      */\r
6 /* base64 encoded strings and decode base64 encoded strings back into 7 bit  */\r
7 /* ASCII strings.                                                            */\r
8 /*                                                                           */\r
9 /* Base64 encoding is sometimes used for simple HTTP authentication. That is */\r
10 /* when strong encryption isn't necessary, Base64 encryption is used to      */\r
11 /* authenticate User-ID's and Passwords.                                     */\r
12 /*                                                                           */\r
13 /* Base64 processes a string by octets (3 Byte blocks).  For every octet in  */\r
14 /* the decoded string, four byte blocks are generated in the encoded string. */\r
15 /* If the decoded string length is not a multiple of 3, the Base64 algorithm */\r
16 /* pads the end of the encoded string with equal signs '='.                  */\r
17 /*                                                                           */\r
18 /* An example taken from RFC 2617 (HTTP Authentication):                     */\r
19 /*                                                                           */\r
20 /* Resource (URL) requires basic authentication (Authorization: Basic) for   */\r
21 /* access, otherwise a HTTP 401 Unauthorized response is returned.           */\r
22 /*                                                                           */\r
23 /* User-ID:Password string  = "Aladdin:open sesame"                          */\r
24 /* Base64 encoded   string  = "QWxhZGRpbjpvcGVuIHNlc2FtZQ=="                 */\r
25 /*                                                                           */\r
26 /* Usage:   base64 OPTION [STRING]                                           */\r
27 /* ------                                                                    */\r
28 /* OPTION:  -h Displays a brief messages.                                    */\r
29 /*          -e Base64 encode the 7-Bit ASCII STRING.                         */\r
30 /*          -d Decode the Base64 STRING to 7-Bit ASCII.                      */\r
31 /*                                                                           */\r
32 /* STRING:  Either a 7-Bit ASCII text string for encoding or a Base64        */\r
33 /*          encoded string for decoding back to 7-Bit ASCII.                 */\r
34 /*                                                                           */\r
35 /* Note:    For EBCDIC and other collating sequences, the STRING must first  */\r
36 /*          be converted to 7-Bit ASCII before passing it to this module and */\r
37 /*          the return string must be converted back to the appropriate      */\r
38 /*          collating sequence.                                              */\r
39 /*                                                                           */\r
40 /* Student Exercises:                                                        */\r
41 /* ------------------                                                        */\r
42 /* 1. Modify base64 to accept an additional parameter "Quiet Mode" (-q) to   */\r
43 /*    optionally supress the ending statistics and only display the encoded  */\r
44 /*    or decoded string.                                                     */\r
45 /*                                                                           */\r
46 /* 2. Make base64 callable from another program as follows:                  */\r
47 /*    a. Add an externally callable function to determine and return the     */\r
48 /*       size of the buffer required for encoding or decoding.               */\r
49 /*    b. Make base64 accept three parameters; input and output buffer point- */\r
50 /*       ers and a flag for indicate encoding or decoding.                   */\r
51 /*    c. Modify base64 so that a calling program can:                        */\r
52 /*       i.   Request the size of a buffer required either for encoding or   */\r
53 /*            decoding.                                                      */\r
54 /*       ii.  Allocate a buffer based on the result from the previous        */\r
55 /*            call.                                                          */\r
56 /*       iii. Call base64 with the appropriate pointers and flag to encode   */\r
57 /*            or decode a string into the callers buffer.                    */\r
58 /*                                                                           */\r
59 /* Copyright (c) 1994 - 2001                                                 */\r
60 /* Marc Niegowski                                                            */\r
61 /* Connectivity, Inc.                                                        */\r
62 /* All rights reserved.                                                      */\r
63 /*---------------------------------------------------------------------------*/\r
64 #include    <stdlib.h>                      // calloc and free prototypes.\r
65 #include    <stdio.h>                       // printf prototype.\r
66 #include    <string.h>                      // str* and memset prototypes.\r
67 \r
68 #include "base64.h"\r
69 \r
70 typedef\r
71 unsigned\r
72 char    uchar;                              // Define unsigned char as uchar.\r
73 \r
74 typedef\r
75 unsigned\r
76 int     uint;                               // Define unsigned int as uint.\r
77 \r
78 char   *b64decode(const char *);            // Decodes a string to ASCII.\r
79 bool    b64valid(uchar *);                  // Tests for a valid Base64 char.\r
80 char   *b64isnot(char *);                   // Displays an invalid message.\r
81 char   *b64buffer(const char *, bool);      // Alloc. encoding/decoding buffer.\r
82 \r
83 // Macro definitions:\r
84 \r
85 #define b64is7bit(c)  ((c) > 0x7f ? 0 : 1)  // Valid 7-Bit ASCII character?\r
86 #define b64blocks(l) (((l) + 2) / 3 * 4 + 1)// Length rounded to 4 byte block.\r
87 #define b64octets(l)  ((l) / 4  * 3 + 1)    // Length rounded to 3 byte octet. \r
88 \r
89 // Note:    Tables are in hex to support different collating sequences\r
90 \r
91 static\r
92 const                                       // Base64 encoding and decoding\r
93 uchar   pBase64[]   =   {                   // table.\r
94                         0x3e, 0x7f, 0x7f, 0x7f, 0x3f, 0x34, 0x35, 0x36,\r
95                         0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x7f,\r
96                         0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x01,\r
97                         0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,\r
98                         0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,\r
99                         0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,\r
100                         0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x1a, 0x1b,\r
101                         0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,\r
102                         0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,\r
103                         0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33\r
104                         };\r
105 \r
106 /*---------------------------------------------------------------------------*/\r
107 /* b64decode - Decode a Base64 string to a 7-Bit ASCII string.               */\r
108 /* ===========================================================               */\r
109 /*                                                                           */\r
110 /* Call with:   char *  - The Base64 string to decode.                       */\r
111 /*                                                                           */\r
112 /* Returns:     bool    - True (!0) if the operation was successful.         */\r
113 /*                        False (0) if the operation was unsuccessful.       */\r
114 /*---------------------------------------------------------------------------*/\r
115 char *b64decode(const char *s)\r
116 {\r
117     int     l = strlen(s);                  // Get length of Base64 string.\r
118     char   *b;                              // Decoding buffer pointers.\r
119     uchar   c = 0;                          // Character to decode.\r
120     int     x = 0;                          // General purpose integers.\r
121     int     y = 0;\r
122 \r
123     static                                  // Collating sequence...\r
124     const                                   // ...independant "===".\r
125     char    pPad[]  =   {0x3d, 0x3d, 0x3d, 0x00};\r
126 \r
127     if  (l % 4)                             // If it's not modulo 4, then it...\r
128         return b64isnot(NULL);              // ...can't be a Base64 string.\r
129 \r
130     if  (b = strchr(s, pPad[0]))            // Only one, two or three equal...\r
131     {                                       // ...'=' signs are allowed at...\r
132         if  ((b - s) < (l - 3))             // ...the end of the Base64 string.\r
133             return b64isnot(NULL);          // Any other equal '=' signs are...\r
134         else                                // ...invalid.\r
135             if  (strncmp(b, (char *) pPad + 3 - (s + l - b), s + l - b))\r
136                 return b64isnot(NULL);\r
137     }\r
138 \r
139     if  (!(b = b64buffer(s, false)))        // Allocate a decoding buffer.\r
140         return NULL;                        // Can't allocate decoding buffer.\r
141 \r
142     x = 0;                                  // Initialize index.\r
143 \r
144     while ((c = *s++))                      // Decode every byte of the...\r
145     {                                       // Base64 string.\r
146         if  (c == pPad[0])                  // Ignore "=".\r
147             break;\r
148 \r
149         if (!b64valid(&c))                  // Valid Base64 Index?\r
150             return b64isnot(b);             // No, return false.\r
151         \r
152         switch(x % 4)                       // Decode 4 byte words into...\r
153         {                                   // ...3 byte octets.\r
154         case    0:                          // Byte 0 of word.\r
155             b[y]    =  c << 2;\r
156             break;                          \r
157         case    1:                          // Byte 1 of word.\r
158             b[y]   |=  c >> 4;\r
159 \r
160             if (!b64is7bit((uchar) b[y++])) // Is 1st byte of octet valid?\r
161                 return b64isnot(b);         // No, return false.\r
162 \r
163             b[y]    = (c & 0x0f) << 4;\r
164             break;\r
165         case    2:                          // Byte 2 of word.\r
166             b[y]   |=  c >> 2;\r
167 \r
168             if (!b64is7bit((uchar) b[y++])) // Is 2nd byte of octet valid?\r
169                 return b64isnot(b);         // No, return false.\r
170 \r
171             b[y]    = (c & 0x03) << 6;\r
172             break;\r
173         case    3:                          // Byte 3 of word.\r
174             b[y]   |=  c;\r
175 \r
176             if (!b64is7bit((uchar) b[y++])) // Is 3rd byte of octet valid?\r
177                 return b64isnot(b);         // No, return false.\r
178         }\r
179         x++;                                // Increment word byte.\r
180     }\r
181 \r
182         return b;\r
183 }\r
184 \r
185 /*---------------------------------------------------------------------------*/\r
186 /* b64valid - validate the character to decode.                              */\r
187 /* ============================================                              */\r
188 /*                                                                           */\r
189 /* Checks whether the character to decode falls within the boundaries of the */\r
190 /* Base64 decoding table.                                                    */\r
191 /*                                                                           */\r
192 /* Call with:   char    - The Base64 character to decode.                    */\r
193 /*                                                                           */\r
194 /* Returns:     bool    - True (!0) if the character is valid.               */\r
195 /*                        False (0) if the character is not valid.           */\r
196 /*---------------------------------------------------------------------------*/\r
197 bool b64valid(uchar *c)\r
198 {\r
199     if ((*c < 0x2b) || (*c > 0x7a))         // If not within the range of...\r
200         return false;                       // ...the table, return false.\r
201     \r
202     if ((*c = pBase64[*c - 0x2b]) == 0x7f)  // If it falls within one of...\r
203         return false;                       // ...the gaps, return false.\r
204 \r
205     return true;                            // Otherwise, return true.\r
206 }\r
207 \r
208 /*---------------------------------------------------------------------------*/\r
209 /* b64isnot - Display an error message and clean up.                         */\r
210 /* =================================================                         */\r
211 /*                                                                           */\r
212 /* Call this routine to display a message indicating that the string being   */\r
213 /* decoded is an invalid Base64 string and de-allocate the decoding buffer.  */\r
214 /*                                                                           */\r
215 /* Call with:   char *  - Pointer to the Base64 string being decoded.        */\r
216 /*              char *  - Pointer to the decoding buffer or NULL if it isn't */\r
217 /*                        allocated and doesn't need to be de-allocated.     */\r
218 /*                                                                           */\r
219 /* Returns:     bool    - True (!0) if the character is valid.               */\r
220 /*                        False (0) if the character is not valid.           */\r
221 /*---------------------------------------------------------------------------*/\r
222 char *b64isnot(char *b)\r
223 {\r
224     if  (b)                                 // If the buffer pointer is not...\r
225         free(b);                            // ...NULL, de-allocate it.\r
226 \r
227     return  NULL;\r
228 }\r
229 \r
230 /*---------------------------------------------------------------------------*/\r
231 /* b64buffer - Allocate the decoding or encoding buffer.                     */\r
232 /* =====================================================                     */\r
233 /*                                                                           */\r
234 /* Call this routine to allocate an encoding buffer in 4 byte blocks or a    */\r
235 /* decoding buffer in 3 byte octets.  We use "calloc" to initialize the      */\r
236 /* buffer to 0x00's for strings.                                             */\r
237 /*                                                                           */\r
238 /* Call with:   char *  - Pointer to the string to be encoded or decoded.    */\r
239 /*              bool    - True (!0) to allocate an encoding buffer.          */\r
240 /*                        False (0) to allocate a decoding buffer.           */\r
241 /*                                                                           */\r
242 /* Returns:     char *  - Pointer to the buffer or NULL if the buffer        */\r
243 /*                        could not be allocated.                            */\r
244 /*---------------------------------------------------------------------------*/\r
245 char *b64buffer(const char *s, bool f)\r
246 {\r
247     int     l = strlen(s);                  // String size to encode or decode.\r
248 \r
249     if  (!l)                                // If the string size is 0...\r
250         return  NULL;                       // ...return null.\r
251 \r
252     return (char *)calloc((f ? b64blocks(l) : b64octets(l)),sizeof(char));\r
253 }\r