1 /* Part of publib.
2 
3    Copyright (c) 1994-2006 Lars Wirzenius.  All rights reserved.
4 
5    Redistribution and use in source and binary forms, with or without
6    modification, are permitted provided that the following conditions
7    are met:
8 
9    1. Redistributions of source code must retain the above copyright
10       notice, this list of conditions and the following disclaimer.
11 
12    2. Redistributions in binary form must reproduce the above
13       copyright notice, this list of conditions and the following
14       disclaimer in the documentation and/or other materials provided
15       with the distribution.
16 
17    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18    OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20    ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23    GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 /*
30  * File:	base64.c
31  * Purpose:	Implementation of MIME's Base64 encoding and decoding.
32  * Author:	Lars Wirzenius
33  * Version:	$Id: base64.c,v 1.2 2003/11/15 18:24:10 liw Exp $
34  */
35 
36 #include <limits.h>
37 #include "publib/base64.h"
38 
39 static const unsigned char sixtet_to_base64[] =
40 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
41 
42 
43 /*
44  * Function:	base64_length
45  * Purpose:	Compute minimum length of encoded output.
46  */
base64_length(size_t n)47 size_t base64_length(size_t n) {
48 	return 4*(n+3)/3 + 1;
49 }
50 
51 
52 /*
53  * Function:	base64_encode
54  * Purpose:	Convert octets to base64
55  * Note:	Output buffer must be at least base64_length(n) chars.
56  */
base64_encode(char * to,const char * from,size_t n)57 size_t base64_encode(char *to, const char *from, size_t n) {
58     	unsigned w;
59 	char *to_start;
60 	unsigned char *fromp;
61 
62     	to_start = to;
63 
64     	fromp = (unsigned char *) from;
65     	for (; n >= 3; n -= 3, fromp += 3) {
66 	    w = (fromp[0] << 16) | (fromp[1] << 8) | fromp[2];
67 	    *to++ = sixtet_to_base64[(w >> 18) & 0x3f];
68 	    *to++ = sixtet_to_base64[(w >> 12) & 0x3f];
69 	    *to++ = sixtet_to_base64[(w >> 6) & 0x3f];
70 	    *to++ = sixtet_to_base64[w & 0x3f];
71 	}
72 
73     	switch (n) {
74 	case 0:
75 	    /* Nothing to do */
76 	    break;
77 
78 	case 1:
79 	    w = fromp[0];
80 	    *to++ = sixtet_to_base64[(w >> 2) & 0x3f];
81 	    *to++ = sixtet_to_base64[(w << 4) & 0x3f];
82 	    *to++ = '=';
83 	    *to++ = '=';
84 	    break;
85 
86 	case 2:
87 	    w = (fromp[0] << 8) | fromp[1];
88 	    *to++ = sixtet_to_base64[(w >> 10) & 0x3f];
89 	    *to++ = sixtet_to_base64[(w >> 4) & 0x3f];
90 	    *to++ = sixtet_to_base64[(w << 2) & 0x3f];
91 	    *to++ = '=';
92 	    break;
93 	}
94 
95 	return to - to_start;
96 }
97 
98 
99 /*
100  * Function:	base64_decode
101  * Purpose:	Convert base64 to octets.
102  * Note:	Output buffer must be at least 3*n/4 chars.
103  *		The output buffer does not get a '\0' appended.
104  */
base64_decode(char * to,const char * from,size_t len)105 size_t base64_decode(char *to, const char *from, size_t len) {
106     	static int base64_to_sixtet[UCHAR_MAX + 1];
107 	static int tab_init = 0;
108 	int i;
109 	unsigned bitbuf;
110 	int nbits;
111 	unsigned char *fromp;
112 	char *to_start;
113 
114     	if (!tab_init) {
115 	    tab_init = 1;
116 	    for (i = 0; i <= UCHAR_MAX + 1; ++i)
117 	    	base64_to_sixtet[i] = -1;
118 	    for (i = 0; sixtet_to_base64[i] != '\0'; ++i)
119 	    	base64_to_sixtet[sixtet_to_base64[i]] = i;
120 	}
121 
122     	to_start = to;
123 
124     	bitbuf = 0;
125 	nbits = 0;
126 	fromp = (unsigned char *) from;
127     	for (i = 0; i < len && fromp[i] != '='; ++i) {
128 	    if (base64_to_sixtet[fromp[i]] != -1) {
129 		bitbuf = (bitbuf << 6) | base64_to_sixtet[fromp[i]];
130 		nbits += 6;
131 		if (nbits >= 8) {
132 		    *to++ = (bitbuf >> (nbits - 8)) & 0xff;
133 		    bitbuf >>= 8;
134 		    nbits -= 8;
135 		}
136 	    }
137 	}
138 
139 	return to - to_start;
140 }
141