]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/dnssec_v2/utilities/base_encoding/base_n.c
mDNSResponder-1310.40.42.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / dnssec_v2 / utilities / base_encoding / base_n.c
1 //
2 // base_n.c
3 // mDNSResponder
4 //
5 // Copyright (c) 2020 Apple Inc. All rights reserved.
6 //
7
8 #pragma mark - Includes
9 #include "base_n.h"
10 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
11 #include <stdint.h>
12 #include <AssertMacros.h>
13 #include "dnssec_v2_log.h"
14
15 #pragma mark - Constants
16
17
18
19 #pragma mark b64_table
20 static const char b64_table[] = {
21 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
22 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
23 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
24 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
25 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
26 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
27 'w', 'x', 'y', 'z', '0', '1', '2', '3',
28 '4', '5', '6', '7', '8', '9', '+', '/'
29 };
30
31 #pragma mark b32_hex_table
32 static const char b32_hex_table[] = {
33 '0', '1', '2', '3', '4', '5', '6', '7',
34 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
35 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
36 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V'
37 };
38
39 #pragma mark - Macros
40
41
42
43 #define MAX_LENGTH_B64_ENCODING_DATA (SIZE_MAX * 3 / 4)
44 #define MAX_LENGTH_B32_HEX_ENCODING_DATA (SIZE_MAX * 5 / 8)
45
46 #pragma mark - Functions
47
48
49
50 #pragma mark - base_n_encode
51 char * _Nullable
52 base_n_encode(base_n_t base_n, const unsigned char * const _Nonnull data, size_t data_len) {
53 return base_n_encode_ex(base_n, data, data_len, NULL);
54 }
55
56 #pragma mark - base_n_encode_ex
57 char * _Nullable
58 base_n_encode_ex(base_n_t base_n, const unsigned char * const _Nonnull data, size_t data_len, size_t * const _Nullable out_str_len) {
59 char * encoded_str = mDNSNULL;
60 const size_t encoded_str_len = get_base_n_encoded_str_length(base_n, data_len);
61 char * encoded_str_ptr;
62 const unsigned char * data_ptr = data;
63 const unsigned char * const data_ptr_limit = data_ptr + data_len;
64 size_t remain;
65 uint64_t quantum;
66
67 encoded_str = malloc(encoded_str_len + 1);
68 require_quiet(encoded_str != mDNSNULL, exit);
69
70 // ensure that the string always ends with '\0'
71 encoded_str[encoded_str_len] = '\0';
72 encoded_str_ptr = encoded_str;
73
74 if (out_str_len != mDNSNULL) {
75 *out_str_len = encoded_str_len;
76 }
77
78 // encoding starts
79 switch (base_n) {
80 case DNSSEC_BASE_64: {
81 for(; data_ptr < data_ptr_limit;) {
82 char encoded_buf[4];
83 size_t encoded_size = 0;
84
85 remain = data_ptr_limit - data_ptr;
86 quantum = 0;
87 // get 24 bits from 3 bytes
88 switch (remain) {
89 default:
90 case 3: quantum |= (uint64_t)data_ptr[2]; // Bits 16 - 23
91 case 2: quantum |= ((uint64_t)data_ptr[1]) << 8; // Bits 8 - 15
92 case 1: quantum |= ((uint64_t)data_ptr[0]) << 16; // Bits 0 - 7
93 }
94 // advance the data pointer
95 data_ptr += ((remain > 3) ? 3 : remain);
96
97 // convert 24 bits to 4 characters
98 switch (remain) {
99 default:
100 case 3:
101 encoded_buf[3] = b64_table[ quantum & 0x3F];
102 encoded_size = 4;
103 case 2:
104 encoded_buf[2] = b64_table[(quantum >> 6) & 0x3F];
105 if (encoded_size == 0) encoded_size = 3;
106 case 1:
107 encoded_buf[1] = b64_table[(quantum >> 12) & 0x3F];
108 encoded_buf[0] = b64_table[(quantum >> 18) & 0x3F];
109 if (encoded_size == 0) encoded_size = 2;
110 }
111
112 // fill the padding with '='
113 for (size_t i = encoded_size; i < sizeof(encoded_buf); i++) {
114 encoded_buf[i] = '=';
115 }
116
117 // move the current encoded string chunk to the returned buffer
118 memcpy(encoded_str_ptr, encoded_buf, sizeof(encoded_buf));
119 encoded_str_ptr += sizeof(encoded_buf);
120 }
121 break;
122 }
123 case DNSSEC_BASE_32_HEX: {
124 for(; data_ptr < data_ptr_limit;) {
125 char encoded_buf[8];
126 size_t encoded_size = 0;
127
128 remain = data_ptr_limit - data_ptr;
129 quantum = 0;
130 // get 40 bits from 8 bytes
131 switch (remain) {
132 default:
133 case 5: quantum |= (uint64_t)data_ptr[4]; // Bits 32 - 39
134 case 4: quantum |= ((uint64_t)data_ptr[3]) << 8; // Bits 24 - 32
135 case 3: quantum |= ((uint64_t)data_ptr[2]) << 16; // Bits 16 - 23
136 case 2: quantum |= ((uint64_t)data_ptr[1]) << 24; // Bits 8 - 15
137 case 1: quantum |= ((uint64_t)data_ptr[0]) << 32; // Bits 0 - 7
138 }
139 // advance the data pointer
140 data_ptr += ((remain > 5) ? 5 : remain);
141
142 // convert 40 bits to 8 characters
143 switch (remain) {
144 default:
145 case 5:
146 encoded_buf[7] = b32_hex_table[quantum & 0x1F];
147 encoded_size = 8;
148 case 4:
149 encoded_buf[6] = b32_hex_table[(quantum >> 5) & 0x1F];
150 encoded_buf[5] = b32_hex_table[(quantum >> 10) & 0x1F];
151 if (encoded_size == 0) encoded_size = 7;
152 case 3:
153 encoded_buf[4] = b32_hex_table[(quantum >> 15) & 0x1F];
154 if (encoded_size == 0) encoded_size = 5;
155 case 2:
156 encoded_buf[3] = b32_hex_table[(quantum >> 20) & 0x1F];
157 encoded_buf[2] = b32_hex_table[(quantum >> 25) & 0x1F];
158 if (encoded_size == 0) encoded_size = 4;
159 case 1:
160 encoded_buf[1] = b32_hex_table[(quantum >> 30) & 0x1F];
161 encoded_buf[0] = b32_hex_table[(quantum >> 35) & 0x1F];
162 if (encoded_size == 0) encoded_size = 2;
163 }
164
165 // fill the padding with '='
166 for (size_t i = encoded_size; i < sizeof(encoded_buf); i++) {
167 encoded_buf[i] = '=';
168 }
169
170 // move the current encoded string chunk to the returned buffer
171 memcpy(encoded_str_ptr, encoded_buf, sizeof(encoded_buf));
172 encoded_str_ptr += sizeof(encoded_buf);
173 }
174 break;
175 }
176 default:
177 // Unsupported Base N, returns empty string.
178 encoded_str[0] = '\0';
179 break;
180 }
181
182 exit:
183 return encoded_str;
184 }
185
186 #pragma mark - get_base_n_encoded_str_length
187 size_t
188 get_base_n_encoded_str_length(base_n_t base_n, size_t data_len) {
189 size_t encoded_str_len = 0;
190
191 switch (base_n) {
192 case DNSSEC_BASE_64:
193 verify_action(data_len <= MAX_LENGTH_B64_ENCODING_DATA, data_len = MAX_LENGTH_B64_ENCODING_DATA);
194 encoded_str_len = (data_len + 2) / 3 * 4;
195 break;
196 case DNSSEC_BASE_32_HEX:
197 verify_action(data_len <= MAX_LENGTH_B32_HEX_ENCODING_DATA, data_len = MAX_LENGTH_B32_HEX_ENCODING_DATA);
198 encoded_str_len = (data_len + 4) / 5 * 8;
199 break;
200 default:
201 encoded_str_len = 0;
202 break;
203 }
204
205 return encoded_str_len;
206 }
207
208 #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)