You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cryptobox.h 13KB

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