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