]>
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;
137 for (bp
= out
+ 4; bp
> out
; bits
>>= 6)
138 *--bp
= nib2b64
[bits
& 0x3f];
164 * Essentially a duplicate of writeBase64, but without line wrapping or
165 * newline termination (note: string IS NUL terminated)
169 writeBase64raw (const unsigned char *in
, size_t length
, unsigned char *out
)
175 for (cc
= 0; length
> 0 && cc
< 3; ++cc
, --length
)
181 bits
= (in
[0] & 0xff) << 16;
183 bits
|= (in
[1] & 0xff) << 8;
185 bits
|= in
[2] & 0xff;
189 for (bp
= out
+ 4; bp
> out
; bits
>>= 6)
190 *--bp
= nib2b64
[bits
& 0x3f];
209 static const unsigned char b642nib
[0x80] = {
210 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
211 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
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, 0x3e, 0xff, 0xff, 0xff, 0x3f,
216 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
217 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
218 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
219 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
220 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
221 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
222 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
223 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
224 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
225 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
229 * Decode a base64 string. The result, decoded, must be freed by the caller.
230 * See description of arguments with declaration in h/prototypes.h.
233 decodeBase64 (const char *encoded
, unsigned char **decoded
, size_t *len
,
234 int skip_crs
, unsigned char *digest
) {
235 const char *cp
= encoded
;
236 int self_delimiting
= 0;
239 /* Size the decoded string very conservatively. */
240 charstring_t decoded_c
= charstring_create (strlen (encoded
));
244 MD5Init (&mdContext
);
255 if (isspace ((unsigned char) *cp
)) {
258 if (skip
|| (((unsigned char) *cp
) & 0x80) ||
259 (value
= b642nib
[((unsigned char) *cp
) & 0x7f]) > 0x3f) {
260 inform("invalid BASE64 encoding in %s", cp
);
261 charstring_free (decoded_c
);
267 bits
|= value
<< bitno
;
269 if ((bitno
-= 6) < 0) {
270 char b
= (char) ((bits
>> 16) & 0xff);
272 if (! skip_crs
|| b
!= '\r') {
273 charstring_push_back (decoded_c
, b
);
276 MD5Update (&mdContext
, (unsigned char *) &b
, 1);
278 b
= (bits
>> 8) & 0xff;
279 if (! skip_crs
|| b
!= '\r') {
280 charstring_push_back (decoded_c
, b
);
283 MD5Update (&mdContext
, (unsigned char *) &b
, 1);
286 if (! skip_crs
|| b
!= '\r') {
287 charstring_push_back (decoded_c
, b
);
290 MD5Update (&mdContext
, (unsigned char *) &b
, 1);
308 if (! self_delimiting
&& bitno
!= 18) {
311 /* Show some context for the error. */
312 for (i
= 0; i
< 20 && cp
> encoded
; ++i
, --cp
) {}
313 inform("premature ending (bitno %d) near %s", bitno
,
315 charstring_free (decoded_c
);
321 *decoded
= (unsigned char *) charstring_buffer_copy (decoded_c
);
322 *len
= charstring_bytes (decoded_c
);
323 charstring_free (decoded_c
);
326 MD5Final (digest
, &mdContext
);
334 * Prepare an unsigned char array for display by replacing non-printable
335 * ASCII bytes with their hex representation. Assumes ASCII input. output
336 * is allocated by the function and must be freed by the caller.
339 hexify (const unsigned char *input
, size_t len
, char **output
) {
340 /* Start with a charstring capacity that's arbitrarily larger than len. */
341 const charstring_t tmp
= charstring_create (2 * len
);
342 const unsigned char *cp
= input
;
345 for (i
= 0; i
< len
; ++i
, ++cp
) {
346 if (isascii(*cp
) && isprint(*cp
)) {
347 charstring_push_back (tmp
, (const char) *cp
);
350 const int num
= snprintf(s
, sizeof s
, "[0x%02x]", *cp
);
352 if (num
<= 0 || (unsigned int) num
>= sizeof s
) {
353 inform("hexify failed to write nonprintable character, needed %d bytes", num
+ 1);
355 charstring_append_cstring (tmp
, s
);
360 *output
= charstring_buffer_copy (tmp
);
361 charstring_free (tmp
);