summaryrefslogtreecommitdiffstats
path: root/src/libcryptobox/cryptobox.h
blob: 8cd79bbad51881f5f510b545d2911418c0dfe708 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
/*-
 * Copyright 2016 Vsevolod Stakhov
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef CRYPTOBOX_H_
#define CRYPTOBOX_H_

#include "config.h"

#include <sodium.h>

#ifdef __cplusplus
extern "C" {
#endif

struct rspamd_cryptobox_segment {
	guchar *data;
	gsize len;
};

#if defined(__GNUC__) &&                                                                                 \
	((defined(__clang__) && (__clang_major__ >= 4 || (__clang_major__ >= 3 && __clang_minor__ >= 8))) || \
	 ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) || (__GNUC__ > 4)))
#define RSPAMD_HAS_TARGET_ATTR 1
#endif

#define rspamd_cryptobox_MAX_NONCEBYTES 24
#define rspamd_cryptobox_MAX_PKBYTES 65
#define rspamd_cryptobox_MAX_SKBYTES 32
#define rspamd_cryptobox_MAX_MACBYTES 16
#define rspamd_cryptobox_MAX_NMBYTES 32
#define rspamd_cryptobox_SIPKEYBYTES 16
#define rspamd_cryptobox_HASHBYTES 64
#define rspamd_cryptobox_HASHKEYBYTES 64
#define rspamd_cryptobox_HASHSTATEBYTES sizeof(crypto_generichash_blake2b_state) + 64
#define rspamd_cryptobox_MAX_SIGSKBYTES 64
#define rspamd_cryptobox_MAX_SIGPKBYTES 32
#define rspamd_cryptobox_MAX_SIGBYTES 72

#define CPUID_AVX2 0x1
#define CPUID_AVX 0x2
#define CPUID_SSE2 0x4
#define CPUID_SSE3 0x8
#define CPUID_SSSE3 0x10
#define CPUID_SSE41 0x20
#define CPUID_SSE42 0x40
#define CPUID_RDRAND 0x80

typedef guchar rspamd_pk_t[rspamd_cryptobox_MAX_PKBYTES];
typedef guchar rspamd_sk_t[rspamd_cryptobox_MAX_SKBYTES];
typedef guchar rspamd_mac_t[rspamd_cryptobox_MAX_MACBYTES];
typedef guchar rspamd_nm_t[rspamd_cryptobox_MAX_NMBYTES];
typedef guchar rspamd_nonce_t[rspamd_cryptobox_MAX_NONCEBYTES];
typedef guchar rspamd_sipkey_t[rspamd_cryptobox_SIPKEYBYTES];
typedef guchar rspamd_signature_t[rspamd_cryptobox_MAX_SIGBYTES];
typedef guchar rspamd_sig_pk_t[rspamd_cryptobox_MAX_SIGPKBYTES];
typedef guchar rspamd_sig_sk_t[rspamd_cryptobox_MAX_SIGSKBYTES];

enum rspamd_cryptobox_mode {
	RSPAMD_CRYPTOBOX_MODE_25519 = 0,
	RSPAMD_CRYPTOBOX_MODE_NIST
};

struct rspamd_cryptobox_library_ctx {
	gchar *cpu_extensions;
	const gchar *chacha20_impl;
	const gchar *base64_impl;
	unsigned long cpu_config;
};

/**
 * Init cryptobox library
 */
struct rspamd_cryptobox_library_ctx *rspamd_cryptobox_init(void);

void rspamd_cryptobox_deinit(struct rspamd_cryptobox_library_ctx *);
/**
 * Generate new keypair
 * @param pk public key buffer
 * @param sk secret key buffer
 */
void rspamd_cryptobox_keypair(rspamd_pk_t pk, rspamd_sk_t sk,
							  enum rspamd_cryptobox_mode mode);

/**
 * Generate new keypair for signing
 * @param pk public key buffer
 * @param sk secret key buffer
 */
