]>
diplodocus.org Git - nmh/blob - sbr/base64.c
2 * base64.c -- routines for converting to base64
4 * This code is Copyright (c) 2012, by the authors of nmh. See the
5 * COPYRIGHT file in the root directory of the nmh distribution for
6 * complete copyright information.
14 static const char nib2b64
[0x40+1] =
15 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
18 writeBase64aux (FILE *in
, FILE *out
, int crlf
)
21 unsigned char inbuf
[3];
25 while ((cc
= fread (inbuf
, sizeof(*inbuf
), sizeof(inbuf
), in
)) > 0) {
30 if (cc
< sizeof(inbuf
)) {
32 if (cc
< sizeof(inbuf
) - 1)
37 * Convert a LF to a CRLF if desired. That means we need to push
38 * data back into the input stream.
44 for (i
= 0; i
< cc
; i
++) {
45 if (inbuf
[i
] == '\n' && !skipnl
) {
48 * If it's the last character in the buffer, we can just
49 * substitute a \r and push a \n back. Otherwise shuffle
50 * everything down and push the last character back.
54 * If we're at the end of the input, there might be
55 * more room in inbuf; if so, add it there. Otherwise
56 * push it back to the input.
58 if (cc
< sizeof(inbuf
))
64 /* This only works as long as sizeof(inbuf) == 3 */
65 ungetc(inbuf
[cc
- 1], in
);
66 if (cc
== 3 && i
== 0)
76 bits
= (inbuf
[0] & 0xff) << 16;
77 bits
|= (inbuf
[1] & 0xff) << 8;
78 bits
|= inbuf
[2] & 0xff;
80 for (bp
= outbuf
+ sizeof(outbuf
); bp
> outbuf
; bits
>>= 6)
81 *--bp
= nib2b64
[bits
& 0x3f];
82 if (cc
< sizeof(inbuf
)) {
84 if (cc
< sizeof inbuf
- 1)
88 if (fwrite (outbuf
, sizeof(*outbuf
), sizeof(outbuf
), out
) <
90 advise ("writeBase64aux", "fwrite");
93 if (cc
< sizeof(inbuf
)) {
110 /* Caller is responsible for ensuring that the out array is long
111 enough. Given length is that of in, out should be have at
113 4 * [length/3] + length/57 + 2
114 But double the length will certainly be sufficient. */
116 writeBase64 (const unsigned char *in
, size_t length
, unsigned char *out
)
118 unsigned int n
= BPERLIN
;
124 for (cc
= 0; length
> 0 && cc
< 3; ++cc
, --length
)
130 bits
= (in
[0] & 0xff) << 16;
132 bits
|= (in
[1] & 0xff) << 8;
134 bits
|= in
[2] & 0xff;
139 for (bp
= out
+ 4; bp
> out
; bits
>>= 6)
140 *--bp
= nib2b64
[bits
& 0x3f];
166 * Essentially a duplicate of writeBase64, but without line wrapping or
167 * newline termination (note: string IS NUL terminated)
171 writeBase64raw (const unsigned char *in
, size_t length
, unsigned char *out
)
177 for (cc
= 0; length
> 0 && cc
< 3; ++cc
, --length
)
183 bits
= (in
[0] & 0xff) << 16;
185 bits
|= (in
[1] & 0xff) << 8;
187 bits
|= in
[2] & 0xff;
192 for (bp
= out
+ 4; bp
> out
; bits
>>= 6)
193 *--bp
= nib2b64
[bits
& 0x3f];
212 static const unsigned char b642nib
[0x80] = {
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, 0xff, 0xff, 0xff, 0xff, 0xff,
218 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
219 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
220 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
221 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
222 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
223 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
224 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
225 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
226 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
227 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
228 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
232 * Decode a base64 string. The result, decoded, must be freed by the caller.
233 * See description of arguments with declaration in h/prototypes.h.
236 decodeBase64 (const char *encoded
, unsigned char **decoded
, size_t *len
,
237 int skip_crs
, unsigned char *digest
) {
238 const char *cp
= encoded
;
239 int self_delimiting
= 0;
242 /* Size the decoded string very conservatively. */
243 charstring_t decoded_c
= charstring_create (strlen (encoded
));
247 MD5Init (&mdContext
);
258 if (isspace ((unsigned char) *cp
)) {
261 if (skip
|| (((unsigned char) *cp
) & 0x80) ||
262 (value
= b642nib
[((unsigned char) *cp
) & 0x7f]) > 0x3f) {
263 advise (NULL
, "invalid BASE64 encoding in %s", cp
);
264 charstring_free (decoded_c
);
270 bits
|= value
<< bitno
;
272 if ((bitno
-= 6) < 0) {
273 char b
= (char) ((bits
>> 16) & 0xff);
275 if (! skip_crs
|| b
!= '\r') {
276 charstring_push_back (decoded_c
, b
);
279 MD5Update (&mdContext
, (unsigned char *) &b
, 1);
281 b
= (bits
>> 8) & 0xff;
282 if (! skip_crs
|| b
!= '\r') {
283 charstring_push_back (decoded_c
, b
);
286 MD5Update (&mdContext
, (unsigned char *) &b
, 1);
289 if (! skip_crs
|| b
!= '\r') {
290 charstring_push_back (decoded_c
, b
);
293 MD5Update (&mdContext
, (unsigned char *) &b
, 1);
313 if (! self_delimiting
&& bitno
!= 18) {
316 /* Show some context for the error. */
317 for (i
= 0; i
< 20 && cp
> encoded
; ++i
, --cp
) {}
318 advise (NULL
, "premature ending (bitno %d) near %s", bitno
,
320 charstring_free (decoded_c
);
326 *decoded
= (unsigned char *) charstring_buffer_copy (decoded_c
);
327 *len
= charstring_bytes (decoded_c
);
328 charstring_free (decoded_c
);
331 MD5Final (digest
, &mdContext
);
339 * Prepare an unsigned char array for display by replacing non-printable
340 * ASCII bytes with their hex representation. Assumes ASCII input. output
341 * is allocated by the function and must be freed by the caller.
344 hexify (const unsigned char *input
, size_t len
, char **output
) {
345 /* Start with a charstring capacity that's arbitrarily larger than len. */
346 const charstring_t tmp
= charstring_create (2 * len
);
347 const unsigned char *cp
= input
;
350 for (i
= 0; i
< len
; ++i
, ++cp
) {
351 if (isascii(*cp
) && isprint(*cp
)) {
352 charstring_push_back (tmp
, (const char) *cp
);
355 const int num
= snprintf(s
, sizeof s
, "[0x%02x]", *cp
);
357 if (num
<= 0 || (unsigned int) num
>= sizeof s
) {
358 advise (NULL
, "hexify failed to write nonprintable character, needed %d bytes", num
+ 1);
360 charstring_append_cstring (tmp
, s
);
365 *output
= charstring_buffer_copy (tmp
);
366 charstring_free (tmp
);