/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; |
33 | 0 | const BYTE* q; |
34 | 0 | char* p; |
35 | 0 | char* ret; |
36 | 0 | int i = 0; |
37 | 0 | int blocks; |
38 | 0 | size_t outLen = (length + 3) * 4 / 3; |
39 | 0 | size_t extra = 0; |
40 | 0 | if (crLf) |
41 | 0 | { |
42 | 0 | size_t nCrLf = (outLen + lineSize - 1) / lineSize; |
43 | 0 | extra = nCrLf * 2; |
44 | 0 | } |
45 | 0 | size_t outCounter = 0; |
46 | |
|
47 | 0 | q = data; |
48 | 0 | p = ret = (char*)malloc(outLen + extra + 1ull); |
49 | 0 | if (!p) |
50 | 0 | return NULL; |
51 | | |
52 | | /* b1, b2, b3 are input bytes |
53 | | * |
54 | | * 0 1 2 |
55 | | * 012345678901234567890123 |
56 | | * | b1 | b2 | b3 | |
57 | | * |
58 | | * [ c1 ] [ c3 ] |
59 | | * [ c2 ] [ c4 ] |
60 | | * |
61 | | * c1, c2, c3, c4 are output chars in base64 |
62 | | */ |
63 | | |
64 | | /* first treat complete blocks */ |
65 | 0 | blocks = length - (length % 3); |
66 | 0 | for (i = 0; i < blocks; i += 3, q += 3) |
67 | 0 | { |
68 | 0 | c = (q[0] << 16) + (q[1] << 8) + q[2]; |
69 | |
|
70 | 0 | *p++ = alphabet[(c & 0x00FC0000) >> 18]; |
71 | 0 | *p++ = alphabet[(c & 0x0003F000) >> 12]; |
72 | 0 | *p++ = alphabet[(c & 0x00000FC0) >> 6]; |
73 | 0 | *p++ = alphabet[c & 0x0000003F]; |
74 | |
|
75 | 0 | outCounter += 4; |
76 | 0 | if (crLf && (outCounter % lineSize == 0)) |
77 | 0 | { |
78 | 0 | *p++ = '\r'; |
79 | 0 | *p++ = '\n'; |
80 | 0 | } |
81 | 0 | } |
82 | | |
83 | | /* then remainder */ |
84 | 0 | switch (length % 3) |
85 | 0 | { |
86 | 0 | case 0: |
87 | 0 | break; |
88 | 0 | case 1: |
89 | 0 | c = (q[0] << 16); |
90 | 0 | *p++ = alphabet[(c & 0x00FC0000) >> 18]; |
91 | 0 | *p++ = alphabet[(c & 0x0003F000) >> 12]; |
92 | 0 | if (pad) |
93 | 0 | { |
94 | 0 | *p++ = '='; |
95 | 0 | *p++ = '='; |
96 | 0 | } |
97 | 0 | break; |
98 | 0 | case 2: |
99 | 0 | c = (q[0] << 16) + (q[1] << 8); |
100 | 0 | *p++ = alphabet[(c & 0x00FC0000) >> 18]; |
101 | 0 | *p++ = alphabet[(c & 0x0003F000) >> 12]; |
102 | 0 | *p++ = alphabet[(c & 0x00000FC0) >> 6]; |
103 | 0 | if (pad) |
104 | 0 | *p++ = '='; |
105 | 0 | break; |
106 | 0 | } |
107 | | |
108 | 0 | if (crLf && length % 3) |
109 | 0 | { |
110 | 0 | *p++ = '\r'; |
111 | 0 | *p++ = '\n'; |
112 | 0 | } |
113 | 0 | *p = 0; |
114 | |
|
115 | 0 | return ret; |
116 | 0 | } |
117 | | |
118 | | static char* base64_encode(const char* alphabet, const BYTE* data, size_t length, BOOL pad) |
119 | 0 | { |
120 | 0 | return base64_encode_ex(alphabet, data, length, pad, FALSE, 64); |
121 | 0 | } |
122 | | |
123 | | static int base64_decode_char(const char* alphabet, char c) |
124 | 0 | { |
125 | 0 | char* p = NULL; |
126 | |
|
127 | 0 | if (c == '\0') |
128 | 0 | return -1; |
129 | | |
130 | 0 | if ((p = strchr(alphabet, c))) |
131 | 0 | return p - alphabet; |
132 | | |
133 | 0 | return -1; |
134 | 0 | } |
135 | | |
136 | | static void* base64_decode(const char* alphabet, const char* s, size_t length, size_t* data_len, |
137 | | BOOL pad) |
138 | 0 | { |
139 | 0 | int n[4]; |
140 | 0 | BYTE* q; |
141 | 0 | BYTE* data; |
142 | 0 | size_t nBlocks, i, outputLen; |
143 | 0 | int remainder = length % 4; |
144 | |
|
145 | 0 | if ((pad && remainder > 0) || (remainder == 1)) |
146 | 0 | return NULL; |
147 | | |
148 | 0 | if (!pad && remainder) |
149 | 0 | length += 4 - remainder; |
150 | |
|
151 | 0 | q = data = (BYTE*)malloc(length / 4 * 3 + 1); |
152 | 0 | if (!q) |
153 | 0 | return NULL; |
154 | | |
155 | | /* first treat complete blocks */ |
156 | 0 | nBlocks = (length / 4); |
157 | 0 | outputLen = 0; |
158 | |
|
159 | 0 | if (nBlocks < 1) |
160 | 0 | { |
161 | 0 | free(data); |
162 | 0 | return NULL; |
163 | 0 | } |
164 | | |
165 | 0 | for (i = 0; i < nBlocks - 1; i++, q += 3) |
166 | 0 | { |
167 | 0 | n[0] = base64_decode_char(alphabet, *s++); |
168 | 0 | n[1] = base64_decode_char(alphabet, *s++); |
169 | 0 | n[2] = base64_decode_char(alphabet, *s++); |
170 | 0 | n[3] = base64_decode_char(alphabet, *s++); |
171 | |
|
172 | 0 | if ((n[0] == -1) || (n[1] == -1) || (n[2] == -1) || (n[3] == -1)) |
173 | 0 | goto out_free; |
174 | | |
175 | 0 | q[0] = (n[0] << 2) + (n[1] >> 4); |
176 | 0 | q[1] = ((n[1] & 15) << 4) + (n[2] >> 2); |
177 | 0 | q[2] = ((n[2] & 3) << 6) + n[3]; |
178 | 0 | outputLen += 3; |
179 | 0 | } |
180 | | |
181 | | /* treat last block */ |
182 | 0 | n[0] = base64_decode_char(alphabet, *s++); |
183 | 0 | n[1] = base64_decode_char(alphabet, *s++); |
184 | 0 | if ((n[0] == -1) || (n[1] == -1)) |
185 | 0 | goto out_free; |
186 | | |
187 | 0 | n[2] = remainder == 2 ? -1 : base64_decode_char(alphabet, *s++); |
188 | 0 | n[3] = remainder >= 2 ? -1 : base64_decode_char(alphabet, *s++); |
189 | |
|
190 | 0 | q[0] = (n[0] << 2) + (n[1] >> 4); |
191 | 0 | if (n[2] == -1) |
192 | 0 | { |
193 | | /* XX== */ |
194 | 0 | outputLen += 1; |
195 | 0 | if (n[3] != -1) |
196 | 0 | goto out_free; |
197 | | |
198 | 0 | q[1] = ((n[1] & 15) << 4); |
199 | 0 | } |
200 | 0 | else if (n[3] == -1) |
201 | 0 | { |
202 | | /* yyy= */ |
203 | 0 | outputLen += 2; |
204 | 0 | q[1] = ((n[1] & 15) << 4) + (n[2] >> 2); |
205 | 0 | q[2] = ((n[2] & 3) << 6); |
206 | 0 | } |
207 | 0 | else |
208 | 0 | { |
209 | | /* XXXX */ |
210 | 0 | outputLen += 3; |
211 | 0 | q[0] = (n[0] << 2) + (n[1] >> 4); |
212 | 0 | q[1] = ((n[1] & 15) << 4) + (n[2] >> 2); |
213 | 0 | q[2] = ((n[2] & 3) << 6) + n[3]; |
214 | 0 | } |
215 | | |
216 | 0 | if (data_len) |
217 | 0 | *data_len = outputLen; |
218 | 0 | data[outputLen] = '\0'; |
219 | |
|
220 | 0 | return data; |
221 | 0 | out_free: |
222 | 0 | free(data); |
223 | 0 | return NULL; |
224 | 0 | } |
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 | 0 | { |
238 | 0 | *dec_data = base64_decode(base64, enc_data, length, res_length, TRUE); |
239 | 0 | } |
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 | } |