/src/FreeRDP/libfreerdp/crypto/base64.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * FreeRDP: A Remote Desktop Protocol Implementation |
3 | | * Base64 Encoding & Decoding |
4 | | * |
5 | | * Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> |
6 | | * |
7 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | * you may not use this file except in compliance with the License. |
9 | | * You may obtain a copy of the License at |
10 | | * |
11 | | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | | * |
13 | | * Unless required by applicable law or agreed to in writing, software |
14 | | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | | * See the License for the specific language governing permissions and |
17 | | * limitations under the License. |
18 | | */ |
19 | | |
20 | | #include <freerdp/config.h> |
21 | | |
22 | | #include <winpr/crt.h> |
23 | | |
24 | | #include <freerdp/crypto/crypto.h> |
25 | | |
26 | | static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
27 | | static const char base64url[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; |
28 | | |
29 | | static char* base64_encode_ex(const char* alphabet, const BYTE* data, size_t length, BOOL pad, |
30 | | BOOL crLf, size_t lineSize) |
31 | 0 | { |
32 | 0 | int c = 0; |
33 | 0 | const BYTE* q = NULL; |
34 | 0 | char* p = NULL; |
35 | 0 | char* ret = NULL; |
36 | 0 | int blocks = 0; |
37 | 0 | size_t outLen = (length + 3) * 4 / 3; |
38 | 0 | size_t extra = 0; |
39 | 0 | if (crLf) |
40 | 0 | { |
41 | 0 | size_t nCrLf = (outLen + lineSize - 1) / lineSize; |
42 | 0 | extra = nCrLf * 2; |
43 | 0 | } |
44 | 0 | size_t outCounter = 0; |
45 | |
|
46 | 0 | q = data; |
47 | 0 | p = ret = (char*)malloc(outLen + extra + 1ull); |
48 | 0 | if (!p) |
49 | 0 | return NULL; |
50 | | |
51 | | /* b1, b2, b3 are input bytes |
52 | | * |
53 | | * 0 1 2 |
54 | | * 012345678901234567890123 |
55 | | * | b1 | b2 | b3 | |
56 | | * |
57 | | * [ c1 ] [ c3 ] |
58 | | * [ c2 ] [ c4 ] |
59 | | * |
60 | | * c1, c2, c3, c4 are output chars in base64 |
61 | | */ |
62 | | |
63 | | /* first treat complete blocks */ |
64 | 0 | blocks = length - (length % 3); |
65 | 0 | for (int i = 0; i < blocks; i += 3, q += 3) |
66 | 0 | { |
67 | 0 | c = (q[0] << 16) + (q[1] << 8) + q[2]; |
68 | |
|
69 | 0 | *p++ = alphabet[(c & 0x00FC0000) >> 18]; |
70 | 0 | *p++ = alphabet[(c & 0x0003F000) >> 12]; |
71 | 0 | *p++ = alphabet[(c & 0x00000FC0) >> 6]; |
72 | 0 | *p++ = alphabet[c & 0x0000003F]; |
73 | |
|
74 | 0 | outCounter += 4; |
75 | 0 | if (crLf && (outCounter % lineSize == 0)) |
76 | 0 | { |
77 | 0 | *p++ = '\r'; |
78 | 0 | *p++ = '\n'; |
79 | 0 | } |
80 | 0 | } |
81 | | |
82 | | /* then remainder */ |
83 | 0 | switch (length % 3) |
84 | 0 | { |
85 | 0 | case 0: |
86 | 0 | break; |
87 | 0 | case 1: |
88 | 0 | c = (q[0] << 16); |
89 | 0 | *p++ = alphabet[(c & 0x00FC0000) >> 18]; |
90 | 0 | *p++ = alphabet[(c & 0x0003F000) >> 12]; |
91 | 0 | if (pad) |
92 | 0 | { |
93 | 0 | *p++ = '='; |
94 | 0 | *p++ = '='; |
95 | 0 | } |
96 | 0 | break; |
97 | 0 | case 2: |
98 | 0 | c = (q[0] << 16) + (q[1] << 8); |
99 | 0 | *p++ = alphabet[(c & 0x00FC0000) >> 18]; |
100 | 0 | *p++ = alphabet[(c & 0x0003F000) >> 12]; |
101 | 0 | *p++ = alphabet[(c & 0x00000FC0) >> 6]; |
102 | 0 | if (pad) |
103 | 0 | *p++ = '='; |
104 | 0 | break; |
105 | 0 | } |
106 | | |
107 | 0 | if (crLf && length % 3) |
108 | 0 | { |
109 | 0 | *p++ = '\r'; |
110 | 0 | *p++ = '\n'; |
111 | 0 | } |
112 | 0 | *p = 0; |
113 | |
|
114 | 0 | return ret; |
115 | 0 | } |
116 | | |
117 | | static char* base64_encode(const char* alphabet, const BYTE* data, size_t length, BOOL pad) |
118 | 0 | { |
119 | 0 | return base64_encode_ex(alphabet, data, length, pad, FALSE, 64); |
120 | 0 | } |
121 | | |
122 | | static int base64_decode_char(const char* alphabet, char c) |
123 | 328 | { |
124 | 328 | char* p = NULL; |
125 | | |
126 | 328 | if (c == '\0') |
127 | 0 | return -1; |
128 | | |
129 | 328 | if ((p = strchr(alphabet, c))) |
130 | 155 | return p - alphabet; |
131 | | |
132 | 173 | return -1; |
133 | 328 | } |
134 | | |
135 | | static void* base64_decode(const char* alphabet, const char* s, size_t length, size_t* data_len, |
136 | | BOOL pad) |
137 | 152 | { |
138 | 152 | int n[4]; |
139 | 152 | BYTE* q = NULL; |
140 | 152 | BYTE* data = NULL; |
141 | 152 | size_t nBlocks = 0; |
142 | 152 | size_t outputLen = 0; |
143 | 152 | int remainder = length % 4; |
144 | | |
145 | 152 | if ((pad && remainder > 0) || (remainder == 1)) |
146 | 79 | return NULL; |
147 | | |
148 | 73 | if (!pad && remainder) |
149 | 0 | length += 4 - remainder; |
150 | | |
151 | 73 | q = data = (BYTE*)malloc(length / 4 * 3 + 1); |
152 | 73 | if (!q) |
153 | 0 | return NULL; |
154 | | |
155 | | /* first treat complete blocks */ |
156 | 73 | nBlocks = (length / 4); |
157 | 73 | outputLen = 0; |
158 | | |
159 | 73 | if (nBlocks < 1) |
160 | 0 | { |
161 | 0 | free(data); |
162 | 0 | return NULL; |
163 | 0 | } |
164 | | |
165 | 90 | for (size_t i = 0; i < nBlocks - 1; i++, q += 3) |
166 | 57 | { |
167 | 57 | n[0] = base64_decode_char(alphabet, *s++); |
168 | 57 | n[1] = base64_decode_char(alphabet, *s++); |
169 | 57 | n[2] = base64_decode_char(alphabet, *s++); |
170 | 57 | n[3] = base64_decode_char(alphabet, *s++); |
171 | | |
172 | 57 | if ((n[0] == -1) || (n[1] == -1) || (n[2] == -1) || (n[3] == -1)) |
173 | 40 | goto out_free; |
174 | | |
175 | 17 | q[0] = (n[0] << 2) + (n[1] >> 4); |
176 | 17 | q[1] = ((n[1] & 15) << 4) + (n[2] >> 2); |
177 | 17 | q[2] = ((n[2] & 3) << 6) + n[3]; |
178 | 17 | outputLen += 3; |
179 | 17 | } |
180 | | |
181 | | /* treat last block */ |
182 | 33 | n[0] = base64_decode_char(alphabet, *s++); |
183 | 33 | n[1] = base64_decode_char(alphabet, *s++); |
184 | 33 | if ((n[0] == -1) || (n[1] == -1)) |
185 | 16 | goto out_free; |
186 | | |
187 | 17 | n[2] = remainder == 2 ? -1 : base64_decode_char(alphabet, *s++); |
188 | 17 | n[3] = remainder >= 2 ? -1 : base64_decode_char(alphabet, *s++); |
189 | | |
190 | 17 | q[0] = (n[0] << 2) + (n[1] >> 4); |
191 | 17 | if (n[2] == -1) |
192 | 7 | { |
193 | | /* XX== */ |
194 | 7 | outputLen += 1; |
195 | 7 | if (n[3] != -1) |
196 | 3 | goto out_free; |
197 | | |
198 | 4 | q[1] = ((n[1] & 15) << 4); |
199 | 4 | } |
200 | 10 | else if (n[3] == -1) |
201 | 3 | { |
202 | | /* yyy= */ |
203 | 3 | outputLen += 2; |
204 | 3 | q[1] = ((n[1] & 15) << 4) + (n[2] >> 2); |
205 | 3 | q[2] = ((n[2] & 3) << 6); |
206 | 3 | } |
207 | 7 | else |
208 | 7 | { |
209 | | /* XXXX */ |
210 | 7 | outputLen += 3; |
211 | 7 | q[0] = (n[0] << 2) + (n[1] >> 4); |
212 | 7 | q[1] = ((n[1] & 15) << 4) + (n[2] >> 2); |
213 | 7 | q[2] = ((n[2] & 3) << 6) + n[3]; |
214 | 7 | } |
215 | | |
216 | 14 | if (data_len) |
217 | 14 | *data_len = outputLen; |
218 | 14 | data[outputLen] = '\0'; |
219 | | |
220 | 14 | return data; |
221 | 59 | out_free: |
222 | 59 | free(data); |
223 | 59 | return NULL; |
224 | 17 | } |
225 | | |
226 | | char* crypto_base64_encode_ex(const BYTE* data, size_t length, BOOL withCrLf) |
227 | 0 | { |
228 | 0 | return base64_encode_ex(base64, data, length, TRUE, withCrLf, 64); |
229 | 0 | } |
230 | | |
231 | | char* crypto_base64_encode(const BYTE* data, size_t length) |
232 | 0 | { |
233 | 0 | return base64_encode(base64, data, length, TRUE); |
234 | 0 | } |
235 | | |
236 | | void crypto_base64_decode(const char* enc_data, size_t length, BYTE** dec_data, size_t* res_length) |
237 | 152 | { |
238 | 152 | *dec_data = base64_decode(base64, enc_data, length, res_length, TRUE); |
239 | 152 | } |
240 | | |
241 | | char* crypto_base64url_encode(const BYTE* data, size_t length) |
242 | 0 | { |
243 | 0 | return base64_encode(base64url, data, length, FALSE); |
244 | 0 | } |
245 | | |
246 | | void crypto_base64url_decode(const char* enc_data, size_t length, BYTE** dec_data, |
247 | | size_t* res_length) |
248 | 0 | { |
249 | 0 | *dec_data = base64_decode(base64url, enc_data, length, res_length, FALSE); |
250 | 0 | } |