The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
base16.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** Encode/decode binary data using printable characters (base16 format - hex)
18 *
19 * @see RFC 4648 <http://www.ietf.org/rfc/rfc4648.txt>.
20 *
21 * @copyright 2021 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
22 */
23RCSID("$Id: 691c9659b38d8cfd2ebcdb7356625cd751f620a4 $")
24
25#include <freeradius-devel/util/base16.h>
26#define us(x) (uint8_t) x
27
28/** lower case encode alphabet for base16
29 *
30 */
32 [0] = '0',
33 [1] = '1',
34 [2] = '2',
35 [3] = '3',
36 [4] = '4',
37 [5] = '5',
38 [6] = '6',
39 [7] = '7',
40 [8] = '8',
41 [9] = '9',
42 [10] = 'a',
43 [11] = 'b',
44 [12] = 'c',
45 [13] = 'd',
46 [14] = 'e',
47 [15] = 'f'
48};
49
50/** lower case encode alphabet for base16
51 *
52 */
54 [0] = '0',
55 [1] = '1',
56 [2] = '2',
57 [3] = '3',
58 [4] = '4',
59 [5] = '5',
60 [6] = '6',
61 [7] = '7',
62 [8] = '8',
63 [9] = '9',
64 [10] = 'A',
65 [11] = 'B',
66 [12] = 'C',
67 [13] = 'D',
68 [14] = 'E',
69 [15] = 'F'
70};
71
72/** Mixed case decode alphabet for base16
73 *
74 */
76 F32(0, UINT8_MAX), F16(32, UINT8_MAX),
77 ['0'] = 0,
78 ['1'] = 1,
79 ['2'] = 2,
80 ['3'] = 3,
81 ['4'] = 4,
82 ['5'] = 5,
83 ['6'] = 6,
84 ['7'] = 7,
85 ['8'] = 8,
86 ['9'] = 9,
87 F4(58, UINT8_MAX), F2(62, UINT8_MAX), F1(64, UINT8_MAX),
88 ['A'] = 10, /* Uppercase */
89 ['B'] = 11,
90 ['C'] = 12,
91 ['D'] = 13,
92 ['E'] = 14,
93 ['F'] = 15,
94 F16(71, UINT8_MAX), F8(87, UINT8_MAX), F2(95, UINT8_MAX),
95 ['a'] = 10, /* Lowercase */
96 ['b'] = 11,
97 ['c'] = 12,
98 ['d'] = 13,
99 ['e'] = 14,
100 ['f'] = 15,
101 F128(103, UINT8_MAX), F16(231, UINT8_MAX), F8(247, UINT8_MAX), F1(255, UINT8_MAX)
102};
103
104/** Convert binary data to a hex string
105 *
106 * Ascii encoded hex string will not be prefixed with '0x'
107 *
108 * @param[out] out Output buffer to write to.
109 * @param[in] in input.
110 * @param[in] alphabet to use for encode.
111 * @return
112 * - >=0 the number of bytes written to out.
113 * - <0 number of bytes we would have needed to print the next hexit.
114 */
116{
117 fr_sbuff_t our_out = FR_SBUFF(out);
118 fr_dbuff_t our_in = FR_DBUFF(in);
119
120 while (fr_dbuff_extend(&our_in)) {
121 uint8_t a = *fr_dbuff_current(&our_in);
122
123 FR_SBUFF_IN_CHAR_RETURN(&our_out, alphabet[us(a >> 4)], (alphabet[us(a & 0x0f)]));
124 fr_dbuff_advance(&our_in, 1);
125 }
126
127 fr_sbuff_terminate(&our_out); /* Ensure this is terminated, even on zero length input */
128 fr_dbuff_set(in, &our_in);
129 FR_SBUFF_SET_RETURN(out, &our_out);
130}
131
132/** Decode base16 encoded input
133 *
134 * @param[out] err If non-null contains any parse errors.
135 * @param[out] out Where to write the decoded binary data.
136 * @param[in] in String to decode.
137 * @param[in] no_trailing Error out if we find non-base16 characters
138 * at the end of the string.
139 * @param[in] alphabet to use for decoding.
140 * @return
141 * - < 0 on failure. The offset where the decoding error occurred as a negative integer.
142 * - Length of decoded data.
143 */
145 bool no_trailing, uint8_t const alphabet[static UINT8_MAX + 1])
146{
147 fr_sbuff_t our_in = FR_SBUFF(in);
148 fr_dbuff_t our_out = FR_DBUFF(out);
149
150 while (fr_sbuff_extend_lowat(NULL, &our_in, 2) >= 2) {
151 char *p = fr_sbuff_current(&our_in);
152 bool a, b;
153
154 a = fr_is_base16_nstd(p[0], alphabet);
155 b = fr_is_base16_nstd(p[1], alphabet);
156 if (!a || !b) {
157 if (a && !b && no_trailing) {
159 FR_SBUFF_ERROR_RETURN(&our_in);
160 }
161 break;
162 }
163
164 FR_DBUFF_IN_BYTES_RETURN(&our_out, (alphabet[us(p[0])] << 4) | alphabet[us(p[1])]);
165
166 fr_sbuff_advance(&our_in, 2);
167 }
168
169 if (err) *err = FR_SBUFF_PARSE_OK;
170
171 fr_sbuff_set(in, &our_in);
172 return fr_dbuff_set(out, &our_out);
173}
char const fr_base16_alphabet_encode_lc[UINT8_MAX+1]
lower case encode alphabet for base16
Definition base16.c:31
fr_slen_t fr_base16_encode_nstd(fr_sbuff_t *out, fr_dbuff_t *in, char const alphabet[static UINT8_MAX+1])
Convert binary data to a hex string.
Definition base16.c:115
#define us(x)
Encode/decode binary data using printable characters (base16 format - hex)
Definition base16.c:26
char const fr_base16_alphabet_encode_uc[UINT8_MAX+1]
lower case encode alphabet for base16
Definition base16.c:53
fr_slen_t fr_base16_decode_nstd(fr_sbuff_parse_error_t *err, fr_dbuff_t *out, fr_sbuff_t *in, bool no_trailing, uint8_t const alphabet[static UINT8_MAX+1])
Decode base16 encoded input.
Definition base16.c:144
uint8_t const fr_base16_alphabet_decode_mc[UINT8_MAX+1]
Mixed case decode alphabet for base16.
Definition base16.c:75
static bool fr_is_base16_nstd(char c, uint8_t const alphabet[static UINT8_MAX+1])
Check if char is in base16 alphabet.
Definition base16.h:51
#define F4(_idx, _val)
Definition build.h:215
#define RCSID(id)
Definition build.h:483
#define F128(_idx, _val)
Definition build.h:220
#define F8(_idx, _val)
Definition build.h:216
#define F2(_idx, _val)
Definition build.h:214
#define F32(_idx, _val)
Definition build.h:218
#define F16(_idx, _val)
Definition build.h:217
#define F1(_idx, _val)
Fill macros for array initialisation.
Definition build.h:213
#define fr_dbuff_advance(_dbuff_or_marker, _len)
Advance 'current' position in dbuff or marker by _len bytes.
Definition dbuff.h:1072
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
Definition dbuff.h:911
#define fr_dbuff_set(_dst, _src)
Set the 'current' position in a dbuff or marker using another dbuff or marker, a char pointer,...
Definition dbuff.h:1004
#define fr_dbuff_extend(_dbuff)
Extend if no space remains.
Definition dbuff.h:705
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
Definition dbuff.h:222
#define FR_DBUFF_IN_BYTES_RETURN(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker returning if there's insufficient space.
Definition dbuff.h:1472
static fr_slen_t err
Definition dict.h:823
static fr_slen_t in
Definition dict.h:823
unsigned char uint8_t
ssize_t fr_slen_t
#define UINT8_MAX
fr_sbuff_parse_error_t
@ FR_SBUFF_PARSE_OK
No error.
@ FR_SBUFF_PARSE_ERROR_TRAILING
Trailing characters found.
#define FR_SBUFF_IN_CHAR_RETURN(_sbuff,...)
#define fr_sbuff_set(_dst, _src)
#define fr_sbuff_current(_sbuff_or_marker)
#define FR_SBUFF_ERROR_RETURN(_sbuff_or_marker)
#define FR_SBUFF_SET_RETURN(_dst, _src)
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define fr_sbuff_extend_lowat(_status, _sbuff_or_marker, _lowat)
static size_t char ** out
Definition value.h:997