chachapoly.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. /**
  2. * \file chachapoly.c
  3. *
  4. * \brief ChaCha20-Poly1305 AEAD construction based on RFC 7539.
  5. *
  6. * Copyright The Mbed TLS Contributors
  7. * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  8. */
  9. #include "common.h"
  10. #if defined(MBEDTLS_CHACHAPOLY_C)
  11. #include "mbedtls/chachapoly.h"
  12. #include "mbedtls/platform_util.h"
  13. #include "mbedtls/error.h"
  14. #include "mbedtls/constant_time.h"
  15. #include <string.h>
  16. #include "mbedtls/platform.h"
  17. #if !defined(MBEDTLS_CHACHAPOLY_ALT)
  18. #define CHACHAPOLY_STATE_INIT (0)
  19. #define CHACHAPOLY_STATE_AAD (1)
  20. #define CHACHAPOLY_STATE_CIPHERTEXT (2) /* Encrypting or decrypting */
  21. #define CHACHAPOLY_STATE_FINISHED (3)
  22. /**
  23. * \brief Adds nul bytes to pad the AAD for Poly1305.
  24. *
  25. * \param ctx The ChaCha20-Poly1305 context.
  26. */
  27. static int chachapoly_pad_aad(mbedtls_chachapoly_context *ctx)
  28. {
  29. uint32_t partial_block_len = (uint32_t) (ctx->aad_len % 16U);
  30. unsigned char zeroes[15];
  31. if (partial_block_len == 0U) {
  32. return 0;
  33. }
  34. memset(zeroes, 0, sizeof(zeroes));
  35. return mbedtls_poly1305_update(&ctx->poly1305_ctx,
  36. zeroes,
  37. 16U - partial_block_len);
  38. }
  39. /**
  40. * \brief Adds nul bytes to pad the ciphertext for Poly1305.
  41. *
  42. * \param ctx The ChaCha20-Poly1305 context.
  43. */
  44. static int chachapoly_pad_ciphertext(mbedtls_chachapoly_context *ctx)
  45. {
  46. uint32_t partial_block_len = (uint32_t) (ctx->ciphertext_len % 16U);
  47. unsigned char zeroes[15];
  48. if (partial_block_len == 0U) {
  49. return 0;
  50. }
  51. memset(zeroes, 0, sizeof(zeroes));
  52. return mbedtls_poly1305_update(&ctx->poly1305_ctx,
  53. zeroes,
  54. 16U - partial_block_len);
  55. }
  56. void mbedtls_chachapoly_init(mbedtls_chachapoly_context *ctx)
  57. {
  58. mbedtls_chacha20_init(&ctx->chacha20_ctx);
  59. mbedtls_poly1305_init(&ctx->poly1305_ctx);
  60. ctx->aad_len = 0U;
  61. ctx->ciphertext_len = 0U;
  62. ctx->state = CHACHAPOLY_STATE_INIT;
  63. ctx->mode = MBEDTLS_CHACHAPOLY_ENCRYPT;
  64. }
  65. void mbedtls_chachapoly_free(mbedtls_chachapoly_context *ctx)
  66. {
  67. if (ctx == NULL) {
  68. return;
  69. }
  70. mbedtls_chacha20_free(&ctx->chacha20_ctx);
  71. mbedtls_poly1305_free(&ctx->poly1305_ctx);
  72. ctx->aad_len = 0U;
  73. ctx->ciphertext_len = 0U;
  74. ctx->state = CHACHAPOLY_STATE_INIT;
  75. ctx->mode = MBEDTLS_CHACHAPOLY_ENCRYPT;
  76. }
  77. int mbedtls_chachapoly_setkey(mbedtls_chachapoly_context *ctx,
  78. const unsigned char key[32])
  79. {
  80. int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
  81. ret = mbedtls_chacha20_setkey(&ctx->chacha20_ctx, key);
  82. return ret;
  83. }
  84. int mbedtls_chachapoly_starts(mbedtls_chachapoly_context *ctx,
  85. const unsigned char nonce[12],
  86. mbedtls_chachapoly_mode_t mode)
  87. {
  88. int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
  89. unsigned char poly1305_key[64];
  90. /* Set counter = 0, will be update to 1 when generating Poly1305 key */
  91. ret = mbedtls_chacha20_starts(&ctx->chacha20_ctx, nonce, 0U);
  92. if (ret != 0) {
  93. goto cleanup;
  94. }
  95. /* Generate the Poly1305 key by getting the ChaCha20 keystream output with
  96. * counter = 0. This is the same as encrypting a buffer of zeroes.
  97. * Only the first 256-bits (32 bytes) of the key is used for Poly1305.
  98. * The other 256 bits are discarded.
  99. */
  100. memset(poly1305_key, 0, sizeof(poly1305_key));
  101. ret = mbedtls_chacha20_update(&ctx->chacha20_ctx, sizeof(poly1305_key),
  102. poly1305_key, poly1305_key);
  103. if (ret != 0) {
  104. goto cleanup;
  105. }
  106. ret = mbedtls_poly1305_starts(&ctx->poly1305_ctx, poly1305_key);
  107. if (ret == 0) {
  108. ctx->aad_len = 0U;
  109. ctx->ciphertext_len = 0U;
  110. ctx->state = CHACHAPOLY_STATE_AAD;
  111. ctx->mode = mode;
  112. }
  113. cleanup:
  114. mbedtls_platform_zeroize(poly1305_key, 64U);
  115. return ret;
  116. }
  117. int mbedtls_chachapoly_update_aad(mbedtls_chachapoly_context *ctx,
  118. const unsigned char *aad,
  119. size_t aad_len)
  120. {
  121. if (ctx->state != CHACHAPOLY_STATE_AAD) {
  122. return MBEDTLS_ERR_CHACHAPOLY_BAD_STATE;
  123. }
  124. ctx->aad_len += aad_len;
  125. return mbedtls_poly1305_update(&ctx->poly1305_ctx, aad, aad_len);
  126. }
  127. int mbedtls_chachapoly_update(mbedtls_chachapoly_context *ctx,
  128. size_t len,
  129. const unsigned char *input,
  130. unsigned char *output)
  131. {
  132. int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
  133. if ((ctx->state != CHACHAPOLY_STATE_AAD) &&
  134. (ctx->state != CHACHAPOLY_STATE_CIPHERTEXT)) {
  135. return MBEDTLS_ERR_CHACHAPOLY_BAD_STATE;
  136. }
  137. if (ctx->state == CHACHAPOLY_STATE_AAD) {
  138. ctx->state = CHACHAPOLY_STATE_CIPHERTEXT;
  139. ret = chachapoly_pad_aad(ctx);
  140. if (ret != 0) {
  141. return ret;
  142. }
  143. }
  144. ctx->ciphertext_len += len;
  145. if (ctx->mode == MBEDTLS_CHACHAPOLY_ENCRYPT) {
  146. ret = mbedtls_chacha20_update(&ctx->chacha20_ctx, len, input, output);
  147. if (ret != 0) {
  148. return ret;
  149. }
  150. ret = mbedtls_poly1305_update(&ctx->poly1305_ctx, output, len);
  151. if (ret != 0) {
  152. return ret;
  153. }
  154. } else { /* DECRYPT */
  155. ret = mbedtls_poly1305_update(&ctx->poly1305_ctx, input, len);
  156. if (ret != 0) {
  157. return ret;
  158. }
  159. ret = mbedtls_chacha20_update(&ctx->chacha20_ctx, len, input, output);
  160. if (ret != 0) {
  161. return ret;
  162. }
  163. }
  164. return 0;
  165. }
  166. int mbedtls_chachapoly_finish(mbedtls_chachapoly_context *ctx,
  167. unsigned char mac[16])
  168. {
  169. int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
  170. unsigned char len_block[16];
  171. if (ctx->state == CHACHAPOLY_STATE_INIT) {
  172. return MBEDTLS_ERR_CHACHAPOLY_BAD_STATE;
  173. }
  174. if (ctx->state == CHACHAPOLY_STATE_AAD) {
  175. ret = chachapoly_pad_aad(ctx);
  176. if (ret != 0) {
  177. return ret;
  178. }
  179. } else if (ctx->state == CHACHAPOLY_STATE_CIPHERTEXT) {
  180. ret = chachapoly_pad_ciphertext(ctx);
  181. if (ret != 0) {
  182. return ret;
  183. }
  184. }
  185. ctx->state = CHACHAPOLY_STATE_FINISHED;
  186. /* The lengths of the AAD and ciphertext are processed by
  187. * Poly1305 as the final 128-bit block, encoded as little-endian integers.
  188. */
  189. MBEDTLS_PUT_UINT64_LE(ctx->aad_len, len_block, 0);
  190. MBEDTLS_PUT_UINT64_LE(ctx->ciphertext_len, len_block, 8);
  191. ret = mbedtls_poly1305_update(&ctx->poly1305_ctx, len_block, 16U);
  192. if (ret != 0) {
  193. return ret;
  194. }
  195. ret = mbedtls_poly1305_finish(&ctx->poly1305_ctx, mac);
  196. return ret;
  197. }
  198. static int chachapoly_crypt_and_tag(mbedtls_chachapoly_context *ctx,
  199. mbedtls_chachapoly_mode_t mode,
  200. size_t length,
  201. const unsigned char nonce[12],
  202. const unsigned char *aad,
  203. size_t aad_len,
  204. const unsigned char *input,
  205. unsigned char *output,
  206. unsigned char tag[16])
  207. {
  208. int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
  209. ret = mbedtls_chachapoly_starts(ctx, nonce, mode);
  210. if (ret != 0) {
  211. goto cleanup;
  212. }
  213. ret = mbedtls_chachapoly_update_aad(ctx, aad, aad_len);
  214. if (ret != 0) {
  215. goto cleanup;
  216. }
  217. ret = mbedtls_chachapoly_update(ctx, length, input, output);
  218. if (ret != 0) {
  219. goto cleanup;
  220. }
  221. ret = mbedtls_chachapoly_finish(ctx, tag);
  222. cleanup:
  223. return ret;
  224. }
  225. int mbedtls_chachapoly_encrypt_and_tag(mbedtls_chachapoly_context *ctx,
  226. size_t length,
  227. const unsigned char nonce[12],
  228. const unsigned char *aad,
  229. size_t aad_len,
  230. const unsigned char *input,
  231. unsigned char *output,
  232. unsigned char tag[16])
  233. {
  234. return chachapoly_crypt_and_tag(ctx, MBEDTLS_CHACHAPOLY_ENCRYPT,
  235. length, nonce, aad, aad_len,
  236. input, output, tag);
  237. }
  238. int mbedtls_chachapoly_auth_decrypt(mbedtls_chachapoly_context *ctx,
  239. size_t length,
  240. const unsigned char nonce[12],
  241. const unsigned char *aad,
  242. size_t aad_len,
  243. const unsigned char tag[16],
  244. const unsigned char *input,
  245. unsigned char *output)
  246. {
  247. int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
  248. unsigned char check_tag[16];
  249. int diff;
  250. if ((ret = chachapoly_crypt_and_tag(ctx,
  251. MBEDTLS_CHACHAPOLY_DECRYPT, length, nonce,
  252. aad, aad_len, input, output, check_tag)) != 0) {
  253. return ret;
  254. }
  255. /* Check tag in "constant-time" */
  256. diff = mbedtls_ct_memcmp(tag, check_tag, sizeof(check_tag));
  257. if (diff != 0) {
  258. mbedtls_platform_zeroize(output, length);
  259. return MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED;
  260. }
  261. return 0;
  262. }
  263. #endif /* MBEDTLS_CHACHAPOLY_ALT */
  264. #if defined(MBEDTLS_SELF_TEST)
  265. static const unsigned char test_key[1][32] =
  266. {
  267. {
  268. 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
  269. 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
  270. 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
  271. 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
  272. }
  273. };
  274. static const unsigned char test_nonce[1][12] =
  275. {
  276. {
  277. 0x07, 0x00, 0x00, 0x00, /* 32-bit common part */
  278. 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 /* 64-bit IV */
  279. }
  280. };
  281. static const unsigned char test_aad[1][12] =
  282. {
  283. {
  284. 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
  285. 0xc4, 0xc5, 0xc6, 0xc7
  286. }
  287. };
  288. static const size_t test_aad_len[1] =
  289. {
  290. 12U
  291. };
  292. static const unsigned char test_input[1][114] =
  293. {
  294. {
  295. 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
  296. 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
  297. 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
  298. 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
  299. 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
  300. 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
  301. 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
  302. 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
  303. 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
  304. 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
  305. 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
  306. 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
  307. 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
  308. 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
  309. 0x74, 0x2e
  310. }
  311. };
  312. static const unsigned char test_output[1][114] =
  313. {
  314. {
  315. 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
  316. 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
  317. 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
  318. 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
  319. 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
  320. 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
  321. 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
  322. 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
  323. 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
  324. 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
  325. 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
  326. 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
  327. 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
  328. 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
  329. 0x61, 0x16
  330. }
  331. };
  332. static const size_t test_input_len[1] =
  333. {
  334. 114U
  335. };
  336. static const unsigned char test_mac[1][16] =
  337. {
  338. {
  339. 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
  340. 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
  341. }
  342. };
  343. /* Make sure no other definition is already present. */
  344. #undef ASSERT
  345. #define ASSERT(cond, args) \
  346. do \
  347. { \
  348. if (!(cond)) \
  349. { \
  350. if (verbose != 0) \
  351. mbedtls_printf args; \
  352. \
  353. return -1; \
  354. } \
  355. } \
  356. while (0)
  357. int mbedtls_chachapoly_self_test(int verbose)
  358. {
  359. mbedtls_chachapoly_context ctx;
  360. unsigned i;
  361. int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
  362. unsigned char output[200];
  363. unsigned char mac[16];
  364. for (i = 0U; i < 1U; i++) {
  365. if (verbose != 0) {
  366. mbedtls_printf(" ChaCha20-Poly1305 test %u ", i);
  367. }
  368. mbedtls_chachapoly_init(&ctx);
  369. ret = mbedtls_chachapoly_setkey(&ctx, test_key[i]);
  370. ASSERT(0 == ret, ("setkey() error code: %i\n", ret));
  371. ret = mbedtls_chachapoly_encrypt_and_tag(&ctx,
  372. test_input_len[i],
  373. test_nonce[i],
  374. test_aad[i],
  375. test_aad_len[i],
  376. test_input[i],
  377. output,
  378. mac);
  379. ASSERT(0 == ret, ("crypt_and_tag() error code: %i\n", ret));
  380. ASSERT(0 == memcmp(output, test_output[i], test_input_len[i]),
  381. ("failure (wrong output)\n"));
  382. ASSERT(0 == memcmp(mac, test_mac[i], 16U),
  383. ("failure (wrong MAC)\n"));
  384. mbedtls_chachapoly_free(&ctx);
  385. if (verbose != 0) {
  386. mbedtls_printf("passed\n");
  387. }
  388. }
  389. if (verbose != 0) {
  390. mbedtls_printf("\n");
  391. }
  392. return 0;
  393. }
  394. #endif /* MBEDTLS_SELF_TEST */
  395. #endif /* MBEDTLS_CHACHAPOLY_C */