1*c3cd14fbSJerome Gaillard /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2*c3cd14fbSJerome Gaillard /* vi: set expandtab shiftwidth=4 tabstop=4: */
3*c3cd14fbSJerome Gaillard /**
4*c3cd14fbSJerome Gaillard * \file
5*c3cd14fbSJerome Gaillard * <PRE>
6*c3cd14fbSJerome Gaillard * MODP_B64 - High performance base64 encoder/decoder
7*c3cd14fbSJerome Gaillard * Version 1.3 -- 17-Mar-2006
8*c3cd14fbSJerome Gaillard * http://modp.com/release/base64
9*c3cd14fbSJerome Gaillard *
10*c3cd14fbSJerome Gaillard * Copyright © 2005, 2006 Nick Galbreath -- nickg [at] modp [dot] com
11*c3cd14fbSJerome Gaillard * All rights reserved.
12*c3cd14fbSJerome Gaillard *
13*c3cd14fbSJerome Gaillard * Redistribution and use in source and binary forms, with or without
14*c3cd14fbSJerome Gaillard * modification, are permitted provided that the following conditions are
15*c3cd14fbSJerome Gaillard * met:
16*c3cd14fbSJerome Gaillard *
17*c3cd14fbSJerome Gaillard * Redistributions of source code must retain the above copyright
18*c3cd14fbSJerome Gaillard * notice, this list of conditions and the following disclaimer.
19*c3cd14fbSJerome Gaillard *
20*c3cd14fbSJerome Gaillard * Redistributions in binary form must reproduce the above copyright
21*c3cd14fbSJerome Gaillard * notice, this list of conditions and the following disclaimer in the
22*c3cd14fbSJerome Gaillard * documentation and/or other materials provided with the distribution.
23*c3cd14fbSJerome Gaillard *
24*c3cd14fbSJerome Gaillard * Neither the name of the modp.com nor the names of its
25*c3cd14fbSJerome Gaillard * contributors may be used to endorse or promote products derived from
26*c3cd14fbSJerome Gaillard * this software without specific prior written permission.
27*c3cd14fbSJerome Gaillard *
28*c3cd14fbSJerome Gaillard * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29*c3cd14fbSJerome Gaillard * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30*c3cd14fbSJerome Gaillard * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31*c3cd14fbSJerome Gaillard * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32*c3cd14fbSJerome Gaillard * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33*c3cd14fbSJerome Gaillard * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34*c3cd14fbSJerome Gaillard * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35*c3cd14fbSJerome Gaillard * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36*c3cd14fbSJerome Gaillard * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37*c3cd14fbSJerome Gaillard * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38*c3cd14fbSJerome Gaillard * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39*c3cd14fbSJerome Gaillard *
40*c3cd14fbSJerome Gaillard * This is the standard "new" BSD license:
41*c3cd14fbSJerome Gaillard * http://www.opensource.org/licenses/bsd-license.php
42*c3cd14fbSJerome Gaillard * </PRE>
43*c3cd14fbSJerome Gaillard */
44*c3cd14fbSJerome Gaillard
45*c3cd14fbSJerome Gaillard /* public header */
46*c3cd14fbSJerome Gaillard #include "modp_b64.h"
47*c3cd14fbSJerome Gaillard
48*c3cd14fbSJerome Gaillard /*
49*c3cd14fbSJerome Gaillard * If you are ripping this out of the library, comment out the next
50*c3cd14fbSJerome Gaillard * line and uncomment the next lines as approrpiate
51*c3cd14fbSJerome Gaillard */
52*c3cd14fbSJerome Gaillard //#include "config.h"
53*c3cd14fbSJerome Gaillard
54*c3cd14fbSJerome Gaillard /* if on motoral, sun, ibm; uncomment this */
55*c3cd14fbSJerome Gaillard /* #define WORDS_BIGENDIAN 1 */
56*c3cd14fbSJerome Gaillard /* else for Intel, Amd; uncomment this */
57*c3cd14fbSJerome Gaillard /* #undef WORDS_BIGENDIAN */
58*c3cd14fbSJerome Gaillard
59*c3cd14fbSJerome Gaillard #include "modp_b64_data.h"
60*c3cd14fbSJerome Gaillard
61*c3cd14fbSJerome Gaillard #define BADCHAR 0x01FFFFFF
62*c3cd14fbSJerome Gaillard
63*c3cd14fbSJerome Gaillard /**
64*c3cd14fbSJerome Gaillard * you can control if we use padding by commenting out this
65*c3cd14fbSJerome Gaillard * next line. However, I highly recommend you use padding and not
66*c3cd14fbSJerome Gaillard * using it should only be for compatability with a 3rd party.
67*c3cd14fbSJerome Gaillard * Also, 'no padding' is not tested!
68*c3cd14fbSJerome Gaillard */
69*c3cd14fbSJerome Gaillard #define DOPAD 1
70*c3cd14fbSJerome Gaillard
71*c3cd14fbSJerome Gaillard /*
72*c3cd14fbSJerome Gaillard * if we aren't doing padding
73*c3cd14fbSJerome Gaillard * set the pad character to NULL
74*c3cd14fbSJerome Gaillard */
75*c3cd14fbSJerome Gaillard #ifndef DOPAD
76*c3cd14fbSJerome Gaillard #undef CHARPAD
77*c3cd14fbSJerome Gaillard #define CHARPAD '\0'
78*c3cd14fbSJerome Gaillard #endif
79*c3cd14fbSJerome Gaillard
modp_b64_encode(char * dest,const char * str,size_t len)80*c3cd14fbSJerome Gaillard size_t modp_b64_encode(char* dest, const char* str, size_t len)
81*c3cd14fbSJerome Gaillard {
82*c3cd14fbSJerome Gaillard size_t i = 0;
83*c3cd14fbSJerome Gaillard uint8_t* p = (uint8_t*) dest;
84*c3cd14fbSJerome Gaillard
85*c3cd14fbSJerome Gaillard /* unsigned here is important! */
86*c3cd14fbSJerome Gaillard uint8_t t1, t2, t3;
87*c3cd14fbSJerome Gaillard
88*c3cd14fbSJerome Gaillard if (len > 2) {
89*c3cd14fbSJerome Gaillard for (; i < len - 2; i += 3) {
90*c3cd14fbSJerome Gaillard t1 = str[i]; t2 = str[i+1]; t3 = str[i+2];
91*c3cd14fbSJerome Gaillard *p++ = e0[t1];
92*c3cd14fbSJerome Gaillard *p++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)];
93*c3cd14fbSJerome Gaillard *p++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)];
94*c3cd14fbSJerome Gaillard *p++ = e2[t3];
95*c3cd14fbSJerome Gaillard }
96*c3cd14fbSJerome Gaillard }
97*c3cd14fbSJerome Gaillard
98*c3cd14fbSJerome Gaillard switch (len - i) {
99*c3cd14fbSJerome Gaillard case 0:
100*c3cd14fbSJerome Gaillard break;
101*c3cd14fbSJerome Gaillard case 1:
102*c3cd14fbSJerome Gaillard t1 = str[i];
103*c3cd14fbSJerome Gaillard *p++ = e0[t1];
104*c3cd14fbSJerome Gaillard *p++ = e1[(t1 & 0x03) << 4];
105*c3cd14fbSJerome Gaillard *p++ = CHARPAD;
106*c3cd14fbSJerome Gaillard *p++ = CHARPAD;
107*c3cd14fbSJerome Gaillard break;
108*c3cd14fbSJerome Gaillard default: /* case 2 */
109*c3cd14fbSJerome Gaillard t1 = str[i]; t2 = str[i+1];
110*c3cd14fbSJerome Gaillard *p++ = e0[t1];
111*c3cd14fbSJerome Gaillard *p++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)];
112*c3cd14fbSJerome Gaillard *p++ = e2[(t2 & 0x0F) << 2];
113*c3cd14fbSJerome Gaillard *p++ = CHARPAD;
114*c3cd14fbSJerome Gaillard }
115*c3cd14fbSJerome Gaillard
116*c3cd14fbSJerome Gaillard *p = '\0';
117*c3cd14fbSJerome Gaillard return p - (uint8_t*)dest;
118*c3cd14fbSJerome Gaillard }
119*c3cd14fbSJerome Gaillard
120*c3cd14fbSJerome Gaillard #ifdef WORDS_BIGENDIAN /* BIG ENDIAN -- SUN / IBM / MOTOROLA */
modp_b64_decode(char * dest,const char * src,int len)121*c3cd14fbSJerome Gaillard int modp_b64_decode(char* dest, const char* src, int len)
122*c3cd14fbSJerome Gaillard {
123*c3cd14fbSJerome Gaillard if (len == 0) return 0;
124*c3cd14fbSJerome Gaillard
125*c3cd14fbSJerome Gaillard #ifdef DOPAD
126*c3cd14fbSJerome Gaillard /* if padding is used, then the message must be at least
127*c3cd14fbSJerome Gaillard 4 chars and be a multiple of 4.
128*c3cd14fbSJerome Gaillard there can be at most 2 pad chars at the end */
129*c3cd14fbSJerome Gaillard if (len < 4 || (len % 4 != 0)) return MODP_B64_ERROR;
130*c3cd14fbSJerome Gaillard if (src[len-1] == CHARPAD) {
131*c3cd14fbSJerome Gaillard len--;
132*c3cd14fbSJerome Gaillard if (src[len -1] == CHARPAD) {
133*c3cd14fbSJerome Gaillard len--;
134*c3cd14fbSJerome Gaillard }
135*c3cd14fbSJerome Gaillard }
136*c3cd14fbSJerome Gaillard #endif /* DOPAD */
137*c3cd14fbSJerome Gaillard
138*c3cd14fbSJerome Gaillard size_t i;
139*c3cd14fbSJerome Gaillard int leftover = len % 4;
140*c3cd14fbSJerome Gaillard size_t chunks = (leftover == 0) ? len / 4 - 1 : len /4;
141*c3cd14fbSJerome Gaillard
142*c3cd14fbSJerome Gaillard uint8_t* p = (uint8_t*) dest;
143*c3cd14fbSJerome Gaillard uint32_t x = 0;
144*c3cd14fbSJerome Gaillard uint32_t* destInt = (uint32_t*) p;
145*c3cd14fbSJerome Gaillard uint32_t* srcInt = (uint32_t*) src;
146*c3cd14fbSJerome Gaillard uint32_t y = *srcInt++;
147*c3cd14fbSJerome Gaillard for (i = 0; i < chunks; ++i) {
148*c3cd14fbSJerome Gaillard x = d0[y >> 24 & 0xff] | d1[y >> 16 & 0xff] |
149*c3cd14fbSJerome Gaillard d2[y >> 8 & 0xff] | d3[y & 0xff];
150*c3cd14fbSJerome Gaillard
151*c3cd14fbSJerome Gaillard if (x >= BADCHAR) return MODP_B64_ERROR;
152*c3cd14fbSJerome Gaillard *destInt = x << 8;
153*c3cd14fbSJerome Gaillard p += 3;
154*c3cd14fbSJerome Gaillard destInt = (uint32_t*)p;
155*c3cd14fbSJerome Gaillard y = *srcInt++;
156*c3cd14fbSJerome Gaillard }
157*c3cd14fbSJerome Gaillard
158*c3cd14fbSJerome Gaillard switch (leftover) {
159*c3cd14fbSJerome Gaillard case 0:
160*c3cd14fbSJerome Gaillard x = d0[y >> 24 & 0xff] | d1[y >> 16 & 0xff] |
161*c3cd14fbSJerome Gaillard d2[y >> 8 & 0xff] | d3[y & 0xff];
162*c3cd14fbSJerome Gaillard if (x >= BADCHAR) return MODP_B64_ERROR;
163*c3cd14fbSJerome Gaillard *p++ = ((uint8_t*)&x)[1];
164*c3cd14fbSJerome Gaillard *p++ = ((uint8_t*)&x)[2];
165*c3cd14fbSJerome Gaillard *p = ((uint8_t*)&x)[3];
166*c3cd14fbSJerome Gaillard return (chunks+1)*3;
167*c3cd14fbSJerome Gaillard case 1:
168*c3cd14fbSJerome Gaillard x = d3[y >> 24];
169*c3cd14fbSJerome Gaillard *p = (uint8_t)x;
170*c3cd14fbSJerome Gaillard break;
171*c3cd14fbSJerome Gaillard case 2:
172*c3cd14fbSJerome Gaillard x = d3[y >> 24] *64 + d3[(y >> 16) & 0xff];
173*c3cd14fbSJerome Gaillard *p = (uint8_t)(x >> 4);
174*c3cd14fbSJerome Gaillard break;
175*c3cd14fbSJerome Gaillard default: /* case 3 */
176*c3cd14fbSJerome Gaillard x = (d3[y >> 24] *64 + d3[(y >> 16) & 0xff])*64 +
177*c3cd14fbSJerome Gaillard d3[(y >> 8) & 0xff];
178*c3cd14fbSJerome Gaillard *p++ = (uint8_t) (x >> 10);
179*c3cd14fbSJerome Gaillard *p = (uint8_t) (x >> 2);
180*c3cd14fbSJerome Gaillard break;
181*c3cd14fbSJerome Gaillard }
182*c3cd14fbSJerome Gaillard
183*c3cd14fbSJerome Gaillard if (x >= BADCHAR) return MODP_B64_ERROR;
184*c3cd14fbSJerome Gaillard return 3*chunks + (6*leftover)/8;
185*c3cd14fbSJerome Gaillard }
186*c3cd14fbSJerome Gaillard
187*c3cd14fbSJerome Gaillard #else /* LITTLE ENDIAN -- INTEL AND FRIENDS */
188*c3cd14fbSJerome Gaillard
modp_b64_decode(char * dest,const char * src,size_t len)189*c3cd14fbSJerome Gaillard size_t modp_b64_decode(char* dest, const char* src, size_t len)
190*c3cd14fbSJerome Gaillard {
191*c3cd14fbSJerome Gaillard if (len == 0) return 0;
192*c3cd14fbSJerome Gaillard
193*c3cd14fbSJerome Gaillard #ifdef DOPAD
194*c3cd14fbSJerome Gaillard /*
195*c3cd14fbSJerome Gaillard * if padding is used, then the message must be at least
196*c3cd14fbSJerome Gaillard * 4 chars and be a multiple of 4
197*c3cd14fbSJerome Gaillard */
198*c3cd14fbSJerome Gaillard if (len < 4 || (len % 4 != 0)) return MODP_B64_ERROR; /* error */
199*c3cd14fbSJerome Gaillard /* there can be at most 2 pad chars at the end */
200*c3cd14fbSJerome Gaillard if (src[len-1] == CHARPAD) {
201*c3cd14fbSJerome Gaillard len--;
202*c3cd14fbSJerome Gaillard if (src[len -1] == CHARPAD) {
203*c3cd14fbSJerome Gaillard len--;
204*c3cd14fbSJerome Gaillard }
205*c3cd14fbSJerome Gaillard }
206*c3cd14fbSJerome Gaillard #endif
207*c3cd14fbSJerome Gaillard
208*c3cd14fbSJerome Gaillard size_t i;
209*c3cd14fbSJerome Gaillard int leftover = len % 4;
210*c3cd14fbSJerome Gaillard size_t chunks = (leftover == 0) ? len / 4 - 1 : len /4;
211*c3cd14fbSJerome Gaillard
212*c3cd14fbSJerome Gaillard uint8_t* p = (uint8_t*)dest;
213*c3cd14fbSJerome Gaillard uint32_t x = 0;
214*c3cd14fbSJerome Gaillard uint32_t* destInt = (uint32_t*) p;
215*c3cd14fbSJerome Gaillard uint32_t* srcInt = (uint32_t*) src;
216*c3cd14fbSJerome Gaillard uint32_t y = *srcInt++;
217*c3cd14fbSJerome Gaillard for (i = 0; i < chunks; ++i) {
218*c3cd14fbSJerome Gaillard x = d0[y & 0xff] |
219*c3cd14fbSJerome Gaillard d1[(y >> 8) & 0xff] |
220*c3cd14fbSJerome Gaillard d2[(y >> 16) & 0xff] |
221*c3cd14fbSJerome Gaillard d3[(y >> 24) & 0xff];
222*c3cd14fbSJerome Gaillard
223*c3cd14fbSJerome Gaillard if (x >= BADCHAR) return MODP_B64_ERROR;
224*c3cd14fbSJerome Gaillard *destInt = x ;
225*c3cd14fbSJerome Gaillard p += 3;
226*c3cd14fbSJerome Gaillard destInt = (uint32_t*)p;
227*c3cd14fbSJerome Gaillard y = *srcInt++;}
228*c3cd14fbSJerome Gaillard
229*c3cd14fbSJerome Gaillard
230*c3cd14fbSJerome Gaillard switch (leftover) {
231*c3cd14fbSJerome Gaillard case 0:
232*c3cd14fbSJerome Gaillard x = d0[y & 0xff] |
233*c3cd14fbSJerome Gaillard d1[(y >> 8) & 0xff] |
234*c3cd14fbSJerome Gaillard d2[(y >> 16) & 0xff] |
235*c3cd14fbSJerome Gaillard d3[(y >> 24) & 0xff];
236*c3cd14fbSJerome Gaillard
237*c3cd14fbSJerome Gaillard if (x >= BADCHAR) return MODP_B64_ERROR;
238*c3cd14fbSJerome Gaillard *p++ = ((uint8_t*)(&x))[0];
239*c3cd14fbSJerome Gaillard *p++ = ((uint8_t*)(&x))[1];
240*c3cd14fbSJerome Gaillard *p = ((uint8_t*)(&x))[2];
241*c3cd14fbSJerome Gaillard return (chunks+1)*3;
242*c3cd14fbSJerome Gaillard break;
243*c3cd14fbSJerome Gaillard case 1: /* with padding this is an impossible case */
244*c3cd14fbSJerome Gaillard x = d0[y & 0xff];
245*c3cd14fbSJerome Gaillard *p = *((uint8_t*)(&x)); // i.e. first char/byte in int
246*c3cd14fbSJerome Gaillard break;
247*c3cd14fbSJerome Gaillard case 2: // * case 2, 1 output byte */
248*c3cd14fbSJerome Gaillard x = d0[y & 0xff] | d1[y >> 8 & 0xff];
249*c3cd14fbSJerome Gaillard *p = *((uint8_t*)(&x)); // i.e. first char
250*c3cd14fbSJerome Gaillard break;
251*c3cd14fbSJerome Gaillard default: /* case 3, 2 output bytes */
252*c3cd14fbSJerome Gaillard x = d0[y & 0xff] |
253*c3cd14fbSJerome Gaillard d1[y >> 8 & 0xff ] |
254*c3cd14fbSJerome Gaillard d2[y >> 16 & 0xff]; /* 0x3c */
255*c3cd14fbSJerome Gaillard *p++ = ((uint8_t*)(&x))[0];
256*c3cd14fbSJerome Gaillard *p = ((uint8_t*)(&x))[1];
257*c3cd14fbSJerome Gaillard break;
258*c3cd14fbSJerome Gaillard }
259*c3cd14fbSJerome Gaillard
260*c3cd14fbSJerome Gaillard if (x >= BADCHAR) return MODP_B64_ERROR;
261*c3cd14fbSJerome Gaillard
262*c3cd14fbSJerome Gaillard return 3*chunks + (6*leftover)/8;
263*c3cd14fbSJerome Gaillard }
264*c3cd14fbSJerome Gaillard
265*c3cd14fbSJerome Gaillard #endif /* if bigendian / else / endif */
266