void rspamd_cryptobox_keypair_sig(rspamd_sig_pk_t pk, rspamd_sig_sk_t sk,
								  enum rspamd_cryptobox_mode mode);

/**
 * Encrypt data inplace adding signature to sig afterwards
 * @param data input buffer
 * @param pk remote pubkey
 * @param sk local secret key
 * @param sig output signature
 */
void rspamd_cryptobox_encrypt_inplace(guchar *data, gsize len,
									  const rspamd_nonce_t nonce,
									  const rspamd_pk_t pk, const rspamd_sk_t sk, rspamd_mac_t sig,
									  enum rspamd_cryptobox_mode mode);

/**
 * Encrypt segments of data inplace adding signature to sig afterwards
 * @param segments segments of data
 * @param cnt count of segments
 * @param pk remote pubkey
 * @param sk local secret key
 * @param sig output signature
 */
void rspamd_cryptobox_encryptv_inplace(struct rspamd_cryptobox_segment *segments,
									   gsize cnt,
									   const rspamd_nonce_t nonce,
									   const rspamd_pk_t pk, const rspamd_sk_t sk, rspamd_mac_t sig,
									   enum rspamd_cryptobox_mode mode);


/**
 * Decrypt and verify data chunk inplace
 * @param data data to decrypt
 * @param len length of data
 * @param pk remote pubkey
 * @param sk local privkey
 * @param sig signature input
 * @return TRUE if input has been verified successfully
 */
gboolean rspamd_cryptobox_decrypt_inplace(guchar *data, gsize len,
										  const rspamd_nonce_t nonce,
										  const rspamd_pk_t pk, const rspamd_sk_t sk, const rspamd_mac_t sig,
										  enum rspamd_cryptobox_mode mode);

/**
 * Encrypt segments of data inplace adding signature to sig afterwards
 * @param segments segments of data
 * @param cnt count of segments
 * @param pk remote pubkey
 * @param sk local secret key
 * @param sig output signature
 */
void rspamd_cryptobox_encrypt_nm_inplace(guchar *data, gsize len,
										 const rspamd_nonce_t nonce,
										 const rspamd_nm_t nm, rspamd_mac_t sig,
										 enum rspamd_cryptobox_mode mode);

/**
 * Encrypt segments of data inplace adding signature to sig afterwards
 * @param segments segments of data
 * @param cnt count of segments
 * @param pk remote pubkey
 * @param sk local secret key
 * @param sig output signature
 */
void rspamd_cryptobox_encryptv_nm_inplace(struct rspamd_cryptobox_segment *segments,
										  gsize cnt,
										  const rspamd_nonce_t nonce,
										  const rspamd_nm_t nm, rspamd_mac_t sig,
										  enum rspamd_cryptobox_mode mode);


/**
 * Decrypt and verify data chunk inplace
 * @param data data to decrypt
 * @param len length of data
 * @param pk remote pubkey
 * @param sk local privkey
 * @param sig signature input
 * @return TRUE if input has been verified successfully
 */
gboolean rspamd_cryptobox_decrypt_nm_inplace(guchar *data, gsize len,
											 const rspamd_nonce_t nonce,
											 const rspamd_nm_t nm, const rspamd_mac_t sig,
											 enum rspamd_cryptobox_mode mode);

/**
 * Generate shared secret from local sk and remote pk
 * @param nm shared secret
 * @param pk remote pubkey
 * @param sk local privkey
 */
void rspamd_cryptobox_nm(rspamd_nm_t nm, const rspamd_pk_t pk,
						 const rspamd_sk_t sk, enum rspamd_cryptobox_mode mode);

/**
 * Create digital signature for the specified message and place result in `sig`
 * @param sig signature target
 * @param siglen_p pointer to signature length (might be NULL)
 * @param m input message
 * @param mlen input length
 * @param sk secret key
 */
