1 /******************************************************************************
2  *
3  * Project:  Common Portability Library
4  * Purpose:  Encoding/Decoding Base64 strings
5  * Author:   Paul Ramsey <pramsey@cleverelephant.ca>
6  *           Dave Blasby <dblasby@gmail.com>
7  *           René Nyffenegger
8  *
9  ******************************************************************************
10  * Copyright (c) 2008 Paul Ramsey
11  * Copyright (c) 2002 Refractions Research
12  * Copyright (C) 2004-2008 René Nyffenegger
13  * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
14  *
15  * (see also part way down the file for license terms for René's code)
16  *
17  * Permission is hereby granted, free of charge, to any person obtaining a
18  * copy of this software and associated documentation files (the "Software"),
19  * to deal in the Software without restriction, including without limitation
20  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
21  * and/or sell copies of the Software, and to permit persons to whom the
22  * Software is furnished to do so, subject to the following conditions:
23  *
24  * The above copyright notice and this permission notice shall be included in
25  * all copies of this Software or works derived from this Software.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33  * DEALINGS IN THE SOFTWARE.
34  ****************************************************************************/
35 
36 #include "cpl_port.h"
37 #include "cpl_string.h"
38 
39 #include <string>
40 
41 #include "cpl_conv.h"
42 
43 CPL_CVSID("$Id: cpl_base64.cpp b1c9c12ad373e40b955162b45d704070d4ebf7b0 2019-06-19 16:50:15 +0200 Even Rouault $")
44 
45 // Derived from MapServer's mappostgis.c.
46 
47 /*
48 ** Decode a base64 character.
49 */
50 constexpr unsigned char CPLBase64DecodeChar[256] = {
51     // Not Base64 characters.
52     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
53     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
54     64,64,64,64,64,64,64,64,64,64,64,
55     // +
56     62,
57     // Not Base64 characters.
58     64,64,64,
59     //  /
60     63,
61     // 0-9
62     52,53,54,55,56,57,58,59,60,61,
63     // Not Base64 characters.
64     64,64,64,64,64,64,64,
65     // A-Z
66     0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,
67     // Not Base64 characters.
68     64,64,64,64,64,64,
69     // a-z
70     26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,
71     51,
72     // Not Base64 characters.
73     64,64,64,64,64,
74     // Not Base64 characters (upper 128 characters).
75     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
76     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
77     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
78     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
79     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
80     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
81     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
82     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64
83     };
84 
85 /************************************************************************/
86 /*                       CPLBase64DecodeInPlace()                       */
87 /************************************************************************/
88 
89 /** Decode base64 string "pszBase64" (null terminated) in place.
90  *
91  * Returns length of decoded array or 0 on failure.
92  */
CPLBase64DecodeInPlace(GByte * pszBase64)93 int CPLBase64DecodeInPlace( GByte* pszBase64 )
94 {
95     if( pszBase64 && *pszBase64 )
96     {
97         unsigned char *p = pszBase64;
98         int offset_1 = 0;
99         int offset_2 = 0;
100 
101         // Drop illegal chars first.
102         for( ; pszBase64[offset_1]; ++offset_1 )
103         {
104             unsigned char c = pszBase64[offset_1];
105             if( (CPLBase64DecodeChar[c] != 64) || (c == '=') )
106             {
107                 pszBase64[offset_2++] = c;
108             }
109         }
110 
111         for( int idx = 0; idx < offset_2; idx += 4 )
112         {
113             unsigned char b1 = CPLBase64DecodeChar[pszBase64[idx]];
114             unsigned char b2 = 0;
115             unsigned char c3 = 'A';
116             unsigned char c4 = 'A';
117 
118             if( idx + 3 < offset_2 )
119             {
120                 b2 = CPLBase64DecodeChar[pszBase64[idx+1]];
121                 c3 = pszBase64[idx+2];
122                 c4 = pszBase64[idx+3];
123             }
124             else if( idx + 2 < offset_2 )
125             {
126                 b2 = CPLBase64DecodeChar[pszBase64[idx+1]];
127                 c3 = pszBase64[idx+2];
128             }
129             else if( idx + 1 < offset_2 )
130             {
131                 b2 = CPLBase64DecodeChar[pszBase64[idx+1]];
132                 // c3 = 'A';
133             }  // Else: Use the default values.
134 
135             const unsigned char b3 = CPLBase64DecodeChar[c3];
136             const unsigned char b4 = CPLBase64DecodeChar[c4];
137 
138             *p++ = ( (b1 << 2) | (b2 >> 4) );
139             if( p - pszBase64 == offset_1 )
140                 break;
141             if( c3 != '=' )
142             {
143                 *p++ = ( ((b2 & 0xf) << 4) | (b3 >> 2) );
144                 if( p - pszBase64 == offset_1 )
145                     break;
146             }
147             if( c4 != '=' )
148             {
149                 *p++ = ( ((b3 & 0x3) << 6) | b4);
150                 if( p - pszBase64 == offset_1 )
151                     break;
152             }
153         }
154         return static_cast<int>(p-pszBase64);
155     }
156     return 0;
157 }
158 
159 /*
160  * This function was extracted from the base64 cpp utility published by
161  * René Nyffenegger. The code was modified into a form suitable for use in
162  * CPL.  The original code can be found at:
163  *
164  * http://www.adp-gmbh.ch/cpp/common/base64.html.
165  *
166  * The following is the original notice of this function.
167  *
168  * base64.cpp and base64.h
169  *
170  *  Copyright (C) 2004-2008 René Nyffenegger
171  *
172  *  This source code is provided 'as-is', without any express or implied
173  *  warranty. In no event will the author be held liable for any damages
174  *  arising from the use of this software.
175  *
176  *  Permission is granted to anyone to use this software for any purpose,
177  *  including commercial applications, and to alter it and redistribute it
178  *  freely, subject to the following restrictions:
179  *
180  *  1. The origin of this source code must not be misrepresented; you must not
181  *     claim that you wrote the original source code. If you use this source
182  *     code in a product, an acknowledgment in the product documentation would
183  *     be appreciated but is not required.
184  *
185  *  2. Altered source versions must be plainly marked as such, and must not be
186  *     misrepresented as being the original source code.
187  *
188  *  3. This notice may not be removed or altered from any source distribution.
189  *
190  *  René Nyffenegger rene.nyffenegger@adp-gmbh.ch
191 */
192 
193 /************************************************************************/
194 /*                          CPLBase64Encode()                           */
195 /************************************************************************/
196 
197 /** Base64 encode a buffer. */
198 
CPLBase64Encode(int nDataLen,const GByte * pabyBytesToEncode)199 char *CPLBase64Encode(int nDataLen, const GByte *pabyBytesToEncode)
200 {
201     constexpr char base64Chars[] =
202         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
203 
204     const int kCharArray3Size = 3;
205     const int kCharArray4Size = 4;
206     unsigned char charArray3[kCharArray3Size] = {};
207 
208     std::string result("");
209     int array3_idx = 0;
210     while( nDataLen-- )
211     {
212         charArray3[array3_idx++] = *(pabyBytesToEncode++);
213 
214         if( array3_idx == kCharArray3Size )
215         {
216             const unsigned char charArray4[kCharArray4Size] = {
217                 static_cast<unsigned char>( (charArray3[0] & 0xfc) >> 2),
218                 static_cast<unsigned char>(((charArray3[0] & 0x03) << 4) +
219                                            ((charArray3[1] & 0xf0) >> 4)),
220                 static_cast<unsigned char>(((charArray3[1] & 0x0f) << 2) +
221                                            ((charArray3[2] & 0xc0) >> 6)),
222                 static_cast<unsigned char>(  charArray3[2] & 0x3f)
223             };
224 
225             for( int idx = 0; idx < kCharArray4Size; ++idx )
226             {
227                 result += base64Chars[charArray4[idx]];
228             }
229 
230             array3_idx = 0;
231         }
232     }
233 
234     if( array3_idx )
235     {
236         for( int idx = array3_idx; idx < kCharArray3Size; ++idx )
237         {
238             charArray3[idx] = '\0';
239         }
240 
241         const unsigned char charArray4[kCharArray4Size] = {
242             static_cast<unsigned char>( (charArray3[0] & 0xfc) >> 2),
243             static_cast<unsigned char>(((charArray3[0] & 0x03) << 4) +
244                                        ((charArray3[1] & 0xf0) >> 4)),
245             static_cast<unsigned char>(((charArray3[1] & 0x0f) << 2) +
246                                        ((charArray3[2] & 0xc0) >> 6)),
247             static_cast<unsigned char>(  charArray3[2] & 0x3f)
248         };
249 
250         for( int idx = 0; idx < (array3_idx + 1); ++idx )
251         {
252             result += base64Chars[charArray4[idx]];
253         }
254 
255         while( array3_idx++ < kCharArray3Size )
256             result += '=';
257     }
258 
259     return CPLStrdup(result.c_str());
260 }
261