Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021-2022 Project CHIP Authors
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #pragma once
19 :
20 : #include <lib/core/CHIPError.h>
21 : #include <lib/support/BitFlags.h>
22 : #include <lib/support/Span.h>
23 :
24 : #include <stdint.h>
25 : #include <stdlib.h>
26 :
27 : namespace chip {
28 : namespace Encoding {
29 :
30 : enum class HexFlags : int
31 : {
32 : kNone = 0u,
33 : // Use uppercase A-F if set otherwise, lowercase a-f
34 : kUppercase = (1u << 0),
35 : // Null-terminate buffer
36 : kNullTerminate = (1u << 1),
37 : // Both use uppercase and null-termination.
38 : // Separately stated to avoid casts for common case.
39 : kUppercaseAndNullTerminate = ((1u << 0) | (1u << 1))
40 : };
41 :
42 : /**
43 : * Encode a buffer of bytes into hexadecimal, with or without null-termination
44 : * and using either lowercase or uppercase hex. The input bytes are assumed to be
45 : * in a big-engian order. The output is also in a big-endian order.
46 : *
47 : * Default is lowercase output, not null-terminated.
48 : *
49 : * If `flags` has `HexFlags::kNullTerminate` set, treat `dest_hex` as a
50 : * null-terminated string buffer. The function returns CHIP_ERROR_BUFFER_TOO_SMALL
51 : * if `dest_size_max` can't fit the entire encoded buffer, and the
52 : * null-terminator if enabled. This function will never output truncated data.
53 : * The result either fits and is written, or does not fit and nothing is written
54 : * to `dest_hex`.
55 : *
56 : * If `src_bytes` and `dest_hex` overlap, the results may be incorrect, depending
57 : * on overlap, but only the core validity checks are done and it's possible to
58 : * get CHIP_NO_ERROR with erroneous output.
59 : *
60 : * On success, number of bytes written to destination is always:
61 : * output_size = (src_size * 2) + ((flags & HexFlags::kNullTerminate) ? 1 : 0);
62 : *
63 : * @param src_bytes Pointer to buffer to convert. Only allowed to be null if
64 : * src_size is 0.
65 : * @param src_size Number of bytes to convert from src_bytes
66 : * @param [out] dest_hex Destination buffer to receive hex encoding
67 : * @param dest_size_max Maximum buffer size for the hex encoded `dest_hex` buffer
68 : * including null-terminator if needed.
69 : * @param flags Flags from `HexFlags` for formatting options
70 : *
71 : * @return CHIP_ERROR_BUFFER_TOO_SMALL on dest_max_size too small to fit output
72 : * @return CHIP_ERROR_INVALID_ARGUMENT if either src_bytes or dest_hex is
73 : * nullptr without the corresponding size
74 : * being 0.
75 : * @return CHIP_NO_ERROR on success
76 : */
77 :
78 : CHIP_ERROR BytesToHex(const uint8_t * src_bytes, size_t src_size, char * dest_hex, size_t dest_size_max, BitFlags<HexFlags> flags);
79 :
80 : /**
81 : * Encode a uint64_t into hexadecimal, with or without null-termination
82 : * and using either lowercase or uppercase hex. The output will be in a big-engian
83 : * order.
84 : *
85 : * Default is lowercase output, not null-terminated.
86 : *
87 : * If `flags` has `HexFlags::kNullTerminate` set, treat `dest_hex` as a
88 : * null-terminated string buffer. The function returns CHIP_ERROR_BUFFER_TOO_SMALL
89 : * if `dest_size_max` can't fit the entire encoded buffer, and the
90 : * null-terminator if enabled. This function will never output truncated data.
91 : * The result either fits and is written, or does not fit and nothing is written
92 : * to `dest_hex`.
93 : *
94 : * On success, number of bytes written to destination is always
95 : * output_size = 16 + ((flags & HexFlags::kNullTerminate) ? 1 : 0);
96 : *
97 : * @param src 64-bit number to convert
98 : * @param [out] dest_hex Destination buffer to receive hex encoding
99 : * @param dest_size_max Maximum buffer size for the hex encoded `dest_hex` buffer
100 : * including null-terminator if needed.
101 : * @param flags Flags from `HexFlags` for formatting options
102 : *
103 : * @return CHIP_ERROR_BUFFER_TOO_SMALL on dest_max_size too small to fit output
104 : * @return CHIP_ERROR_INVALID_ARGUMENT if either src_bytes or dest_hex is nullptr
105 : * @return CHIP_NO_ERROR on success
106 : */
107 : CHIP_ERROR Uint64ToHex(uint64_t src, char * dest_hex, size_t dest_size_max, BitFlags<HexFlags> flags);
108 :
109 : /** Same as Uint64ToHex() but for uint32_t. */
110 : CHIP_ERROR Uint32ToHex(uint32_t src, char * dest_hex, size_t dest_size_max, BitFlags<HexFlags> flags);
111 :
112 : /** Same as Uint64ToHex() but for uint16_t. */
113 : CHIP_ERROR Uint16ToHex(uint16_t src, char * dest_hex, size_t dest_size_max, BitFlags<HexFlags> flags);
114 :
115 : // Alias for Uppercase option, no null-termination
116 2 : inline CHIP_ERROR BytesToUppercaseHexBuffer(const uint8_t * src_bytes, size_t src_size, char * dest_hex_buf, size_t dest_size_max)
117 : {
118 2 : return BytesToHex(src_bytes, src_size, dest_hex_buf, dest_size_max, HexFlags::kUppercase);
119 : }
120 :
121 : // Alias for Lowercase option, no null-termination
122 : inline CHIP_ERROR BytesToLowercaseHexBuffer(const uint8_t * src_bytes, size_t src_size, char * dest_hex_buf, size_t dest_size_max)
123 : {
124 : return BytesToHex(src_bytes, src_size, dest_hex_buf, dest_size_max, HexFlags::kNone);
125 : }
126 :
127 : // Alias for Uppercase option, with null-termination
128 28 : inline CHIP_ERROR BytesToUppercaseHexString(const uint8_t * src_bytes, size_t src_size, char * dest_hex_str, size_t dest_size_max)
129 : {
130 28 : return BytesToHex(src_bytes, src_size, dest_hex_str, dest_size_max, HexFlags::kUppercaseAndNullTerminate);
131 : }
132 :
133 : // Alias for Lowercase option, with null-termination
134 : inline CHIP_ERROR BytesToLowercaseHexString(const uint8_t * src_bytes, size_t src_size, char * dest_hex_str, size_t dest_size_max)
135 : {
136 : return BytesToHex(src_bytes, src_size, dest_hex_str, dest_size_max, HexFlags::kNullTerminate);
137 : }
138 :
139 : /**
140 : * @brief Dumps a binary buffer to log as hexadecimal
141 : *
142 : * Output is 32 bytes per line of uppercase hex, prepended with a given label.
143 : *
144 : * This function is useful to dump binary buffers such as certificates
145 : * which may need to be extracted from logs during debugging.
146 : *
147 : * Format is organized to allow easy extraction by searching the regex
148 : * `LABEL>>>[0-9A-F]+$` where LABEL is the `label` argument passed.
149 : *
150 : * Format looks like:
151 : *
152 : * ```
153 : * label>>>A54A39294B28886E8BFC15B44105A3FD22745225983A753E6BB82DA7C62493BF
154 : * label>>>02C3ED03D41B6F7874E7E887321DE7B4872CEB9F080B6ECE14A8ABFA260573A3
155 : * label>>>8D759C
156 : * ```
157 : *
158 : * If buffer is empty, at least one line with the `LABEL>>>` will be logged,
159 : * with no data.
160 : *
161 : * @param label - label to prepend. If nullptr, no label will be prepended
162 : * @param span - Span over buffer that needs to be dumped.
163 : */
164 : void LogBufferAsHex(const char * label, const ByteSpan & span);
165 :
166 : /**
167 : * Convert a buffer of hexadecimal characters to bytes. Supports both lowercase
168 : * and uppercase (or a mix of cases) hexadecimal characters. Supported input is
169 : * [0-9a-fA-F]. The input is assumed to be in a big-endian order. The output is
170 : * also in a big-endian order.
171 : *
172 : * @param src_hex a pointer to the character buffer to convert. It is not
173 : * assumed to be null-terminated.
174 : * @param src_size the number of characters to convert from src_hex.
175 : * @param dest_bytes the buffer to fill with the decoded bytes.
176 : * @param dest_size_max the total size of the buffer to be filled.
177 : *
178 : * @return 0 on errors:
179 : * - dest_size_max not big enough.
180 : * - src_size not even.
181 : * - Some character not in [0-9a-fA-F] is present in src_hex.
182 : * Otherwise, returns number of bytes actually decoded from the string on success.
183 : */
184 : size_t HexToBytes(const char * src_hex, const size_t src_size, uint8_t * dest_bytes, size_t dest_size_max);
185 :
186 : /**
187 : * Convert a buffer of hexadecimal characters into uint64_t. Supports only
188 : * uppercase hexadecimal input characters. Supported input is [0-9A-F].
189 : * The input is assumed to be in a big-endian order.
190 : *
191 : * @param src_hex a pointer to the character buffer to convert. It is not
192 : * assumed to be null-terminated.
193 : * @param src_size the number of characters to convert from src_hex.
194 : * @param dest 64-bit number to output.
195 : *
196 : * @return 0 on errors:
197 : * - src_size not even.
198 : * - Some character not in [0-9A-F] is present in src_hex.
199 : * Otherwise, returns 8 (number of bytes actually decoded from the string) on success.
200 : */
201 : size_t UppercaseHexToUint64(const char * src_hex, const size_t src_size, uint64_t & dest);
202 :
203 : /** Same as UppercaseHexToUint64() but for uint32_t. */
204 : size_t UppercaseHexToUint32(const char * src_hex, const size_t src_size, uint32_t & dest);
205 :
206 : /** Same as UppercaseHexToUint64() but for uint16_t. */
207 : size_t UppercaseHexToUint16(const char * src_hex, const size_t src_size, uint16_t & dest);
208 :
209 : /**
210 : * Computes the hex encoded length for a given input length.
211 : * Left shift to generate optimized equivalent of LEN*2.
212 : */
213 : #define HEX_ENCODED_LENGTH(LEN) ((LEN) << 1)
214 :
215 : /**
216 : * Computes the maximum possible decoded length for a given hex string input length.
217 : * Right shift to generate optimized equivalent of LEN/2.
218 : */
219 : #define HEX_MAX_DECODED_LENGTH(LEN) ((LEN) >> 1)
220 :
221 : } // namespace Encoding
222 : } // namespace chip
|