Coverage Report

Created: 2024-05-20 06:11

/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
}