blob: 53e4d65b296da7968d6d9a13e207d6fcd80515fc [file] [log] [blame]
willy tarreau9e138862006-05-14 23:06:28 +02001/*
Krzysztof Piotr Oledzkifccbdc82010-01-29 13:36:23 +01002 * ASCII <-> Base64 conversion as described in RFC1421.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003 *
Willy Tarreauc01062b2010-10-07 19:27:29 +02004 * Copyright 2006-2010 Willy Tarreau <w@1wt.eu>
Krzysztof Piotr Oledzkifccbdc82010-01-29 13:36:23 +01005 * Copyright 2009-2010 Krzysztof Piotr Oledzki <ole@ans.pl>
willy tarreau9e138862006-05-14 23:06:28 +02006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
Krzysztof Piotr Oledzkifccbdc82010-01-29 13:36:23 +010014#include <stdlib.h>
15#include <string.h>
16
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020017#include <haproxy/api.h>
Willy Tarreau8d366972020-05-27 16:10:29 +020018#include <haproxy/base64.h>
willy tarreau9e138862006-05-14 23:06:28 +020019
Krzysztof Piotr Oledzkifccbdc82010-01-29 13:36:23 +010020#define B64BASE '#' /* arbitrary chosen base value */
21#define B64CMIN '+'
22#define B64CMAX 'z'
23#define B64PADV 64 /* Base64 chosen special pad value */
24
Willy Tarreau69e989c2008-06-29 17:17:38 +020025const char base64tab[65]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
Krzysztof Piotr Oledzkifccbdc82010-01-29 13:36:23 +010026const char base64rev[]="b###cXYZ[\\]^_`a###d###$%&'()*+,-./0123456789:;<=######>?@ABCDEFGHIJKLMNOPQRSTUVW";
willy tarreau9e138862006-05-14 23:06:28 +020027
28/* Encodes <ilen> bytes from <in> to <out> for at most <olen> chars (including
29 * the trailing zero). Returns the number of bytes written. No check is made
30 * for <in> or <out> to be NULL. Returns negative value if <olen> is too short
31 * to accept <ilen>. 4 output bytes are produced for 1 to 3 input bytes.
32 */
33int a2base64(char *in, int ilen, char *out, int olen)
34{
willy tarreau9e138862006-05-14 23:06:28 +020035 int convlen;
36
37 convlen = ((ilen + 2) / 3) * 4;
38
39 if (convlen >= olen)
40 return -1;
41
42 /* we don't need to check olen anymore */
43 while (ilen >= 3) {
Willy Tarreaubaaee002006-06-26 02:48:02 +020044 out[0] = base64tab[(((unsigned char)in[0]) >> 2)];
45 out[1] = base64tab[(((unsigned char)in[0] & 0x03) << 4) | (((unsigned char)in[1]) >> 4)];
46 out[2] = base64tab[(((unsigned char)in[1] & 0x0F) << 2) | (((unsigned char)in[2]) >> 6)];
47 out[3] = base64tab[(((unsigned char)in[2] & 0x3F))];
willy tarreau9e138862006-05-14 23:06:28 +020048 out += 4;
49 in += 3; ilen -= 3;
50 }
51
52 if (!ilen) {
53 out[0] = '\0';
54 } else {
Willy Tarreaubaaee002006-06-26 02:48:02 +020055 out[0] = base64tab[((unsigned char)in[0]) >> 2];
willy tarreau9e138862006-05-14 23:06:28 +020056 if (ilen == 1) {
Willy Tarreaubaaee002006-06-26 02:48:02 +020057 out[1] = base64tab[((unsigned char)in[0] & 0x03) << 4];
willy tarreau9e138862006-05-14 23:06:28 +020058 out[2] = '=';
59 } else {
Willy Tarreaubaaee002006-06-26 02:48:02 +020060 out[1] = base64tab[(((unsigned char)in[0] & 0x03) << 4) |
willy tarreau9e138862006-05-14 23:06:28 +020061 (((unsigned char)in[1]) >> 4)];
Willy Tarreaubaaee002006-06-26 02:48:02 +020062 out[2] = base64tab[((unsigned char)in[1] & 0x0F) << 2];
willy tarreau9e138862006-05-14 23:06:28 +020063 }
64 out[3] = '=';
65 out[4] = '\0';
66 }
67
68 return convlen;
69}
Krzysztof Piotr Oledzkifccbdc82010-01-29 13:36:23 +010070
71/* Decodes <ilen> bytes from <in> to <out> for at most <olen> chars.
72 * Returns the number of bytes converted. No check is made for
73 * <in> or <out> to be NULL. Returns -1 if <in> is invalid or ilen
74 * has wrong size, -2 if <olen> is too short.
75 * 1 to 3 output bytes are produced for 4 input bytes.
76 */
77int base64dec(const char *in, size_t ilen, char *out, size_t olen) {
78
79 unsigned char t[4];
80 signed char b;
81 int convlen = 0, i = 0, pad = 0;
82
83 if (ilen % 4)
84 return -1;
85
Emeric Bruned697e42019-01-14 14:38:39 +010086 if (olen < ((ilen / 4 * 3)
87 - (in[ilen-1] == '=' ? 1 : 0)
88 - (in[ilen-2] == '=' ? 1 : 0)))
Krzysztof Piotr Oledzkifccbdc82010-01-29 13:36:23 +010089 return -2;
90
91 while (ilen) {
92
93 /* if (*p < B64CMIN || *p > B64CMAX) */
94 b = (signed char)*in - B64CMIN;
95 if ((unsigned char)b > (B64CMAX-B64CMIN))
96 return -1;
97
98 b = base64rev[b] - B64BASE - 1;
99
100 /* b == -1: invalid character */
101 if (b < 0)
102 return -1;
103
Joseph Herlant3b4e8e12018-11-25 13:16:35 -0800104 /* padding has to be continuous */
Krzysztof Piotr Oledzkifccbdc82010-01-29 13:36:23 +0100105 if (pad && b != B64PADV)
106 return -1;
107
108 /* valid padding: "XX==" or "XXX=", but never "X===" or "====" */
109 if (pad && i < 2)
110 return -1;
111
112 if (b == B64PADV)
113 pad++;
114
115 t[i++] = b;
116
117 if (i == 4) {
118 /*
119 * WARNING: we allow to write little more data than we
120 * should, but the checks from the beginning of the
121 * functions guarantee that we can safely do that.
122 */
123
124 /* xx000000 xx001111 xx111122 xx222222 */
125 out[convlen] = ((t[0] << 2) + (t[1] >> 4));
126 out[convlen+1] = ((t[1] << 4) + (t[2] >> 2));
127 out[convlen+2] = ((t[2] << 6) + (t[3] >> 0));
128
129 convlen += 3-pad;
130
131 pad = i = 0;
132 }
133
134 in++;
135 ilen--;
136 }
137
138 return convlen;
139}
Willy Tarreauc01062b2010-10-07 19:27:29 +0200140
141
142/* Converts the lower 30 bits of an integer to a 5-char base64 string. The
143 * caller is responsible for ensuring that the output buffer can accept 6 bytes
144 * (5 + the trailing zero). The pointer to the string is returned. The
145 * conversion is performed with MSB first and in a format that can be
146 * decoded with b64tos30(). This format is not padded and thus is not
147 * compatible with usual base64 routines.
148 */
149const char *s30tob64(int in, char *out)
150{
151 int i;
152 for (i = 0; i < 5; i++) {
153 out[i] = base64tab[(in >> 24) & 0x3F];
154 in <<= 6;
155 }
156 out[5] = '\0';
157 return out;
158}
159
160/* Converts a 5-char base64 string encoded by s30tob64() into a 30-bit integer.
161 * The caller is responsible for ensuring that the input contains at least 5
162 * chars. If any unexpected character is encountered, a negative value is
163 * returned. Otherwise the decoded value is returned.
164 */
165int b64tos30(const char *in)
166{
167 int i, out;
168 signed char b;
169
170 out = 0;
171 for (i = 0; i < 5; i++) {
172 b = (signed char)in[i] - B64CMIN;
173 if ((unsigned char)b > (B64CMAX - B64CMIN))
174 return -1; /* input character out of range */
175
176 b = base64rev[b] - B64BASE - 1;
177 if (b < 0) /* invalid character */
178 return -1;
179
180 if (b == B64PADV) /* padding not allowed */
181 return -1;
182
183 out = (out << 6) + b;
184 }
185 return out;
186}