void rspamd_cryptobox_sign(guchar *sig, unsigned long long *siglen_p,
						   const guchar *m, gsize mlen,
						   const rspamd_sk_t sk,
						   enum rspamd_cryptobox_mode mode);

/**
 * Verifies digital signature for the specified message using the specified
 * pubkey
 * @param sig signature source
 * @param m input message
 * @param mlen message length
 * @param pk public key for verification
 * @return true if signature is valid, false otherwise
 */
bool rspamd_cryptobox_verify(const guchar *sig,
							 gsize siglen,
							 const guchar *m,
							 gsize mlen,
							 const rspamd_pk_t pk,
							 enum rspamd_cryptobox_mode mode);

/**
 * Securely clear the buffer specified
 * @param buf buffer to zero
 * @param buflen length of buffer
 */

#define rspamd_explicit_memzero sodium_memzero

/**
 * Constant time memcmp
 * @param b1_
 * @param b2_
 * @param len
 * @return
 */
#define rspamd_cryptobox_memcmp sodium_memcmp

/**
 * Calculates siphash-2-4 for a message
 * @param out (8 bytes output)
 * @param in
 * @param inlen
 * @param k key (must be 16 bytes)
 */
void rspamd_cryptobox_siphash(unsigned char *out, const unsigned char *in,
							  unsigned long long inlen,
							  const rspamd_sipkey_t k);

enum rspamd_cryptobox_pbkdf_type {
	RSPAMD_CRYPTOBOX_PBKDF2 = 0,
	RSPAMD_CRYPTOBOX_CATENA
};


/**
 * Derive key from password using the specified algorithm
 * @param pass input password
 * @param pass_len length of the password
 * @param salt input salt
 * @param salt_len length of salt
 * @param key output key
 * @param key_len size of the key
 * @param complexity empiric number of complexity (rounds for pbkdf2 and garlic for catena)
 * @return TRUE in case of success and FALSE if failed
 */
gboolean rspamd_cryptobox_pbkdf(const char *pass, gsize pass_len,
								const guint8 *salt, gsize salt_len,
								guint8 *key, gsize key_len,
								unsigned int complexity,
								enum rspamd_cryptobox_pbkdf_type type);


/**
 * Real size of rspamd cryptobox public key
 */
guint rspamd_cryptobox_pk_bytes(enum rspamd_cryptobox_mode mode);

/**
 * Real size of rspamd cryptobox signing public key
 */
guint rspamd_cryptobox_pk_sig_bytes(enum rspamd_cryptobox_mode mode);

/**
 * Real size of crypto nonce
 */
guint rspamd_cryptobox_nonce_bytes(enum rspamd_cryptobox_mode mode);

/**
 * Real size of rspamd cryptobox secret key
 */
guint rspamd_cryptobox_sk_bytes(enum rspamd_cryptobox_mode mode);

/**
 * Real size of rspamd cryptobox signing secret key
 */
guint rspamd_cryptobox_sk_sig_bytes(enum rspamd_cryptobox_mode mode);

/**
 * Real size of rspamd cryptobox shared key
 */
guint rspamd_cryptobox_nm_bytes(enum rspamd_cryptobox_mode mode);

/**
 * Real size of rspamd cryptobox MAC signature
 */
guint rspamd_cryptobox_mac_bytes(enum rspamd_cryptobox_mode mode);

/**
 * Real size of rspamd cryptobox digital signature
 */
guint rspamd_cryptobox_signature_bytes(enum rspamd_cryptobox_mode mode);

/* Hash IUF interface */
typedef crypto_generichash_blake2b_state rspamd_cryptobox_hash_state_t;

/**
 * Init cryptobox hash state using key if needed, `st` must point to the buffer
 * with at least rspamd_cryptobox_HASHSTATEBYTES bytes length. If keylen == 0, then
 * non-keyed hash is generated
 */
void rspamd_cryptobox_hash_init(rspamd_cryptobox_hash_state_t *st,
								const guchar *key, gsize keylen);

