/src/libzmq/src/zmq_utils.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: MPL-2.0 */ |
2 | | |
3 | | #include "precompiled.hpp" |
4 | | |
5 | | #include "macros.hpp" |
6 | | #include "clock.hpp" |
7 | | #include "err.hpp" |
8 | | #include "thread.hpp" |
9 | | #include "atomic_counter.hpp" |
10 | | #include "atomic_ptr.hpp" |
11 | | #include "random.hpp" |
12 | | #include <assert.h> |
13 | | #include <new> |
14 | | |
15 | | #if !defined ZMQ_HAVE_WINDOWS |
16 | | #include <unistd.h> |
17 | | #endif |
18 | | |
19 | | #if defined(ZMQ_USE_LIBSODIUM) |
20 | | #include "sodium.h" |
21 | | #endif |
22 | | |
23 | | void zmq_sleep (int seconds_) |
24 | 0 | { |
25 | | #if defined ZMQ_HAVE_WINDOWS |
26 | | Sleep (seconds_ * 1000); |
27 | | #else |
28 | 0 | sleep (seconds_); |
29 | 0 | #endif |
30 | 0 | } |
31 | | |
32 | | void *zmq_stopwatch_start () |
33 | 0 | { |
34 | 0 | uint64_t *watch = static_cast<uint64_t *> (malloc (sizeof (uint64_t))); |
35 | 0 | alloc_assert (watch); |
36 | 0 | *watch = zmq::clock_t::now_us (); |
37 | 0 | return static_cast<void *> (watch); |
38 | 0 | } |
39 | | |
40 | | unsigned long zmq_stopwatch_intermediate (void *watch_) |
41 | 0 | { |
42 | 0 | const uint64_t end = zmq::clock_t::now_us (); |
43 | 0 | const uint64_t start = *static_cast<uint64_t *> (watch_); |
44 | 0 | return static_cast<unsigned long> (end - start); |
45 | 0 | } |
46 | | |
47 | | unsigned long zmq_stopwatch_stop (void *watch_) |
48 | 0 | { |
49 | 0 | const unsigned long res = zmq_stopwatch_intermediate (watch_); |
50 | 0 | free (watch_); |
51 | 0 | return res; |
52 | 0 | } |
53 | | |
54 | | void *zmq_threadstart (zmq_thread_fn *func_, void *arg_) |
55 | 0 | { |
56 | 0 | zmq::thread_t *thread = new (std::nothrow) zmq::thread_t; |
57 | 0 | alloc_assert (thread); |
58 | 0 | thread->start (func_, arg_, "ZMQapp"); |
59 | 0 | return thread; |
60 | 0 | } |
61 | | |
62 | | void zmq_threadclose (void *thread_) |
63 | 0 | { |
64 | 0 | zmq::thread_t *p_thread = static_cast<zmq::thread_t *> (thread_); |
65 | 0 | p_thread->stop (); |
66 | 0 | LIBZMQ_DELETE (p_thread); |
67 | 0 | } |
68 | | |
69 | | // Z85 codec, taken from 0MQ RFC project, implements RFC32 Z85 encoding |
70 | | |
71 | | // Maps base 256 to base 85 |
72 | | static char encoder[85 + 1] = {"0123456789" |
73 | | "abcdefghij" |
74 | | "klmnopqrst" |
75 | | "uvwxyzABCD" |
76 | | "EFGHIJKLMN" |
77 | | "OPQRSTUVWX" |
78 | | "YZ.-:+=^!/" |
79 | | "*?&<>()[]{" |
80 | | "}@%$#"}; |
81 | | |
82 | | // Maps base 85 to base 256 |
83 | | // We chop off lower 32 and higher 128 ranges |
84 | | // 0xFF denotes invalid characters within this range |
85 | | static uint8_t decoder[96] = { |
86 | | 0xFF, 0x44, 0xFF, 0x54, 0x53, 0x52, 0x48, 0xFF, 0x4B, 0x4C, 0x46, 0x41, |
87 | | 0xFF, 0x3F, 0x3E, 0x45, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
88 | | 0x08, 0x09, 0x40, 0xFF, 0x49, 0x42, 0x4A, 0x47, 0x51, 0x24, 0x25, 0x26, |
89 | | 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, |
90 | | 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x4D, |
91 | | 0xFF, 0x4E, 0x43, 0xFF, 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, |
92 | | 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, |
93 | | 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x4F, 0xFF, 0x50, 0xFF, 0xFF}; |
94 | | |
95 | | // -------------------------------------------------------------------------- |
96 | | // Encode a binary frame as a string; destination string MUST be at least |
97 | | // size * 5 / 4 bytes long plus 1 byte for the null terminator. Returns |
98 | | // dest. Size must be a multiple of 4. |
99 | | // Returns NULL and sets errno = EINVAL for invalid input. |
100 | | |
101 | | char *zmq_z85_encode (char *dest_, const uint8_t *data_, size_t size_) |
102 | 0 | { |
103 | 0 | if (size_ % 4 != 0) { |
104 | 0 | errno = EINVAL; |
105 | 0 | return NULL; |
106 | 0 | } |
107 | 0 | unsigned int char_nbr = 0; |
108 | 0 | unsigned int byte_nbr = 0; |
109 | 0 | uint32_t value = 0; |
110 | 0 | while (byte_nbr < size_) { |
111 | | // Accumulate value in base 256 (binary) |
112 | 0 | value = value * 256 + data_[byte_nbr++]; |
113 | 0 | if (byte_nbr % 4 == 0) { |
114 | | // Output value in base 85 |
115 | 0 | unsigned int divisor = 85 * 85 * 85 * 85; |
116 | 0 | while (divisor) { |
117 | 0 | dest_[char_nbr++] = encoder[value / divisor % 85]; |
118 | 0 | divisor /= 85; |
119 | 0 | } |
120 | 0 | value = 0; |
121 | 0 | } |
122 | 0 | } |
123 | 0 | assert (char_nbr == size_ * 5 / 4); |
124 | 0 | dest_[char_nbr] = 0; |
125 | 0 | return dest_; |
126 | 0 | } |
127 | | |
128 | | |
129 | | // -------------------------------------------------------------------------- |
130 | | // Decode an encoded string into a binary frame; dest must be at least |
131 | | // strlen (string) * 4 / 5 bytes long. Returns dest. strlen (string) |
132 | | // must be a multiple of 5. |
133 | | // Returns NULL and sets errno = EINVAL for invalid input. |
134 | | |
135 | | uint8_t *zmq_z85_decode (uint8_t *dest_, const char *string_) |
136 | 0 | { |
137 | 0 | unsigned int byte_nbr = 0; |
138 | 0 | unsigned int char_nbr = 0; |
139 | 0 | uint32_t value = 0; |
140 | 0 | size_t src_len = strlen (string_); |
141 | |
|
142 | 0 | if (src_len < 5 || src_len % 5 != 0) |
143 | 0 | goto error_inval; |
144 | | |
145 | 0 | while (string_[char_nbr]) { |
146 | | // Accumulate value in base 85 |
147 | 0 | if (UINT32_MAX / 85 < value) { |
148 | | // Invalid z85 encoding, represented value exceeds 0xffffffff |
149 | 0 | goto error_inval; |
150 | 0 | } |
151 | 0 | value *= 85; |
152 | 0 | const uint8_t index = string_[char_nbr++] - 32; |
153 | 0 | if (index >= sizeof (decoder)) { |
154 | | // Invalid z85 encoding, character outside range |
155 | 0 | goto error_inval; |
156 | 0 | } |
157 | 0 | const uint32_t summand = decoder[index]; |
158 | 0 | if (summand == 0xFF || summand > (UINT32_MAX - value)) { |
159 | | // Invalid z85 encoding, invalid character or represented value exceeds 0xffffffff |
160 | 0 | goto error_inval; |
161 | 0 | } |
162 | 0 | value += summand; |
163 | 0 | if (char_nbr % 5 == 0) { |
164 | | // Output value in base 256 |
165 | 0 | unsigned int divisor = 256 * 256 * 256; |
166 | 0 | while (divisor) { |
167 | 0 | dest_[byte_nbr++] = value / divisor % 256; |
168 | 0 | divisor /= 256; |
169 | 0 | } |
170 | 0 | value = 0; |
171 | 0 | } |
172 | 0 | } |
173 | 0 | if (char_nbr % 5 != 0) { |
174 | 0 | goto error_inval; |
175 | 0 | } |
176 | 0 | assert (byte_nbr == strlen (string_) * 4 / 5); |
177 | 0 | return dest_; |
178 | | |
179 | 0 | error_inval: |
180 | 0 | errno = EINVAL; |
181 | 0 | return NULL; |
182 | 0 | } |
183 | | |
184 | | // -------------------------------------------------------------------------- |
185 | | // Generate a public/private keypair with libsodium. |
186 | | // Generated keys will be 40 byte z85-encoded strings. |
187 | | // Returns 0 on success, -1 on failure, setting errno. |
188 | | // Sets errno = ENOTSUP in the absence of a CURVE library. |
189 | | |
190 | | int zmq_curve_keypair (char *z85_public_key_, char *z85_secret_key_) |
191 | 0 | { |
192 | 0 | #if defined(ZMQ_HAVE_CURVE) |
193 | | #if crypto_box_PUBLICKEYBYTES != 32 || crypto_box_SECRETKEYBYTES != 32 |
194 | | #error "CURVE encryption library not built correctly" |
195 | | #endif |
196 | |
|
197 | 0 | uint8_t public_key[32]; |
198 | 0 | uint8_t secret_key[32]; |
199 | |
|
200 | 0 | zmq::random_open (); |
201 | |
|
202 | 0 | const int res = crypto_box_keypair (public_key, secret_key); |
203 | 0 | zmq_z85_encode (z85_public_key_, public_key, 32); |
204 | 0 | zmq_z85_encode (z85_secret_key_, secret_key, 32); |
205 | |
|
206 | 0 | zmq::random_close (); |
207 | |
|
208 | 0 | return res; |
209 | | #else |
210 | | (void) z85_public_key_, (void) z85_secret_key_; |
211 | | errno = ENOTSUP; |
212 | | return -1; |
213 | | #endif |
214 | 0 | } |
215 | | |
216 | | // -------------------------------------------------------------------------- |
217 | | // Derive the public key from a private key using libsodium. |
218 | | // Derived key will be 40 byte z85-encoded string. |
219 | | // Returns 0 on success, -1 on failure, setting errno. |
220 | | // Sets errno = ENOTSUP in the absence of a CURVE library. |
221 | | |
222 | | int zmq_curve_public (char *z85_public_key_, const char *z85_secret_key_) |
223 | 0 | { |
224 | 0 | #if defined(ZMQ_HAVE_CURVE) |
225 | | #if crypto_box_PUBLICKEYBYTES != 32 || crypto_box_SECRETKEYBYTES != 32 |
226 | | #error "CURVE encryption library not built correctly" |
227 | | #endif |
228 | |
|
229 | 0 | uint8_t public_key[32]; |
230 | 0 | uint8_t secret_key[32]; |
231 | |
|
232 | 0 | zmq::random_open (); |
233 | |
|
234 | 0 | if (zmq_z85_decode (secret_key, z85_secret_key_) == NULL) |
235 | 0 | return -1; |
236 | | |
237 | | // Return codes are suppressed as none of these can actually fail. |
238 | 0 | crypto_scalarmult_base (public_key, secret_key); |
239 | 0 | zmq_z85_encode (z85_public_key_, public_key, 32); |
240 | |
|
241 | 0 | zmq::random_close (); |
242 | |
|
243 | 0 | return 0; |
244 | | #else |
245 | | (void) z85_public_key_, (void) z85_secret_key_; |
246 | | errno = ENOTSUP; |
247 | | return -1; |
248 | | #endif |
249 | 0 | } |
250 | | |
251 | | |
252 | | // -------------------------------------------------------------------------- |
253 | | // Initialize a new atomic counter, which is set to zero |
254 | | |
255 | | void *zmq_atomic_counter_new (void) |
256 | 0 | { |
257 | 0 | zmq::atomic_counter_t *counter = new (std::nothrow) zmq::atomic_counter_t; |
258 | 0 | alloc_assert (counter); |
259 | 0 | return counter; |
260 | 0 | } |
261 | | |
262 | | // Se the value of the atomic counter |
263 | | |
264 | | void zmq_atomic_counter_set (void *counter_, int value_) |
265 | 0 | { |
266 | 0 | (static_cast<zmq::atomic_counter_t *> (counter_))->set (value_); |
267 | 0 | } |
268 | | |
269 | | // Increment the atomic counter, and return the old value |
270 | | |
271 | | int zmq_atomic_counter_inc (void *counter_) |
272 | 0 | { |
273 | 0 | return (static_cast<zmq::atomic_counter_t *> (counter_))->add (1); |
274 | 0 | } |
275 | | |
276 | | // Decrement the atomic counter and return 1 (if counter >= 1), or |
277 | | // 0 if counter hit zero. |
278 | | |
279 | | int zmq_atomic_counter_dec (void *counter_) |
280 | 0 | { |
281 | 0 | return (static_cast<zmq::atomic_counter_t *> (counter_))->sub (1) ? 1 : 0; |
282 | 0 | } |
283 | | |
284 | | // Return actual value of atomic counter |
285 | | |
286 | | int zmq_atomic_counter_value (void *counter_) |
287 | 0 | { |
288 | 0 | return (static_cast<zmq::atomic_counter_t *> (counter_))->get (); |
289 | 0 | } |
290 | | |
291 | | // Destroy atomic counter, and set reference to NULL |
292 | | |
293 | | void zmq_atomic_counter_destroy (void **counter_p_) |
294 | 0 | { |
295 | 0 | delete (static_cast<zmq::atomic_counter_t *> (*counter_p_)); |
296 | 0 | *counter_p_ = NULL; |
297 | 0 | } |