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