]>
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 writeBase64aux (FILE *in
, FILE *out
, int crlf
)
20 unsigned char inbuf
[3];
24 while ((cc
= fread (inbuf
, sizeof(*inbuf
), sizeof(inbuf
), in
)) > 0) {
29 if (cc
< sizeof(inbuf
)) {
31 if (cc
< sizeof(inbuf
) - 1)
36 * Convert a LF to a CRLF if desired. That means we need to push
37 * data back into the input stream.
43 for (i
= 0; i
< cc
; i
++) {
44 if (inbuf
[i
] == '\n' && !skipnl
) {
47 * If it's the last character in the buffer, we can just
48 * substitute a \r and push a \n back. Otherwise shuffle
49 * everything down and push the last character back.
53 * If we're at the end of the input, there might be
54 * more room in inbuf; if so, add it there. Otherwise
55 * push it back to the input.
57 if (cc
< sizeof(inbuf
))
63 /* This only works as long as sizeof(inbuf) == 3 */
64 ungetc(inbuf
[cc
- 1], in
);
65 if (cc
== 3 && i
== 0)
75 bits
= (inbuf
[0] & 0xff) << 16;
76 bits
|= (inbuf
[1] & 0xff) << 8;
77 bits
|= inbuf
[2] & 0xff;
79 for (bp
= outbuf
+ sizeof(outbuf
); bp
> outbuf
; bits
>>= 6)
80 *--bp
= nib2b64
[bits
& 0x3f];
81 if (cc
< sizeof(inbuf
)) {
83 if (cc
< sizeof inbuf
- 1)
87 if (fwrite (outbuf
, sizeof(*outbuf
), sizeof(outbuf
), out
) <
89 advise ("writeBase64aux", "fwrite");
92 if (cc
< sizeof(inbuf
)) {
109 /* Caller is responsible for ensuring that the out array is long
110 enough. Given length is that of in, out should be have at
112 4 * [length/3] + length/57 + 2
113 But double the length will certainly be sufficient. */
115 writeBase64 (const unsigned char *in
, size_t length
, unsigned char *out
)
117 unsigned int n
= BPERLIN
;
123 for (cc
= 0; length
> 0 && cc
< 3; ++cc
, --length
)
129 bits
= (in
[0] & 0xff) << 16;
131 bits
|= (in
[1] & 0xff) << 8;
133 bits
|= in
[2] & 0xff;
138 for (bp
= out
+ 4; bp
> out
; bits
>>= 6)
139 *--bp
= nib2b64
[bits
& 0x3f];
165 * Essentially a duplicate of writeBase64, but without line wrapping or
166 * newline termination (note: string IS NUL terminated)
170 writeBase64raw (const unsigned char *in
, size_t length
, unsigned char *out
)
176 for (cc
= 0; length
> 0 && cc
< 3; ++cc
, --length
)
182 bits
= (in
[0] & 0xff) << 16;
184 bits
|= (in
[1] & 0xff) << 8;
186 bits
|= in
[2] & 0xff;
191 for (bp
= out
+ 4; bp
> out
; bits
>>= 6)
192 *--bp
= nib2b64
[bits
& 0x3f];
211 static const unsigned char b642nib
[0x80] = {
212 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
213 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
214 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
215 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
216 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
217 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
218 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
219 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
220 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
221 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
222 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
223 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
224 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
225 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
226 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
227 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
231 * Decode a base64 string. The result, decoded, must be freed by the caller.
232 * See description of arguments with declaration in h/prototypes.h.
235 decodeBase64 (const char *encoded
, unsigned char **decoded
, size_t *len
,
236 int skip_crs
, unsigned char *digest
) {
237 const char *cp
= encoded
;
238 int self_delimiting
= 0;
241 /* Size the decoded string very conservatively. */
242 charstring_t decoded_c
= charstring_create (strlen (encoded
));
246 MD5Init (&mdContext
);
257 if (isspace ((unsigned char) *cp
)) {
260 if (skip
|| (((unsigned char) *cp
) & 0x80) ||
261 (value
= b642nib
[((unsigned char) *cp
) & 0x7f]) > 0x3f) {
262 inform("invalid BASE64 encoding in %s", cp
);
263 charstring_free (decoded_c
);
269 bits
|= value
<< bitno
;
271 if ((bitno
-= 6) < 0) {
272 char b
= (char) ((bits
>> 16) & 0xff);
274 if (! skip_crs
|| b
!= '\r') {
275 charstring_push_back (decoded_c
, b
);
278 MD5Update (&mdContext
, (unsigned char *) &b
, 1);
280 b
= (bits
>> 8) & 0xff;
281 if (! skip_crs
|| b
!= '\r') {
282 charstring_push_back (decoded_c
, b
);
285 MD5Update (&mdContext
, (unsigned char *) &b
, 1);
288 if (! skip_crs
|| b
!= '\r') {
289 charstring_push_back (decoded_c
, b
);
292 MD5Update (&mdContext
, (unsigned char *) &b
, 1);
312 if (! self_delimiting
&& bitno
!= 18) {
315 /* Show some context for the error. */
316 for (i
= 0; i
< 20 && cp
> encoded
; ++i
, --cp
) {}
317 inform("premature ending (bitno %d) near %s", bitno
,
319 charstring_free (decoded_c
);
325 *decoded
= (unsigned char *) charstring_buffer_copy (decoded_c
);
326 *len
= charstring_bytes (decoded_c
);
327 charstring_free (decoded_c
);
330 MD5Final (digest
, &mdContext
);
338 * Prepare an unsigned char array for display by replacing non-printable
339 * ASCII bytes with their hex representation. Assumes ASCII input. output
340 * is allocated by the function and must be freed by the caller.
343 hexify (const unsigned char *input
, size_t len
, char **output
) {
344 /* Start with a charstring capacity that's arbitrarily larger than len. */
345 const charstring_t tmp
= charstring_create (2 * len
);
346 const unsigned char *cp
= input
;
349 for (i
= 0; i
< len
; ++i
, ++cp
) {
350 if (isascii(*cp
) && isprint(*cp
)) {
351 charstring_push_back (tmp
, (const char) *cp
);
354 const int num
= snprintf(s
, sizeof s
, "[0x%02x]", *cp
);
356 if (num
<= 0 || (unsigned int) num
>= sizeof s
) {
357 inform("hexify failed to write nonprintable character, needed %d bytes", num
+ 1);
359 charstring_append_cstring (tmp
, s
);
364 *output
= charstring_buffer_copy (tmp
);
365 charstring_free (tmp
);