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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include <winpr/crt.h>
25 
26 #include <freerdp/crypto/crypto.h>
27 
28 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
29 
crypto_base64_encode(const BYTE * data,int length)30 char* crypto_base64_encode(const BYTE* data, int length)
31 {
32 	int c;
33 	const BYTE* q;
34 	char* p;
35 	char* ret;
36 	int i = 0;
37 	int blocks;
38 
39 	q = data;
40 	p = ret = (char*)malloc((length + 3) * 4 / 3 + 1);
41 	if (!p)
42 		return NULL;
43 
44 	/* b1, b2, b3 are input bytes
45 	 *
46 	 * 0         1         2
47 	 * 012345678901234567890123
48 	 * |  b1  |  b2   |  b3   |
49 	 *
50 	 * [ c1 ]     [  c3 ]
51 	 *      [  c2 ]     [  c4 ]
52 	 *
53 	 * c1, c2, c3, c4 are output chars in base64
54 	 */
55 
56 	/* first treat complete blocks */
57 	blocks = length - (length % 3);
58 	for (i = 0; i < blocks; i += 3, q += 3)
59 	{
60 		c = (q[0] << 16) + (q[1] << 8) + q[2];
61 
62 		*p++ = base64[(c & 0x00FC0000) >> 18];
63 		*p++ = base64[(c & 0x0003F000) >> 12];
64 		*p++ = base64[(c & 0x00000FC0) >> 6];
65 		*p++ = base64[c & 0x0000003F];
66 	}
67 
68 	/* then remainder */
69 	switch (length % 3)
70 	{
71 		case 0:
72 			break;
73 		case 1:
74 			c = (q[0] << 16);
75 			*p++ = base64[(c & 0x00FC0000) >> 18];
76 			*p++ = base64[(c & 0x0003F000) >> 12];
77 			*p++ = '=';
78 			*p++ = '=';
79 			break;
80 		case 2:
81 			c = (q[0] << 16) + (q[1] << 8);
82 			*p++ = base64[(c & 0x00FC0000) >> 18];
83 			*p++ = base64[(c & 0x0003F000) >> 12];
84 			*p++ = base64[(c & 0x00000FC0) >> 6];
85 			*p++ = '=';
86 			break;
87 	}
88 
89 	*p = 0;
90 
91 	return ret;
92 }
93 
base64_decode_char(char c)94 static int base64_decode_char(char c)
95 {
96 	if (c >= 'A' && c <= 'Z')
97 		return c - 'A';
98 
99 	if (c >= 'a' && c <= 'z')
100 		return c - 'a' + 26;
101 
102 	if (c >= '0' && c <= '9')
103 		return c - '0' + 52;
104 
105 	if (c == '+')
106 		return 62;
107 
108 	if (c == '/')
109 		return 63;
110 
111 	if (c == '=')
112 		return -1;
113 
114 	return -1;
115 }
116 
base64_decode(const char * s,int length,int * data_len)117 static void* base64_decode(const char* s, int length, int* data_len)
118 {
119 	int n[4];
120 	BYTE* q;
121 	BYTE* data;
122 	int nBlocks, i, outputLen;
123 
124 	if (length % 4)
125 		return NULL;
126 
127 	q = data = (BYTE*)malloc(length / 4 * 3 + 1);
128 	if (!q)
129 		return NULL;
130 
131 	/* first treat complete blocks */
132 	nBlocks = (length / 4);
133 	outputLen = 0;
134 
135 	for (i = 0; i < nBlocks - 1; i++, q += 3)
136 	{
137 		n[0] = base64_decode_char(*s++);
138 		n[1] = base64_decode_char(*s++);
139 		n[2] = base64_decode_char(*s++);
140 		n[3] = base64_decode_char(*s++);
141 
142 		if ((n[0] == -1) || (n[1] == -1) || (n[2] == -1) || (n[3] == -1))
143 			goto out_free;
144 
145 		q[0] = (n[0] << 2) + (n[1] >> 4);
146 		q[1] = ((n[1] & 15) << 4) + (n[2] >> 2);
147 		q[2] = ((n[2] & 3) << 6) + n[3];
148 		outputLen += 3;
149 	}
150 
151 	/* treat last block */
152 	n[0] = base64_decode_char(*s++);
153 	n[1] = base64_decode_char(*s++);
154 	if ((n[0] == -1) || (n[1] == -1))
155 		goto out_free;
156 
157 	n[2] = base64_decode_char(*s++);
158 	n[3] = base64_decode_char(*s++);
159 
160 	q[0] = (n[0] << 2) + (n[1] >> 4);
161 	if (n[2] == -1)
162 	{
163 		/* XX== */
164 		outputLen += 1;
165 		if (n[3] != -1)
166 			goto out_free;
167 
168 		q[1] = ((n[1] & 15) << 4);
169 	}
170 	else if (n[3] == -1)
171 	{
172 		/* yyy= */
173 		outputLen += 2;
174 		q[1] = ((n[1] & 15) << 4) + (n[2] >> 2);
175 		q[2] = ((n[2] & 3) << 6);
176 	}
177 	else
178 	{
179 		/* XXXX */
180 		outputLen += 3;
181 		q[0] = (n[0] << 2) + (n[1] >> 4);
182 		q[1] = ((n[1] & 15) << 4) + (n[2] >> 2);
183 		q[2] = ((n[2] & 3) << 6) + n[3];
184 	}
185 
186 	*data_len = outputLen;
187 	data[outputLen] = '\0';
188 
189 	return data;
190 out_free:
191 	free(data);
192 	return NULL;
193 }
194 
crypto_base64_decode(const char * enc_data,int length,BYTE ** dec_data,int * res_length)195 void crypto_base64_decode(const char* enc_data, int length, BYTE** dec_data, int* res_length)
196 {
197 	*dec_data = base64_decode(enc_data, length, res_length);
198 }
199