1 /*-
2  * Copyright 2016 Vsevolod Stakhov
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #ifndef CRYPTOBOX_H_
17 #define CRYPTOBOX_H_
18 
19 #include "config.h"
20 
21 #include <sodium.h>
22 
23 #ifdef  __cplusplus
24 extern "C" {
25 #endif
26 
27 struct rspamd_cryptobox_segment {
28 	guchar *data;
29 	gsize len;
30 };
31 
32 #if defined(__GNUC__) && \
33     ((defined(__clang__) && (__clang_major__ >= 4 || (__clang_major__ >= 3 && __clang_minor__ >= 8))) || \
34     ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) || (__GNUC__ > 4)))
35 #define RSPAMD_HAS_TARGET_ATTR 1
36 #endif
37 
38 #define rspamd_cryptobox_MAX_NONCEBYTES 24
39 #define rspamd_cryptobox_MAX_PKBYTES 65
40 #define rspamd_cryptobox_MAX_SKBYTES 32
41 #define rspamd_cryptobox_MAX_MACBYTES 16
42 #define rspamd_cryptobox_MAX_NMBYTES 32
43 #define rspamd_cryptobox_SIPKEYBYTES 16
44 #define rspamd_cryptobox_HASHBYTES 64
45 #define rspamd_cryptobox_HASHKEYBYTES 64
46 #define rspamd_cryptobox_HASHSTATEBYTES sizeof(crypto_generichash_blake2b_state) + 64
47 #define rspamd_cryptobox_MAX_SIGSKBYTES 64
48 #define rspamd_cryptobox_MAX_SIGPKBYTES 32
49 #define rspamd_cryptobox_MAX_SIGBYTES 72
50 
51 #define CPUID_AVX2 0x1
52 #define CPUID_AVX 0x2
53 #define CPUID_SSE2 0x4
54 #define CPUID_SSE3 0x8
55 #define CPUID_SSSE3 0x10
56 #define CPUID_SSE41 0x20
57 #define CPUID_SSE42 0x40
58 #define CPUID_RDRAND 0x80
59 
60 typedef guchar rspamd_pk_t[rspamd_cryptobox_MAX_PKBYTES];
61 typedef guchar rspamd_sk_t[rspamd_cryptobox_MAX_SKBYTES];
62 typedef guchar rspamd_mac_t[rspamd_cryptobox_MAX_MACBYTES];
63 typedef guchar rspamd_nm_t[rspamd_cryptobox_MAX_NMBYTES];
64 typedef guchar rspamd_nonce_t[rspamd_cryptobox_MAX_NONCEBYTES];
65 typedef guchar rspamd_sipkey_t[rspamd_cryptobox_SIPKEYBYTES];
66 typedef guchar rspamd_signature_t[rspamd_cryptobox_MAX_SIGBYTES];
67 typedef guchar rspamd_sig_pk_t[rspamd_cryptobox_MAX_SIGPKBYTES];
68 typedef guchar rspamd_sig_sk_t[rspamd_cryptobox_MAX_SIGSKBYTES];
69 
70 enum rspamd_cryptobox_mode {
71 	RSPAMD_CRYPTOBOX_MODE_25519 = 0,
72 	RSPAMD_CRYPTOBOX_MODE_NIST
73 };
74 
75 struct rspamd_cryptobox_library_ctx {
76 	gchar *cpu_extensions;
77 	const gchar *chacha20_impl;
78 	const gchar *base64_impl;
79 	unsigned long cpu_config;
80 };
81 
82 /**
83  * Init cryptobox library
84  */
85 struct rspamd_cryptobox_library_ctx *rspamd_cryptobox_init (void);
86 
87 void rspamd_cryptobox_deinit (struct rspamd_cryptobox_library_ctx *);
88 /**
89  * Generate new keypair
90  * @param pk public key buffer
91  * @param sk secret key buffer
92  */
93 void rspamd_cryptobox_keypair (rspamd_pk_t pk, rspamd_sk_t sk,
94 							   enum rspamd_cryptobox_mode mode);
95 
96 /**
97  * Generate new keypair for signing
98  * @param pk public key buffer
99  * @param sk secret key buffer
100  */
101 void rspamd_cryptobox_keypair_sig (rspamd_sig_pk_t pk, rspamd_sig_sk_t sk,
102 								   enum rspamd_cryptobox_mode mode);
103 
104 /**
105  * Encrypt data inplace adding signature to sig afterwards
106  * @param data input buffer
107  * @param pk remote pubkey
108  * @param sk local secret key
109  * @param sig output signature
110  */
111 void rspamd_cryptobox_encrypt_inplace (guchar *data, gsize len,
112 									   const rspamd_nonce_t nonce,
113 									   const rspamd_pk_t pk, const rspamd_sk_t sk, rspamd_mac_t sig,
114 									   enum rspamd_cryptobox_mode mode);
115 
116 /**
117  * Encrypt segments of data inplace adding signature to sig afterwards
118  * @param segments segments of data
119  * @param cnt count of segments
120  * @param pk remote pubkey
121  * @param sk local secret key
122  * @param sig output signature
123  */
124 void rspamd_cryptobox_encryptv_inplace (struct rspamd_cryptobox_segment *segments,
125 										gsize cnt,
126 										const rspamd_nonce_t nonce,
127 										const rspamd_pk_t pk, const rspamd_sk_t sk, rspamd_mac_t sig,
128 										enum rspamd_cryptobox_mode mode);
129 
130 
131 /**
132  * Decrypt and verify data chunk inplace
133  * @param data data to decrypt
134  * @param len length of data
135  * @param pk remote pubkey
136  * @param sk local privkey
137  * @param sig signature input
138  * @return TRUE if input has been verified successfully
139  */
140 gboolean rspamd_cryptobox_decrypt_inplace (guchar *data, gsize len,
141 										   const rspamd_nonce_t nonce,
142 										   const rspamd_pk_t pk, const rspamd_sk_t sk, const rspamd_mac_t sig,
143 										   enum rspamd_cryptobox_mode mode);
144 
145 /**
146  * Encrypt segments of data inplace adding signature to sig afterwards
147  * @param segments segments of data
148  * @param cnt count of segments
149  * @param pk remote pubkey
150  * @param sk local secret key
151  * @param sig output signature
152  */
153 void rspamd_cryptobox_encrypt_nm_inplace (guchar *data, gsize len,
154 										  const rspamd_nonce_t nonce,
155 										  const rspamd_nm_t nm, rspamd_mac_t sig,
156 										  enum rspamd_cryptobox_mode mode);
157 
158 /**
159  * Encrypt segments of data inplace adding signature to sig afterwards
160  * @param segments segments of data
161  * @param cnt count of segments
162  * @param pk remote pubkey
163  * @param sk local secret key
164  * @param sig output signature
165  */
166 void rspamd_cryptobox_encryptv_nm_inplace (struct rspamd_cryptobox_segment *segments,
167 										   gsize cnt,
168 										   const rspamd_nonce_t nonce,
169 										   const rspamd_nm_t nm, rspamd_mac_t sig,
170 										   enum rspamd_cryptobox_mode mode);
171 
172 
173 /**
174  * Decrypt and verify data chunk inplace
175  * @param data data to decrypt
176  * @param len length of data
177  * @param pk remote pubkey
178  * @param sk local privkey
179  * @param sig signature input
180  * @return TRUE if input has been verified successfully
181  */
182 gboolean rspamd_cryptobox_decrypt_nm_inplace (guchar *data, gsize len,
183 											  const rspamd_nonce_t nonce,
184 											  const rspamd_nm_t nm, const rspamd_mac_t sig,
185 											  enum rspamd_cryptobox_mode mode);
186 
187 /**
188  * Generate shared secret from local sk and remote pk
189  * @param nm shared secret
190  * @param pk remote pubkey
191  * @param sk local privkey
192  */
193 void rspamd_cryptobox_nm (rspamd_nm_t nm, const rspamd_pk_t pk,
194 						  const rspamd_sk_t sk, enum rspamd_cryptobox_mode mode);
195 
196 /**
197  * Create digital signature for the specified message and place result in `sig`
198  * @param sig signature target
199  * @param siglen_p pointer to signature length (might be NULL)
200  * @param m input message
201  * @param mlen input length
202  * @param sk secret key
203  */
204 void rspamd_cryptobox_sign (guchar *sig, unsigned long long *siglen_p,
205 							const guchar *m, gsize mlen,
206 							const rspamd_sk_t sk,
207 							enum rspamd_cryptobox_mode mode);
208 
209 /**
210  * Verifies digital signature for the specified message using the specified
211  * pubkey
212  * @param sig signature source
213  * @param m input message
214  * @param mlen message length
215  * @param pk public key for verification
216  * @return true if signature is valid, false otherwise
217  */
218 bool rspamd_cryptobox_verify (const guchar *sig,
219 							  gsize siglen,
220 							  const guchar *m,
221 							  gsize mlen,
222 							  const rspamd_pk_t pk,
223 							  enum rspamd_cryptobox_mode mode);
224 
225 /**
226  * Securely clear the buffer specified
227  * @param buf buffer to zero
228  * @param buflen length of buffer
229  */
230 
231 #define rspamd_explicit_memzero sodium_memzero
232 
233 /**
234  * Constant time memcmp
235  * @param b1_
236  * @param b2_
237  * @param len
238  * @return
239  */
240 #define rspamd_cryptobox_memcmp sodium_memcmp
241 
242 /**
243  * Calculates siphash-2-4 for a message
244  * @param out (8 bytes output)
245  * @param in
246  * @param inlen
247  * @param k key (must be 16 bytes)
248  */
249 void rspamd_cryptobox_siphash (unsigned char *out, const unsigned char *in,
250 							   unsigned long long inlen,
251 							   const rspamd_sipkey_t k);
252 
253 enum rspamd_cryptobox_pbkdf_type {
254 	RSPAMD_CRYPTOBOX_PBKDF2 = 0,
255 	RSPAMD_CRYPTOBOX_CATENA
256 };
257 
258 
259 /**
260  * Derive key from password using the specified algorithm
261  * @param pass input password
262  * @param pass_len length of the password
263  * @param salt input salt
264  * @param salt_len length of salt
265  * @param key output key
266  * @param key_len size of the key
267  * @param complexity empiric number of complexity (rounds for pbkdf2 and garlic for catena)
268  * @return TRUE in case of success and FALSE if failed
269  */
270 gboolean rspamd_cryptobox_pbkdf (const char *pass, gsize pass_len,
271 								 const guint8 *salt, gsize salt_len,
272 								 guint8 *key, gsize key_len,
273 								 unsigned int complexity,
274 								 enum rspamd_cryptobox_pbkdf_type type);
275 
276 
277 /**
278  * Real size of rspamd cryptobox public key
279  */
280 guint rspamd_cryptobox_pk_bytes (enum rspamd_cryptobox_mode mode);
281 
282 /**
283  * Real size of rspamd cryptobox signing public key
284  */
285 guint rspamd_cryptobox_pk_sig_bytes (enum rspamd_cryptobox_mode mode);
286 
287 /**
288  * Real size of crypto nonce
289  */
290 guint rspamd_cryptobox_nonce_bytes (enum rspamd_cryptobox_mode mode);
291 
292 /**
293  * Real size of rspamd cryptobox secret key
294  */
295 guint rspamd_cryptobox_sk_bytes (enum rspamd_cryptobox_mode mode);
296 
297 /**
298  * Real size of rspamd cryptobox signing secret key
299  */
300 guint rspamd_cryptobox_sk_sig_bytes (enum rspamd_cryptobox_mode mode);
301 
302 /**
303  * Real size of rspamd cryptobox shared key
304  */
305 guint rspamd_cryptobox_nm_bytes (enum rspamd_cryptobox_mode mode);
306 
307 /**
308  * Real size of rspamd cryptobox MAC signature
309  */
310 guint rspamd_cryptobox_mac_bytes (enum rspamd_cryptobox_mode mode);
311 
312 /**
313  * Real size of rspamd cryptobox digital signature
314  */
315 guint rspamd_cryptobox_signature_bytes (enum rspamd_cryptobox_mode mode);
316 
317 /* Hash IUF interface */
318 typedef crypto_generichash_blake2b_state rspamd_cryptobox_hash_state_t;
319 
320 /**
321  * Init cryptobox hash state using key if needed, `st` must point to the buffer
322  * with at least rspamd_cryptobox_HASHSTATEBYTES bytes length. If keylen == 0, then
323  * non-keyed hash is generated
324  */
325 void rspamd_cryptobox_hash_init (rspamd_cryptobox_hash_state_t *st,
326 		const guchar *key, gsize keylen);
327 
328 /**
329  * Update hash with data portion
330  */
331 void rspamd_cryptobox_hash_update (rspamd_cryptobox_hash_state_t *st,
332 		const guchar *data, gsize len);
333 
334 /**
335  * Output hash to the buffer of rspamd_cryptobox_HASHBYTES length
336  */
337 void rspamd_cryptobox_hash_final (rspamd_cryptobox_hash_state_t *st, guchar *out);
338 
339 /**
340  * One in all function
341  */
342 void rspamd_cryptobox_hash (guchar *out,
343 							const guchar *data,
344 							gsize len,
345 							const guchar *key,
346 							gsize keylen);
347 
348 enum rspamd_cryptobox_fast_hash_type {
349 	RSPAMD_CRYPTOBOX_XXHASH64 = 0,
350 	RSPAMD_CRYPTOBOX_XXHASH32,
351 	RSPAMD_CRYPTOBOX_MUMHASH,
352 	RSPAMD_CRYPTOBOX_T1HA,
353 	RSPAMD_CRYPTOBOX_HASHFAST,
354 	RSPAMD_CRYPTOBOX_HASHFAST_INDEPENDENT
355 };
356 
357 /* Non crypto hash IUF interface */
358 typedef struct rspamd_cryptobox_fast_hash_state_s {
359 	guint64 opaque[11];
360 	enum rspamd_cryptobox_fast_hash_type type;
361 } rspamd_cryptobox_fast_hash_state_t;
362 
363 /**
364  * Init cryptobox hash state using key if needed, `st` must point to the buffer
365  * with at least rspamd_cryptobox_HASHSTATEBYTES bytes length. If keylen == 0, then
366  * non-keyed hash is generated
367  */
368 void rspamd_cryptobox_fast_hash_init (rspamd_cryptobox_fast_hash_state_t *st,
369 									  guint64 seed);
370 
371 /**
372  * Init cryptobox hash state using key if needed, `st` must point to the buffer
373  * with at least rspamd_cryptobox_HASHSTATEBYTES bytes length. If keylen == 0, then
374  * non-keyed hash is generated
375  */
376 void rspamd_cryptobox_fast_hash_init_specific (rspamd_cryptobox_fast_hash_state_t *st,
377 											   enum rspamd_cryptobox_fast_hash_type type,
378 											   guint64 seed);
379 
380 /**
381  * Update hash with data portion
382  */
383 void rspamd_cryptobox_fast_hash_update (rspamd_cryptobox_fast_hash_state_t *st,
384 										const void *data, gsize len);
385 
386 /**
387  * Output hash to the buffer of rspamd_cryptobox_HASHBYTES length
388  */
389 guint64 rspamd_cryptobox_fast_hash_final (rspamd_cryptobox_fast_hash_state_t *st);
390 
391 /**
392  * One in all function
393  */
394 guint64 rspamd_cryptobox_fast_hash (const void *data,
395 									gsize len, guint64 seed);
396 
397 /**
398  * Platform independent version
399  */
400 guint64 rspamd_cryptobox_fast_hash_specific (
401 		enum rspamd_cryptobox_fast_hash_type type,
402 		const void *data,
403 		gsize len, guint64 seed);
404 
405 /**
406  * Decode base64 using platform optimized code
407  * @param in
408  * @param inlen
409  * @param out
410  * @param outlen
411  * @return
412  */
413 gboolean rspamd_cryptobox_base64_decode (const gchar *in, gsize inlen,
414 										 guchar *out, gsize *outlen);
415 
416 /**
417  * Returns TRUE if data looks like a valid base64 string
418  * @param in
419  * @param inlen
420  * @return
421  */
422 gboolean rspamd_cryptobox_base64_is_valid (const gchar *in, gsize inlen);
423 
424 #ifdef  __cplusplus
425 }
426 #endif
427 
428 #endif /* CRYPTOBOX_H_ */
429