]>
diplodocus.org Git - nmh/blob - sbr/base64.c
1 /* base64.c -- routines for converting to base64
3 * This code is Copyright (c) 2012, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
13 static const char nib2b64
[0x40+1] =
14 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
17 * Copy data from one file to another, converting to base64-encoding.
21 * in - Input filehandle (unencoded data)
22 * out - Output filename (base64-encoded data)
23 * crlf - If set, output encoded CRLF for every LF on input.
25 * Returns OK on success, NOTOK otherwise.
28 writeBase64aux (FILE *in
, FILE *out
, int crlf
)
31 unsigned char inbuf
[3];
35 while ((cc
= fread (inbuf
, sizeof(*inbuf
), sizeof(inbuf
), in
)) > 0) {
40 if (cc
< sizeof(inbuf
)) {
42 if (cc
< sizeof(inbuf
) - 1)
47 * Convert a LF to a CRLF if desired. That means we need to push
48 * data back into the input stream.
54 for (i
= 0; i
< cc
; i
++) {
55 if (inbuf
[i
] == '\n' && !skipnl
) {
58 * If it's the last character in the buffer, we can just
59 * substitute a \r and push a \n back. Otherwise shuffle
60 * everything down and push the last character back.
64 * If we're at the end of the input, there might be
65 * more room in inbuf; if so, add it there. Otherwise
66 * push it back to the input.
68 if (cc
< sizeof(inbuf
))
74 /* This only works as long as sizeof(inbuf) == 3 */
75 ungetc(inbuf
[cc
- 1], in
);
76 if (cc
== 3 && i
== 0)
86 bits
= (inbuf
[0] & 0xff) << 16;
87 bits
|= (inbuf
[1] & 0xff) << 8;
88 bits
|= inbuf
[2] & 0xff;
90 for (bp
= outbuf
+ sizeof(outbuf
); bp
> outbuf
; bits
>>= 6)
91 *--bp
= nib2b64
[bits
& 0x3f];
92 if (cc
< sizeof(inbuf
)) {
94 if (cc
< sizeof inbuf
- 1)
98 if (fwrite (outbuf
, sizeof(*outbuf
), sizeof(outbuf
), out
) <
100 advise ("writeBase64aux", "fwrite");
103 if (cc
< sizeof(inbuf
)) {
120 /* Caller is responsible for ensuring that the out array is long
121 enough. Given length is that of in, out should be have at
123 4 * [length/3] + length/57 + 2
124 But double the length will certainly be sufficient. */
126 writeBase64 (const unsigned char *in
, size_t length
, unsigned char *out
)
128 unsigned int n
= BPERLIN
;
134 for (cc
= 0; length
> 0 && cc
< 3; ++cc
, --length
)
140 bits
= (in
[0] & 0xff) << 16;
142 bits
|= (in
[1] & 0xff) << 8;
144 bits
|= in
[2] & 0xff;
148 for (bp
= out
+ 4; bp
> out
; bits
>>= 6)
149 *--bp
= nib2b64
[bits
& 0x3f];
175 * Essentially a duplicate of writeBase64, but without line wrapping or
176 * newline termination (note: string IS NUL terminated)
180 writeBase64raw (const unsigned char *in
, size_t length
, unsigned char *out
)
186 for (cc
= 0; length
> 0 && cc
< 3; ++cc
, --length
)
192 bits
= (in
[0] & 0xff) << 16;
194 bits
|= (in
[1] & 0xff) << 8;
196 bits
|= in
[2] & 0xff;
200 for (bp
= out
+ 4; bp
> out
; bits
>>= 6)
201 *--bp
= nib2b64
[bits
& 0x3f];
220 static const unsigned char b642nib
[0x80] = {
221 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
222 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
223 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
224 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
225 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
226 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
227 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
228 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
229 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
230 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
231 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
232 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
233 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
234 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
235 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
236 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
240 * Decode a base64 string. The result, decoded, must be freed by the caller.
242 * encoded - the string to be decoded
243 * decoded - the decoded bytes
244 * len - number of decoded bytes
245 * skip-crs - non-zero for text content, and for which CR's should be
247 * digest - for an MD5 digest, it can be null
250 decodeBase64 (const char *encoded
, unsigned char **decoded
, size_t *len
,
251 int skip_crs
, unsigned char *digest
) {
252 const char *cp
= encoded
;
253 int self_delimiting
= 0;
256 /* Size the decoded string very conservatively. */
257 charstring_t decoded_c
= charstring_create (strlen (encoded
));
261 MD5Init (&mdContext
);
272 if (isspace ((unsigned char) *cp
)) {
275 if (skip
|| (((unsigned char) *cp
) & 0x80) ||
276 (value
= b642nib
[((unsigned char) *cp
) & 0x7f]) > 0x3f) {
277 inform("invalid base64 byte %#x: %.42s",
278 *(unsigned char *)cp
, cp
);
279 charstring_free (decoded_c
);
285 bits
|= value
<< bitno
;
287 if ((bitno
-= 6) < 0) {
288 char b
= (char) ((bits
>> 16) & 0xff);
290 if (! skip_crs
|| b
!= '\r') {
291 charstring_push_back (decoded_c
, b
);
294 MD5Update (&mdContext
, (unsigned char *) &b
, 1);
296 b
= (bits
>> 8) & 0xff;
297 if (! skip_crs
|| b
!= '\r') {
298 charstring_push_back (decoded_c
, b
);
301 MD5Update (&mdContext
, (unsigned char *) &b
, 1);
304 if (! skip_crs
|| b
!= '\r') {
305 charstring_push_back (decoded_c
, b
);
308 MD5Update (&mdContext
, (unsigned char *) &b
, 1);
326 if (! self_delimiting
&& bitno
!= 18) {
327 /* Show some context for the error. */
328 cp
-= min(cp
- encoded
, 20);
329 inform("premature ending (bitno %d) near %s", bitno
, cp
);
330 charstring_free (decoded_c
);
336 *decoded
= (unsigned char *) charstring_buffer_copy (decoded_c
);
337 *len
= charstring_bytes (decoded_c
);
338 charstring_free (decoded_c
);
341 MD5Final (digest
, &mdContext
);
349 * Prepare an unsigned char array for display by replacing non-printable
350 * ASCII bytes with their hex representation. Assumes ASCII input. output
351 * is allocated by the function and must be freed by the caller.
354 hexify (const unsigned char *input
, size_t len
, char **output
) {
355 /* Start with a charstring capacity that's arbitrarily larger than len. */
356 const charstring_t tmp
= charstring_create (2 * len
);
357 const unsigned char *cp
= input
;
360 for (i
= 0; i
< len
; ++i
, ++cp
) {
361 if (isascii(*cp
) && isprint(*cp
)) {
362 charstring_push_back (tmp
, (const char) *cp
);
365 const int num
= snprintf(s
, sizeof s
, "[0x%02x]", *cp
);
367 if (num
<= 0 || (unsigned int) num
>= sizeof s
) {
368 inform("hexify failed to write nonprintable character, needed %d bytes", num
+ 1);
370 charstring_append_cstring (tmp
, s
);
375 *output
= charstring_buffer_copy (tmp
);
376 charstring_free (tmp
);