1 |
|
|
/* |
2 |
|
|
+----------------------------------------------------------------------+ |
3 |
|
|
| PHP HTML Embedded Scripting Language Version 3.0 | |
4 |
|
|
+----------------------------------------------------------------------+ |
5 |
|
|
| Copyright (c) 1997-2000 PHP Development Team (See Credits file) | |
6 |
|
|
+----------------------------------------------------------------------+ |
7 |
|
|
| This program is free software; you can redistribute it and/or modify | |
8 |
|
|
| it under the terms of one of the following licenses: | |
9 |
|
|
| | |
10 |
|
|
| A) the GNU General Public License as published by the Free Software | |
11 |
|
|
| Foundation; either version 2 of the License, or (at your option) | |
12 |
|
|
| any later version. | |
13 |
|
|
| | |
14 |
|
|
| B) the PHP License as published by the PHP Development Team and | |
15 |
|
|
| included in the distribution in the file: LICENSE | |
16 |
|
|
| | |
17 |
|
|
| This program is distributed in the hope that it will be useful, | |
18 |
|
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 |
|
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 |
|
|
| GNU General Public License for more details. | |
21 |
|
|
| | |
22 |
|
|
| You should have received a copy of both licenses referred to here. | |
23 |
|
|
| If you did not, or have any questions about PHP licensing, please | |
24 |
|
|
| contact [email protected]. | |
25 |
|
|
+----------------------------------------------------------------------+ |
26 |
|
|
| Author: Jim Winstead ([email protected]) | |
27 |
|
|
+----------------------------------------------------------------------+ |
28 |
|
|
*/ |
29 |
|
|
|
30 |
|
|
#include "utils/base64.h" |
31 |
|
|
|
32 |
|
|
#include "utils/cast.h" |
33 |
|
|
|
34 |
|
|
#include "debug.h" |
35 |
|
|
|
36 |
|
|
static char base64_table[] = |
37 |
|
|
{ |
38 |
|
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', |
39 |
|
|
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', |
40 |
|
|
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', |
41 |
|
|
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', |
42 |
|
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0' |
43 |
|
|
}; |
44 |
|
|
static const char base64_pad = '='; |
45 |
|
|
|
46 |
|
|
unsigned char *php3_base64_encode(const unsigned char *restrict const string, |
47 |
|
|
int length, |
48 |
|
|
int *restrict const ret_length) |
49 |
|
|
{ |
50 |
|
|
if (string == nullptr) |
51 |
|
|
return nullptr; |
52 |
|
|
const unsigned char *current = string; |
53 |
|
|
int i = 0; |
54 |
|
|
unsigned char *const result = static_cast<unsigned char *>( |
55 |
|
|
calloc(CAST_SIZE((length + 3 - length % 3) * 4 / 3 + 1) |
56 |
|
|
* sizeof(unsigned char), 1)); |
57 |
|
|
if (result == nullptr) |
58 |
|
|
return nullptr; |
59 |
|
|
|
60 |
|
|
while (length > 2) |
61 |
|
|
{ /* keep going until we have less than 24 bits */ |
62 |
|
|
result[i++] = base64_table[current[0] >> 2]; |
63 |
|
|
result[i++] = base64_table[((current[0] & 0x03) |
64 |
|
|
<< 4) + (current[1] >> 4)]; |
65 |
|
|
result[i++] = base64_table[((current[1] & 0x0f) |
66 |
|
|
<< 2) + (current[2] >> 6)]; |
67 |
|
|
result[i++] = base64_table[current[2] & 0x3f]; |
68 |
|
|
|
69 |
|
|
current += 3; |
70 |
|
|
length -= 3; /* we just handle 3 octets of data */ |
71 |
|
|
} |
72 |
|
|
|
73 |
|
|
/* now deal with the tail end of things */ |
74 |
|
|
if (length != 0) |
75 |
|
|
{ |
76 |
|
|
result[i++] = base64_table[current[0] >> 2]; |
77 |
|
|
if (length > 1) |
78 |
|
|
{ |
79 |
|
|
result[i++] = base64_table[((current[0] & 0x03) << 4) |
80 |
|
|
+ (current[1] >> 4)]; |
81 |
|
|
result[i++] = base64_table[(current[1] & 0x0f) << 2]; |
82 |
|
|
result[i++] = base64_pad; |
83 |
|
|
} |
84 |
|
|
else |
85 |
|
|
{ |
86 |
|
|
result[i++] = base64_table[(current[0] & 0x03) << 4]; |
87 |
|
|
result[i++] = base64_pad; |
88 |
|
|
result[i++] = base64_pad; |
89 |
|
|
} |
90 |
|
|
} |
91 |
|
|
if (ret_length != nullptr) |
92 |
|
|
{ |
93 |
|
|
*ret_length = i; |
94 |
|
|
} |
95 |
|
|
result[i] = '\0'; |
96 |
|
|
return result; |
97 |
|
|
} |
98 |
|
|
|
99 |
|
|
/* as above, but backwards. :) */ |
100 |
|
2 |
unsigned char *php3_base64_decode(const unsigned char *restrict const string, |
101 |
|
|
const int length, |
102 |
|
|
int *restrict const ret_length) |
103 |
|
|
{ |
104 |
|
2 |
const unsigned char *current = string; |
105 |
|
|
int ch; |
106 |
|
2 |
int i = 0; |
107 |
|
2 |
int j = 0; |
108 |
|
|
int k; |
109 |
|
|
|
110 |
|
|
unsigned char *result = static_cast<unsigned char *>( |
111 |
|
2 |
calloc(length + 1, 1)); |
112 |
|
|
|
113 |
✓✗ |
2 |
if (result == nullptr) |
114 |
|
|
return nullptr; |
115 |
|
|
|
116 |
|
|
/* run through the whole string, converting as we go */ |
117 |
✗✓ |
2 |
while ((ch = *current++) != '\0') |
118 |
|
|
{ |
119 |
|
|
if (ch == base64_pad) |
120 |
|
|
break; |
121 |
|
|
|
122 |
|
|
/* When Base64 gets POSTed, all pluses are interpreted as spaces. |
123 |
|
|
This line changes them back. It's not exactly the Base64 spec, |
124 |
|
|
but it is completely compatible with it (the spec says that |
125 |
|
|
spaces are invalid). This will also save many people considerable |
126 |
|
|
headache. - Turadg Aleahmad <[email protected]> |
127 |
|
|
*/ |
128 |
|
|
|
129 |
|
|
if (ch == ' ') ch = '+'; |
130 |
|
|
|
131 |
|
|
const char *const chp = strchr(base64_table, ch); |
132 |
|
|
if (chp == nullptr) |
133 |
|
|
continue; |
134 |
|
|
ch = CAST_S32(chp - base64_table); |
135 |
|
|
|
136 |
|
|
switch (i % 4) |
137 |
|
|
{ |
138 |
|
|
case 0: |
139 |
|
|
result[j] = CAST_U8(ch << 2U); |
140 |
|
|
break; |
141 |
|
|
case 1: |
142 |
|
|
result[j++] |= CAST_U8(ch >> 4U); |
143 |
|
|
result[j] = CAST_U8((ch & 0x0f) << 4U); |
144 |
|
|
break; |
145 |
|
|
case 2: |
146 |
|
|
result[j++] |= CAST_U8(ch >>2U); |
147 |
|
|
result[j] = CAST_U8((ch & 0x03) << 6U); |
148 |
|
|
break; |
149 |
|
|
case 3: |
150 |
|
|
result[j++] |= CAST_U8(ch); |
151 |
|
|
break; |
152 |
|
|
default: |
153 |
|
|
break; |
154 |
|
|
} |
155 |
|
|
i++; |
156 |
|
|
} |
157 |
|
|
|
158 |
|
2 |
k = j; |
159 |
|
|
/* mop things up if we ended on a boundary */ |
160 |
✗✓ |
2 |
if (ch == base64_pad) |
161 |
|
|
{ |
162 |
|
|
switch (i % 4) |
163 |
|
|
{ |
164 |
|
|
case 0: |
165 |
|
|
case 1: |
166 |
|
|
free(result); |
167 |
|
|
return nullptr; |
168 |
|
|
case 2: |
169 |
|
|
k++; |
170 |
|
|
// copy from 3. is it should be here? |
171 |
|
|
result[k++] = 0; |
172 |
|
|
break; |
173 |
|
|
case 3: |
174 |
|
|
result[k++] = 0; |
175 |
|
|
break; |
176 |
|
|
default: |
177 |
|
|
break; |
178 |
|
|
} |
179 |
|
|
} |
180 |
✓✗ |
2 |
if (ret_length != nullptr) |
181 |
|
|
{ |
182 |
|
2 |
*ret_length = j; |
183 |
|
|
} |
184 |
|
2 |
result[k] = '\0'; |
185 |
|
2 |
return result; |
186 |
|
|
} |
187 |
|
|
|
188 |
|
|
std::string encodeBase64String(std::string value) |
189 |
|
|
{ |
190 |
|
|
int sz = 0; |
191 |
|
|
const unsigned char *const str = reinterpret_cast<unsigned char*>( |
192 |
|
|
const_cast<char*>(value.c_str())); |
193 |
|
|
unsigned char *const buf = php3_base64_encode( |
194 |
|
|
str, CAST_S32(value.size()), &sz); |
195 |
|
|
if (buf == nullptr) |
196 |
|
|
return std::string(); |
197 |
|
|
|
198 |
|
|
value = std::string(reinterpret_cast<char*>(buf), sz); |
199 |
|
|
free(buf); |
200 |
|
|
return value; |
201 |
|
|
} |
202 |
|
|
|
203 |
|
2 |
std::string decodeBase64String(std::string value) |
204 |
|
|
{ |
205 |
|
2 |
int sz = 0; |
206 |
|
|
const unsigned char *const str = reinterpret_cast<unsigned char*>( |
207 |
|
2 |
const_cast<char*>(value.c_str())); |
208 |
|
2 |
unsigned char *const buf = php3_base64_decode( |
209 |
|
4 |
str, CAST_S32(value.size()), &sz); |
210 |
|
|
|
211 |
✓✗ |
2 |
if (buf != nullptr) |
212 |
|
8 |
value = std::string(reinterpret_cast<char*>(buf), sz); |
213 |
|
|
else |
214 |
|
|
value.clear(); |
215 |
|
2 |
free(buf); |
216 |
|
2 |
return value; |
217 |
|
|
} |