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.

keypair.c 23KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  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. #include "config.h"
  17. #include "libcryptobox/keypair.h"
  18. #include "libcryptobox/keypair_private.h"
  19. #include "libutil/str_util.h"
  20. #include "libutil/printf.h"
  21. #include "contrib/libottery/ottery.h"
  22. const guchar encrypted_magic[7] = {'r', 'u', 'c', 'l', 'e', 'v', '1'};
  23. static GQuark
  24. rspamd_keypair_quark(void)
  25. {
  26. return g_quark_from_static_string("rspamd-cryptobox-keypair");
  27. }
  28. /**
  29. * Returns specific private key for different keypair types
  30. */
  31. static void *
  32. rspamd_cryptobox_keypair_sk(struct rspamd_cryptobox_keypair *kp,
  33. guint *len)
  34. {
  35. g_assert(kp != NULL);
  36. if (kp->alg == RSPAMD_CRYPTOBOX_MODE_25519) {
  37. if (kp->type == RSPAMD_KEYPAIR_KEX) {
  38. *len = 32;
  39. return RSPAMD_CRYPTOBOX_KEYPAIR_25519(kp)->sk;
  40. }
  41. else {
  42. *len = 64;
  43. return RSPAMD_CRYPTOBOX_KEYPAIR_SIG_25519(kp)->sk;
  44. }
  45. }
  46. else {
  47. if (kp->type == RSPAMD_KEYPAIR_KEX) {
  48. *len = 32;
  49. return RSPAMD_CRYPTOBOX_KEYPAIR_NIST(kp)->sk;
  50. }
  51. else {
  52. *len = 32;
  53. return RSPAMD_CRYPTOBOX_KEYPAIR_SIG_NIST(kp)->sk;
  54. }
  55. }
  56. /* Not reached */
  57. return NULL;
  58. }
  59. static void *
  60. rspamd_cryptobox_keypair_pk(struct rspamd_cryptobox_keypair *kp,
  61. guint *len)
  62. {
  63. g_assert(kp != NULL);
  64. if (kp->alg == RSPAMD_CRYPTOBOX_MODE_25519) {
  65. if (kp->type == RSPAMD_KEYPAIR_KEX) {
  66. *len = 32;
  67. return RSPAMD_CRYPTOBOX_KEYPAIR_25519(kp)->pk;
  68. }
  69. else {
  70. *len = 32;
  71. return RSPAMD_CRYPTOBOX_KEYPAIR_SIG_25519(kp)->pk;
  72. }
  73. }
  74. else {
  75. if (kp->type == RSPAMD_KEYPAIR_KEX) {
  76. *len = 65;
  77. return RSPAMD_CRYPTOBOX_KEYPAIR_NIST(kp)->pk;
  78. }
  79. else {
  80. *len = 65;
  81. return RSPAMD_CRYPTOBOX_KEYPAIR_SIG_NIST(kp)->pk;
  82. }
  83. }
  84. /* Not reached */
  85. return NULL;
  86. }
  87. static void *
  88. rspamd_cryptobox_pubkey_pk(const struct rspamd_cryptobox_pubkey *kp,
  89. guint *len)
  90. {
  91. g_assert(kp != NULL);
  92. if (kp->alg == RSPAMD_CRYPTOBOX_MODE_25519) {
  93. if (kp->type == RSPAMD_KEYPAIR_KEX) {
  94. *len = 32;
  95. return RSPAMD_CRYPTOBOX_PUBKEY_25519(kp)->pk;
  96. }
  97. else {
  98. *len = 32;
  99. return RSPAMD_CRYPTOBOX_PUBKEY_SIG_25519(kp)->pk;
  100. }
  101. }
  102. else {
  103. if (kp->type == RSPAMD_KEYPAIR_KEX) {
  104. *len = 65;
  105. return RSPAMD_CRYPTOBOX_PUBKEY_NIST(kp)->pk;
  106. }
  107. else {
  108. *len = 65;
  109. return RSPAMD_CRYPTOBOX_PUBKEY_SIG_NIST(kp)->pk;
  110. }
  111. }
  112. /* Not reached */
  113. return NULL;
  114. }
  115. static struct rspamd_cryptobox_keypair *
  116. rspamd_cryptobox_keypair_alloc(enum rspamd_cryptobox_keypair_type type,
  117. enum rspamd_cryptobox_mode alg)
  118. {
  119. struct rspamd_cryptobox_keypair *kp;
  120. guint size = 0;
  121. if (alg == RSPAMD_CRYPTOBOX_MODE_25519) {
  122. if (type == RSPAMD_KEYPAIR_KEX) {
  123. size = sizeof(struct rspamd_cryptobox_keypair_25519);
  124. }
  125. else {
  126. size = sizeof(struct rspamd_cryptobox_keypair_sig_25519);
  127. }
  128. }
  129. else {
  130. if (type == RSPAMD_KEYPAIR_KEX) {
  131. size = sizeof(struct rspamd_cryptobox_keypair_nist);
  132. }
  133. else {
  134. size = sizeof(struct rspamd_cryptobox_keypair_sig_nist);
  135. }
  136. }
  137. g_assert(size >= sizeof(*kp));
  138. if (posix_memalign((void **) &kp, 32, size) != 0) {
  139. abort();
  140. }
  141. memset(kp, 0, size);
  142. return kp;
  143. }
  144. static struct rspamd_cryptobox_pubkey *
  145. rspamd_cryptobox_pubkey_alloc(enum rspamd_cryptobox_keypair_type type,
  146. enum rspamd_cryptobox_mode alg)
  147. {
  148. struct rspamd_cryptobox_pubkey *pk;
  149. guint size = 0;
  150. if (alg == RSPAMD_CRYPTOBOX_MODE_25519) {
  151. if (type == RSPAMD_KEYPAIR_KEX) {
  152. size = sizeof(struct rspamd_cryptobox_pubkey_25519);
  153. }
  154. else {
  155. size = sizeof(struct rspamd_cryptobox_pubkey_sig_25519);
  156. }
  157. }
  158. else {
  159. if (type == RSPAMD_KEYPAIR_KEX) {
  160. size = sizeof(struct rspamd_cryptobox_pubkey_nist);
  161. }
  162. else {
  163. size = sizeof(struct rspamd_cryptobox_pubkey_sig_nist);
  164. }
  165. }
  166. g_assert(size >= sizeof(*pk));
  167. if (posix_memalign((void **) &pk, 32, size) != 0) {
  168. abort();
  169. }
  170. memset(pk, 0, size);
  171. return pk;
  172. }
  173. void rspamd_cryptobox_nm_dtor(struct rspamd_cryptobox_nm *nm)
  174. {
  175. rspamd_explicit_memzero(nm->nm, sizeof(nm->nm));
  176. free(nm);
  177. }
  178. void rspamd_cryptobox_keypair_dtor(struct rspamd_cryptobox_keypair *kp)
  179. {
  180. void *sk;
  181. guint len = 0;
  182. sk = rspamd_cryptobox_keypair_sk(kp, &len);
  183. g_assert(sk != NULL && len > 0);
  184. rspamd_explicit_memzero(sk, len);
  185. if (kp->extensions) {
  186. ucl_object_unref(kp->extensions);
  187. }
  188. /* Not g_free as kp is aligned using posix_memalign */
  189. free(kp);
  190. }
  191. void rspamd_cryptobox_pubkey_dtor(struct rspamd_cryptobox_pubkey *p)
  192. {
  193. if (p->nm) {
  194. REF_RELEASE(p->nm);
  195. }
  196. /* Not g_free as p is aligned using posix_memalign */
  197. free(p);
  198. }
  199. struct rspamd_cryptobox_keypair *
  200. rspamd_keypair_new(enum rspamd_cryptobox_keypair_type type,
  201. enum rspamd_cryptobox_mode alg)
  202. {
  203. struct rspamd_cryptobox_keypair *kp;
  204. void *pk, *sk;
  205. guint size;
  206. kp = rspamd_cryptobox_keypair_alloc(type, alg);
  207. kp->alg = alg;
  208. kp->type = type;
  209. sk = rspamd_cryptobox_keypair_sk(kp, &size);
  210. pk = rspamd_cryptobox_keypair_pk(kp, &size);
  211. if (type == RSPAMD_KEYPAIR_KEX) {
  212. rspamd_cryptobox_keypair(pk, sk, alg);
  213. }
  214. else {
  215. rspamd_cryptobox_keypair_sig(pk, sk, alg);
  216. }
  217. rspamd_cryptobox_hash(kp->id, pk, size, NULL, 0);
  218. REF_INIT_RETAIN(kp, rspamd_cryptobox_keypair_dtor);
  219. return kp;
  220. }
  221. struct rspamd_cryptobox_keypair *
  222. rspamd_keypair_ref(struct rspamd_cryptobox_keypair *kp)
  223. {
  224. REF_RETAIN(kp);
  225. return kp;
  226. }
  227. void rspamd_keypair_unref(struct rspamd_cryptobox_keypair *kp)
  228. {
  229. REF_RELEASE(kp);
  230. }
  231. struct rspamd_cryptobox_pubkey *
  232. rspamd_pubkey_ref(struct rspamd_cryptobox_pubkey *kp)
  233. {
  234. REF_RETAIN(kp);
  235. return kp;
  236. }
  237. void rspamd_pubkey_unref(struct rspamd_cryptobox_pubkey *kp)
  238. {
  239. REF_RELEASE(kp);
  240. }
  241. enum rspamd_cryptobox_keypair_type
  242. rspamd_keypair_type(struct rspamd_cryptobox_keypair *kp)
  243. {
  244. g_assert(kp != NULL);
  245. return kp->type;
  246. }
  247. enum rspamd_cryptobox_keypair_type
  248. rspamd_pubkey_type(struct rspamd_cryptobox_pubkey *p)
  249. {
  250. g_assert(p != NULL);
  251. return p->type;
  252. }
  253. enum rspamd_cryptobox_mode
  254. rspamd_keypair_alg(struct rspamd_cryptobox_keypair *kp)
  255. {
  256. g_assert(kp != NULL);
  257. return kp->alg;
  258. }
  259. enum rspamd_cryptobox_mode
  260. rspamd_pubkey_alg(struct rspamd_cryptobox_pubkey *p)
  261. {
  262. g_assert(p != NULL);
  263. return p->alg;
  264. }
  265. struct rspamd_cryptobox_pubkey *
  266. rspamd_pubkey_from_base32(const gchar *b32,
  267. gsize len,
  268. enum rspamd_cryptobox_keypair_type type,
  269. enum rspamd_cryptobox_mode alg)
  270. {
  271. guchar *decoded;
  272. gsize dlen, expected_len;
  273. guint pklen;
  274. struct rspamd_cryptobox_pubkey *pk;
  275. guchar *pk_data;
  276. g_assert(b32 != NULL);
  277. if (len == 0) {
  278. len = strlen(b32);
  279. }
  280. decoded = rspamd_decode_base32(b32, len, &dlen, RSPAMD_BASE32_DEFAULT);
  281. if (decoded == NULL) {
  282. return NULL;
  283. }
  284. expected_len = (type == RSPAMD_KEYPAIR_KEX) ? rspamd_cryptobox_pk_bytes(alg) : rspamd_cryptobox_pk_sig_bytes(alg);
  285. if (dlen != expected_len) {
  286. g_free(decoded);
  287. return NULL;
  288. }
  289. pk = rspamd_cryptobox_pubkey_alloc(type, alg);
  290. REF_INIT_RETAIN(pk, rspamd_cryptobox_pubkey_dtor);
  291. pk->alg = alg;
  292. pk->type = type;
  293. pk_data = rspamd_cryptobox_pubkey_pk(pk, &pklen);
  294. memcpy(pk_data, decoded, pklen);
  295. g_free(decoded);
  296. rspamd_cryptobox_hash(pk->id, pk_data, pklen, NULL, 0);
  297. return pk;
  298. }
  299. struct rspamd_cryptobox_pubkey *
  300. rspamd_pubkey_from_hex(const gchar *hex,
  301. gsize len,
  302. enum rspamd_cryptobox_keypair_type type,
  303. enum rspamd_cryptobox_mode alg)
  304. {
  305. guchar *decoded;
  306. gsize dlen, expected_len;
  307. guint pklen;
  308. struct rspamd_cryptobox_pubkey *pk;
  309. guchar *pk_data;
  310. g_assert(hex != NULL);
  311. if (len == 0) {
  312. len = strlen(hex);
  313. }
  314. dlen = len / 2;
  315. decoded = rspamd_decode_hex(hex, len);
  316. if (decoded == NULL) {
  317. return NULL;
  318. }
  319. expected_len = (type == RSPAMD_KEYPAIR_KEX) ? rspamd_cryptobox_pk_bytes(alg) : rspamd_cryptobox_pk_sig_bytes(alg);
  320. if (dlen != expected_len) {
  321. g_free(decoded);
  322. return NULL;
  323. }
  324. pk = rspamd_cryptobox_pubkey_alloc(type, alg);
  325. REF_INIT_RETAIN(pk, rspamd_cryptobox_pubkey_dtor);
  326. pk->alg = alg;
  327. pk->type = type;
  328. pk_data = rspamd_cryptobox_pubkey_pk(pk, &pklen);
  329. memcpy(pk_data, decoded, pklen);
  330. g_free(decoded);
  331. rspamd_cryptobox_hash(pk->id, pk_data, pklen, NULL, 0);
  332. return pk;
  333. }
  334. struct rspamd_cryptobox_pubkey *
  335. rspamd_pubkey_from_bin(const guchar *raw,
  336. gsize len,
  337. enum rspamd_cryptobox_keypair_type type,
  338. enum rspamd_cryptobox_mode alg)
  339. {
  340. gsize expected_len;
  341. guint pklen;
  342. struct rspamd_cryptobox_pubkey *pk;
  343. guchar *pk_data;
  344. g_assert(raw != NULL && len > 0);
  345. expected_len = (type == RSPAMD_KEYPAIR_KEX) ? rspamd_cryptobox_pk_bytes(alg) : rspamd_cryptobox_pk_sig_bytes(alg);
  346. if (len != expected_len) {
  347. return NULL;
  348. }
  349. pk = rspamd_cryptobox_pubkey_alloc(type, alg);
  350. REF_INIT_RETAIN(pk, rspamd_cryptobox_pubkey_dtor);
  351. pk->alg = alg;
  352. pk->type = type;
  353. pk_data = rspamd_cryptobox_pubkey_pk(pk, &pklen);
  354. memcpy(pk_data, raw, pklen);
  355. rspamd_cryptobox_hash(pk->id, pk_data, pklen, NULL, 0);
  356. return pk;
  357. }
  358. const guchar *
  359. rspamd_pubkey_get_nm(struct rspamd_cryptobox_pubkey *p,
  360. struct rspamd_cryptobox_keypair *kp)
  361. {
  362. g_assert(p != NULL);
  363. if (p->nm) {
  364. if (memcmp(kp->id, (const guchar *) &p->nm->sk_id, sizeof(uint64_t)) == 0) {
  365. return p->nm->nm;
  366. }
  367. /* Wrong ID, need to recalculate */
  368. REF_RELEASE(p->nm);
  369. p->nm = NULL;
  370. }
  371. return NULL;
  372. }
  373. const guchar *
  374. rspamd_pubkey_calculate_nm(struct rspamd_cryptobox_pubkey *p,
  375. struct rspamd_cryptobox_keypair *kp)
  376. {
  377. g_assert(kp->alg == p->alg);
  378. g_assert(kp->type == p->type);
  379. g_assert(p->type == RSPAMD_KEYPAIR_KEX);
  380. if (p->nm == NULL) {
  381. if (posix_memalign((void **) &p->nm, 32, sizeof(*p->nm)) != 0) {
  382. abort();
  383. }
  384. memcpy(&p->nm->sk_id, kp->id, sizeof(uint64_t));
  385. REF_INIT_RETAIN(p->nm, rspamd_cryptobox_nm_dtor);
  386. }
  387. if (kp->alg == RSPAMD_CRYPTOBOX_MODE_25519) {
  388. struct rspamd_cryptobox_pubkey_25519 *rk_25519 =
  389. RSPAMD_CRYPTOBOX_PUBKEY_25519(p);
  390. struct rspamd_cryptobox_keypair_25519 *sk_25519 =
  391. RSPAMD_CRYPTOBOX_KEYPAIR_25519(kp);
  392. rspamd_cryptobox_nm(p->nm->nm, rk_25519->pk, sk_25519->sk, p->alg);
  393. }
  394. else {
  395. struct rspamd_cryptobox_pubkey_nist *rk_nist =
  396. RSPAMD_CRYPTOBOX_PUBKEY_NIST(p);
  397. struct rspamd_cryptobox_keypair_nist *sk_nist =
  398. RSPAMD_CRYPTOBOX_KEYPAIR_NIST(kp);
  399. rspamd_cryptobox_nm(p->nm->nm, rk_nist->pk, sk_nist->sk, p->alg);
  400. }
  401. return p->nm->nm;
  402. }
  403. const guchar *
  404. rspamd_keypair_get_id(struct rspamd_cryptobox_keypair *kp)
  405. {
  406. g_assert(kp != NULL);
  407. return kp->id;
  408. }
  409. const ucl_object_t *
  410. rspamd_keypair_get_extensions(struct rspamd_cryptobox_keypair *kp)
  411. {
  412. g_assert(kp != NULL);
  413. return kp->extensions;
  414. }
  415. const guchar *
  416. rspamd_pubkey_get_id(struct rspamd_cryptobox_pubkey *pk)
  417. {
  418. g_assert(pk != NULL);
  419. return pk->id;
  420. }
  421. const guchar *
  422. rspamd_pubkey_get_pk(struct rspamd_cryptobox_pubkey *pk,
  423. guint *len)
  424. {
  425. guchar *ret = NULL;
  426. guint rlen;
  427. ret = rspamd_cryptobox_pubkey_pk(pk, &rlen);
  428. if (len) {
  429. *len = rlen;
  430. }
  431. return ret;
  432. }
  433. static void
  434. rspamd_keypair_print_component(guchar *data, gsize datalen,
  435. GString *res, guint how, const gchar *description)
  436. {
  437. gint olen, b32_len;
  438. if (how & RSPAMD_KEYPAIR_HUMAN) {
  439. rspamd_printf_gstring(res, "%s: ", description);
  440. }
  441. if (how & RSPAMD_KEYPAIR_BASE32) {
  442. b32_len = (datalen * 8 / 5) + 2;
  443. g_string_set_size(res, res->len + b32_len);
  444. res->len -= b32_len;
  445. olen = rspamd_encode_base32_buf(data, datalen, res->str + res->len,
  446. res->len + b32_len - 1, RSPAMD_BASE32_DEFAULT);
  447. if (olen > 0) {
  448. res->len += olen;
  449. res->str[res->len] = '\0';
  450. }
  451. }
  452. else if (how & RSPAMD_KEYPAIR_HEX) {
  453. rspamd_printf_gstring(res, "%*xs", (gint) datalen, data);
  454. }
  455. else {
  456. g_string_append_len(res, data, datalen);
  457. }
  458. if (how & RSPAMD_KEYPAIR_HUMAN) {
  459. g_string_append_c(res, '\n');
  460. }
  461. }
  462. GString *
  463. rspamd_keypair_print(struct rspamd_cryptobox_keypair *kp, guint how)
  464. {
  465. GString *res;
  466. guint len;
  467. gpointer p;
  468. g_assert(kp != NULL);
  469. res = g_string_sized_new(63);
  470. if ((how & RSPAMD_KEYPAIR_PUBKEY)) {
  471. p = rspamd_cryptobox_keypair_pk(kp, &len);
  472. rspamd_keypair_print_component(p, len, res, how, "Public key");
  473. }
  474. if ((how & RSPAMD_KEYPAIR_PRIVKEY)) {
  475. p = rspamd_cryptobox_keypair_sk(kp, &len);
  476. rspamd_keypair_print_component(p, len, res, how, "Private key");
  477. }
  478. if ((how & RSPAMD_KEYPAIR_ID_SHORT)) {
  479. rspamd_keypair_print_component(kp->id, RSPAMD_KEYPAIR_SHORT_ID_LEN,
  480. res, how, "Short key ID");
  481. }
  482. if ((how & RSPAMD_KEYPAIR_ID)) {
  483. rspamd_keypair_print_component(kp->id, sizeof(kp->id), res, how, "Key ID");
  484. }
  485. return res;
  486. }
  487. GString *
  488. rspamd_pubkey_print(struct rspamd_cryptobox_pubkey *pk, guint how)
  489. {
  490. GString *res;
  491. guint len;
  492. gpointer p;
  493. g_assert(pk != NULL);
  494. res = g_string_sized_new(63);
  495. if ((how & RSPAMD_KEYPAIR_PUBKEY)) {
  496. p = rspamd_cryptobox_pubkey_pk(pk, &len);
  497. rspamd_keypair_print_component(p, len, res, how, "Public key");
  498. }
  499. if ((how & RSPAMD_KEYPAIR_ID_SHORT)) {
  500. rspamd_keypair_print_component(pk->id, RSPAMD_KEYPAIR_SHORT_ID_LEN,
  501. res, how, "Short key ID");
  502. }
  503. if ((how & RSPAMD_KEYPAIR_ID)) {
  504. rspamd_keypair_print_component(pk->id, sizeof(pk->id), res, how,
  505. "Key ID");
  506. }
  507. return res;
  508. }
  509. const guchar *
  510. rspamd_keypair_component(struct rspamd_cryptobox_keypair *kp,
  511. guint ncomp, guint *len)
  512. {
  513. guint rlen = 0;
  514. const guchar *ret = NULL;
  515. g_assert(kp != NULL);
  516. switch (ncomp) {
  517. case RSPAMD_KEYPAIR_COMPONENT_ID:
  518. rlen = sizeof(kp->id);
  519. ret = kp->id;
  520. break;
  521. case RSPAMD_KEYPAIR_COMPONENT_PK:
  522. ret = rspamd_cryptobox_keypair_pk(kp, &rlen);
  523. break;
  524. case RSPAMD_KEYPAIR_COMPONENT_SK:
  525. ret = rspamd_cryptobox_keypair_sk(kp, &rlen);
  526. break;
  527. }
  528. if (len) {
  529. *len = rlen;
  530. }
  531. return ret;
  532. }
  533. struct rspamd_cryptobox_keypair *
  534. rspamd_keypair_from_ucl(const ucl_object_t *obj)
  535. {
  536. const ucl_object_t *privkey, *pubkey, *elt;
  537. const gchar *str;
  538. enum rspamd_cryptobox_keypair_type type = RSPAMD_KEYPAIR_KEX;
  539. enum rspamd_cryptobox_mode mode = RSPAMD_CRYPTOBOX_MODE_25519;
  540. gboolean is_hex = FALSE;
  541. struct rspamd_cryptobox_keypair *kp;
  542. guint len;
  543. gsize ucl_len;
  544. gint dec_len;
  545. gpointer target;
  546. if (ucl_object_type(obj) != UCL_OBJECT) {
  547. return NULL;
  548. }
  549. elt = ucl_object_lookup(obj, "keypair");
  550. if (elt != NULL) {
  551. obj = elt;
  552. }
  553. pubkey = ucl_object_lookup_any(obj, "pubkey", "public", "public_key",
  554. NULL);
  555. if (pubkey == NULL || ucl_object_type(pubkey) != UCL_STRING) {
  556. return NULL;
  557. }
  558. privkey = ucl_object_lookup_any(obj, "privkey", "private", "private_key",
  559. "secret", "secret_key", NULL);
  560. if (privkey == NULL || ucl_object_type(privkey) != UCL_STRING) {
  561. return NULL;
  562. }
  563. /* Optional fields */
  564. elt = ucl_object_lookup(obj, "type");
  565. if (elt && ucl_object_type(elt) == UCL_STRING) {
  566. str = ucl_object_tostring(elt);
  567. if (g_ascii_strcasecmp(str, "kex") == 0) {
  568. type = RSPAMD_KEYPAIR_KEX;
  569. }
  570. else if (g_ascii_strcasecmp(str, "sign") == 0) {
  571. type = RSPAMD_KEYPAIR_SIGN;
  572. }
  573. /* TODO: handle errors */
  574. }
  575. elt = ucl_object_lookup(obj, "algorithm");
  576. if (elt && ucl_object_type(elt) == UCL_STRING) {
  577. str = ucl_object_tostring(elt);
  578. if (g_ascii_strcasecmp(str, "curve25519") == 0) {
  579. mode = RSPAMD_CRYPTOBOX_MODE_25519;
  580. }
  581. else if (g_ascii_strcasecmp(str, "nistp256") == 0) {
  582. mode = RSPAMD_CRYPTOBOX_MODE_NIST;
  583. }
  584. /* TODO: handle errors */
  585. }
  586. elt = ucl_object_lookup(obj, "encoding");
  587. if (elt && ucl_object_type(elt) == UCL_STRING) {
  588. str = ucl_object_tostring(elt);
  589. if (g_ascii_strcasecmp(str, "hex") == 0) {
  590. is_hex = TRUE;
  591. }
  592. /* TODO: handle errors */
  593. }
  594. kp = rspamd_cryptobox_keypair_alloc(type, mode);
  595. kp->type = type;
  596. kp->alg = mode;
  597. REF_INIT_RETAIN(kp, rspamd_cryptobox_keypair_dtor);
  598. g_assert(kp != NULL);
  599. target = rspamd_cryptobox_keypair_sk(kp, &len);
  600. str = ucl_object_tolstring(privkey, &ucl_len);
  601. if (is_hex) {
  602. dec_len = rspamd_decode_hex_buf(str, ucl_len, target, len);
  603. }
  604. else {
  605. dec_len = rspamd_decode_base32_buf(str, ucl_len, target, len, RSPAMD_BASE32_DEFAULT);
  606. }
  607. if (dec_len != (gint) len) {
  608. rspamd_keypair_unref(kp);
  609. return NULL;
  610. }
  611. target = rspamd_cryptobox_keypair_pk(kp, &len);
  612. str = ucl_object_tolstring(pubkey, &ucl_len);
  613. if (is_hex) {
  614. dec_len = rspamd_decode_hex_buf(str, ucl_len, target, len);
  615. }
  616. else {
  617. dec_len = rspamd_decode_base32_buf(str, ucl_len, target, len, RSPAMD_BASE32_DEFAULT);
  618. }
  619. if (dec_len != (gint) len) {
  620. rspamd_keypair_unref(kp);
  621. return NULL;
  622. }
  623. rspamd_cryptobox_hash(kp->id, target, len, NULL, 0);
  624. elt = ucl_object_lookup(obj, "extensions");
  625. if (elt && ucl_object_type(elt) == UCL_OBJECT) {
  626. /* Use copy to avoid issues with the refcounts */
  627. kp->extensions = ucl_object_copy(elt);
  628. }
  629. return kp;
  630. }
  631. ucl_object_t *
  632. rspamd_keypair_to_ucl(struct rspamd_cryptobox_keypair *kp,
  633. enum rspamd_keypair_dump_flags flags)
  634. {
  635. ucl_object_t *ucl_out, *elt;
  636. gint how = 0;
  637. GString *keypair_out;
  638. const gchar *encoding;
  639. g_assert(kp != NULL);
  640. if (flags & RSPAMD_KEYPAIR_DUMP_HEX) {
  641. how |= RSPAMD_KEYPAIR_HEX;
  642. encoding = "hex";
  643. }
  644. else {
  645. how |= RSPAMD_KEYPAIR_BASE32;
  646. encoding = "base32";
  647. }
  648. if (flags & RSPAMD_KEYPAIR_DUMP_FLATTENED) {
  649. ucl_out = ucl_object_typed_new(UCL_OBJECT);
  650. elt = ucl_out;
  651. }
  652. else {
  653. ucl_out = ucl_object_typed_new(UCL_OBJECT);
  654. elt = ucl_object_typed_new(UCL_OBJECT);
  655. ucl_object_insert_key(ucl_out, elt, "keypair", 0, false);
  656. }
  657. /* pubkey part */
  658. keypair_out = rspamd_keypair_print(kp,
  659. RSPAMD_KEYPAIR_PUBKEY | how);
  660. ucl_object_insert_key(elt,
  661. ucl_object_fromlstring(keypair_out->str, keypair_out->len),
  662. "pubkey", 0, false);
  663. g_string_free(keypair_out, TRUE);
  664. if (!(flags & RSPAMD_KEYPAIR_DUMP_NO_SECRET)) {
  665. /* privkey part */
  666. keypair_out = rspamd_keypair_print(kp,
  667. RSPAMD_KEYPAIR_PRIVKEY | how);
  668. ucl_object_insert_key(elt,
  669. ucl_object_fromlstring(keypair_out->str, keypair_out->len),
  670. "privkey", 0, false);
  671. g_string_free(keypair_out, TRUE);
  672. }
  673. keypair_out = rspamd_keypair_print(kp,
  674. RSPAMD_KEYPAIR_ID | how);
  675. ucl_object_insert_key(elt,
  676. ucl_object_fromlstring(keypair_out->str, keypair_out->len),
  677. "id", 0, false);
  678. g_string_free(keypair_out, TRUE);
  679. ucl_object_insert_key(elt,
  680. ucl_object_fromstring(encoding),
  681. "encoding", 0, false);
  682. ucl_object_insert_key(elt,
  683. ucl_object_fromstring(
  684. kp->alg == RSPAMD_CRYPTOBOX_MODE_NIST ? "nistp256" : "curve25519"),
  685. "algorithm", 0, false);
  686. ucl_object_insert_key(elt,
  687. ucl_object_fromstring(
  688. kp->type == RSPAMD_KEYPAIR_KEX ? "kex" : "sign"),
  689. "type", 0, false);
  690. if (kp->extensions) {
  691. ucl_object_insert_key(elt, ucl_object_copy(kp->extensions),
  692. "extensions", 0, false);
  693. }
  694. return ucl_out;
  695. }
  696. gboolean
  697. rspamd_keypair_decrypt(struct rspamd_cryptobox_keypair *kp,
  698. const guchar *in, gsize inlen,
  699. guchar **out, gsize *outlen,
  700. GError **err)
  701. {
  702. const guchar *nonce, *mac, *data, *pubkey;
  703. g_assert(kp != NULL);
  704. g_assert(in != NULL);
  705. if (kp->type != RSPAMD_KEYPAIR_KEX) {
  706. g_set_error(err, rspamd_keypair_quark(), EINVAL,
  707. "invalid keypair type");
  708. return FALSE;
  709. }
  710. if (inlen < sizeof(encrypted_magic) + rspamd_cryptobox_pk_bytes(kp->alg) +
  711. rspamd_cryptobox_mac_bytes(kp->alg) +
  712. rspamd_cryptobox_nonce_bytes(kp->alg)) {
  713. g_set_error(err, rspamd_keypair_quark(), E2BIG, "invalid size: too small");
  714. return FALSE;
  715. }
  716. if (memcmp(in, encrypted_magic, sizeof(encrypted_magic)) != 0) {
  717. g_set_error(err, rspamd_keypair_quark(), EINVAL,
  718. "invalid magic");
  719. return FALSE;
  720. }
  721. /* Set pointers */
  722. pubkey = in + sizeof(encrypted_magic);
  723. mac = pubkey + rspamd_cryptobox_pk_bytes(kp->alg);
  724. nonce = mac + rspamd_cryptobox_mac_bytes(kp->alg);
  725. data = nonce + rspamd_cryptobox_nonce_bytes(kp->alg);
  726. if (data - in >= inlen) {
  727. g_set_error(err, rspamd_keypair_quark(), E2BIG, "invalid size: too small");
  728. return FALSE;
  729. }
  730. inlen -= data - in;
  731. /* Allocate memory for output */
  732. *out = g_malloc(inlen);
  733. memcpy(*out, data, inlen);
  734. if (!rspamd_cryptobox_decrypt_inplace(*out, inlen, nonce, pubkey,
  735. rspamd_keypair_component(kp, RSPAMD_KEYPAIR_COMPONENT_SK, NULL),
  736. mac, kp->alg)) {
  737. g_set_error(err, rspamd_keypair_quark(), EPERM, "verification failed");
  738. g_free(*out);
  739. return FALSE;
  740. }
  741. if (outlen) {
  742. *outlen = inlen;
  743. }
  744. return TRUE;
  745. }
  746. gboolean
  747. rspamd_keypair_encrypt(struct rspamd_cryptobox_keypair *kp,
  748. const guchar *in, gsize inlen,
  749. guchar **out, gsize *outlen,
  750. GError **err)
  751. {
  752. guchar *nonce, *mac, *data, *pubkey;
  753. struct rspamd_cryptobox_keypair *local;
  754. gsize olen;
  755. g_assert(kp != NULL);
  756. g_assert(in != NULL);
  757. if (kp->type != RSPAMD_KEYPAIR_KEX) {
  758. g_set_error(err, rspamd_keypair_quark(), EINVAL,
  759. "invalid keypair type");
  760. return FALSE;
  761. }
  762. local = rspamd_keypair_new(kp->type, kp->alg);
  763. olen = inlen + sizeof(encrypted_magic) +
  764. rspamd_cryptobox_pk_bytes(kp->alg) +
  765. rspamd_cryptobox_mac_bytes(kp->alg) +
  766. rspamd_cryptobox_nonce_bytes(kp->alg);
  767. *out = g_malloc(olen);
  768. memcpy(*out, encrypted_magic, sizeof(encrypted_magic));
  769. pubkey = *out + sizeof(encrypted_magic);
  770. mac = pubkey + rspamd_cryptobox_pk_bytes(kp->alg);
  771. nonce = mac + rspamd_cryptobox_mac_bytes(kp->alg);
  772. data = nonce + rspamd_cryptobox_nonce_bytes(kp->alg);
  773. ottery_rand_bytes(nonce, rspamd_cryptobox_nonce_bytes(kp->alg));
  774. memcpy(data, in, inlen);
  775. memcpy(pubkey, rspamd_keypair_component(kp, RSPAMD_KEYPAIR_COMPONENT_PK, NULL),
  776. rspamd_cryptobox_pk_bytes(kp->alg));
  777. rspamd_cryptobox_encrypt_inplace(data, inlen, nonce, pubkey,
  778. rspamd_keypair_component(local, RSPAMD_KEYPAIR_COMPONENT_SK, NULL),
  779. mac, kp->alg);
  780. rspamd_keypair_unref(local);
  781. if (outlen) {
  782. *outlen = olen;
  783. }
  784. return TRUE;
  785. }
  786. gboolean
  787. rspamd_pubkey_encrypt(struct rspamd_cryptobox_pubkey *pk,
  788. const guchar *in, gsize inlen,
  789. guchar **out, gsize *outlen,
  790. GError **err)
  791. {
  792. guchar *nonce, *mac, *data, *pubkey;
  793. struct rspamd_cryptobox_keypair *local;
  794. gsize olen;
  795. g_assert(pk != NULL);
  796. g_assert(in != NULL);
  797. if (pk->type != RSPAMD_KEYPAIR_KEX) {
  798. g_set_error(err, rspamd_keypair_quark(), EINVAL,
  799. "invalid pubkey type");
  800. return FALSE;
  801. }
  802. local = rspamd_keypair_new(pk->type, pk->alg);
  803. olen = inlen + sizeof(encrypted_magic) +
  804. rspamd_cryptobox_pk_bytes(pk->alg) +
  805. rspamd_cryptobox_mac_bytes(pk->alg) +
  806. rspamd_cryptobox_nonce_bytes(pk->alg);
  807. *out = g_malloc(olen);
  808. memcpy(*out, encrypted_magic, sizeof(encrypted_magic));
  809. pubkey = *out + sizeof(encrypted_magic);
  810. mac = pubkey + rspamd_cryptobox_pk_bytes(pk->alg);
  811. nonce = mac + rspamd_cryptobox_mac_bytes(pk->alg);
  812. data = nonce + rspamd_cryptobox_nonce_bytes(pk->alg);
  813. ottery_rand_bytes(nonce, rspamd_cryptobox_nonce_bytes(pk->alg));
  814. memcpy(data, in, inlen);
  815. memcpy(pubkey, rspamd_pubkey_get_pk(pk, NULL),
  816. rspamd_cryptobox_pk_bytes(pk->alg));
  817. rspamd_cryptobox_encrypt_inplace(data, inlen, nonce, pubkey,
  818. rspamd_keypair_component(local, RSPAMD_KEYPAIR_COMPONENT_SK, NULL),
  819. mac, pk->alg);
  820. rspamd_keypair_unref(local);
  821. if (outlen) {
  822. *outlen = olen;
  823. }
  824. return TRUE;
  825. }