xref: /aosp_15_r20/external/modp_b64/modp_b64.cc (revision c3cd14fb6370b1f0a2b85e79eb9b360b8782fd16)
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 &copy; 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