/**
 * Update hash with data portion
 */
void rspamd_cryptobox_hash_update(rspamd_cryptobox_hash_state_t *st,
								  const guchar *data, gsize len);

/**
 * Output hash to the buffer of rspamd_cryptobox_HASHBYTES length
 */
void rspamd_cryptobox_hash_final(rspamd_cryptobox_hash_state_t *st, guchar *out);

/**
 * One in all function
 */
void rspamd_cryptobox_hash(guchar *out,
						   const guchar *data,
						   gsize len,
						   const guchar *key,
						   gsize keylen);

enum rspamd_cryptobox_fast_hash_type {
	RSPAMD_CRYPTOBOX_XXHASH64 = 0,
	RSPAMD_CRYPTOBOX_XXHASH32,
	RSPAMD_CRYPTOBOX_XXHASH3,
	RSPAMD_CRYPTOBOX_MUMHASH,
	RSPAMD_CRYPTOBOX_T1HA,
	RSPAMD_CRYPTOBOX_HASHFAST,
	RSPAMD_CRYPTOBOX_HASHFAST_INDEPENDENT
};

/* Non crypto hash IUF interface */
typedef struct CRYPTO_ALIGN(64) rspamd_cryptobox_fast_hash_state_s {
	guchar opaque[576]; /* Required for xxhash3 */
	enum rspamd_cryptobox_fast_hash_type type;
} rspamd_cryptobox_fast_hash_state_t;


/**
 * Creates a new cryptobox state properly aligned
 * @return
 */
rspamd_cryptobox_fast_hash_state_t *rspamd_cryptobox_fast_hash_new(void);
void rspamd_cryptobox_fast_hash_free(rspamd_cryptobox_fast_hash_state_t *st);

/**
 * Init cryptobox hash state using key if needed, `st` must point to the buffer
 * with at least rspamd_cryptobox_HASHSTATEBYTES bytes length. If keylen == 0, then
 * non-keyed hash is generated
 */
void rspamd_cryptobox_fast_hash_init(rspamd_cryptobox_fast_hash_state_t *st,
									 guint64 seed);

/**
 * Init cryptobox hash state using key if needed, `st` must point to the buffer
 * with at least rspamd_cryptobox_HASHSTATEBYTES bytes length. If keylen == 0, then
 * non-keyed hash is generated
 */
void rspamd_cryptobox_fast_hash_init_specific(rspamd_cryptobox_fast_hash_state_t *st,
											  enum rspamd_cryptobox_fast_hash_type type,
											  guint64 seed);

/**
 * Update hash with data portion
 */
void rspamd_cryptobox_fast_hash_update(rspamd_cryptobox_fast_hash_state_t *st,
									   const void *data, gsize len);

/**
 * Output hash to the buffer of rspamd_cryptobox_HASHBYTES length
 */
guint64 rspamd_cryptobox_fast_hash_final(rspamd_cryptobox_fast_hash_state_t *st);

/**
 * One in all function
 */
guint64 rspamd_cryptobox_fast_hash(const void *data,
								   gsize len, guint64 seed);

/**
 * Platform independent version
 */
guint64 rspamd_cryptobox_fast_hash_specific(
	enum rspamd_cryptobox_fast_hash_type type,
	const void *data,
	gsize len, guint64 seed);

/**
 * Decode base64 using platform optimized code
 * @param in
 * @param inlen
 * @param out
 * @param outlen
 * @return
 */
gboolean rspamd_cryptobox_base64_decode(const gchar *in, gsize inlen,
										guchar *out, gsize *outlen);

/**
 * Returns TRUE if data looks like a valid base64 string
 * @param in
 * @param inlen
 * @return
 */
gboolean rspamd_cryptobox_base64_is_valid(const gchar *in, gsize inlen);

#ifdef __cplusplus
}
#endif

#endif /* CRYPTOBOX_H_ */