chacha20poly1305.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. #ifdef FREEBL_NO_DEPEND
  5. #include "stubs.h"
  6. #endif
  7. #include <string.h>
  8. #include <stdio.h>
  9. #include "seccomon.h"
  10. #include "secerr.h"
  11. #include "blapit.h"
  12. #include "blapii.h"
  13. #include "chacha20poly1305.h"
  14. // There are three implementations of ChaCha20Poly1305:
  15. // 1) 128-bit with AVX hardware acceleration used on x64
  16. // 2) 256-bit with AVX2 hardware acceleration used on x64
  17. // 3) 32-bit used on all other platforms
  18. // On x64 when AVX2 and other necessary registers are available,
  19. // the 256bit-verctorized version will be used. When AVX2 features
  20. // are unavailable or disabled but AVX registers are available, the
  21. // 128bit-vectorized version will be used. In all other cases the
  22. // scalar version of the HACL* code will be used.
  23. // Instead of including the headers (they bring other things we don't want),
  24. // we declare the functions here.
  25. // Usage is guarded by runtime checks of required hardware features.
  26. // Forward declaration from Hacl_Chacha20_Vec128.h and Hacl_Chacha20Poly1305_128.h.
  27. extern void Hacl_Chacha20_Vec128_chacha20_encrypt_128(uint32_t len, uint8_t *out,
  28. uint8_t *text, uint8_t *key,
  29. uint8_t *n1, uint32_t ctr);
  30. extern void
  31. Hacl_Chacha20Poly1305_128_aead_encrypt(uint8_t *k, uint8_t *n1, uint32_t aadlen,
  32. uint8_t *aad, uint32_t mlen, uint8_t *m,
  33. uint8_t *cipher, uint8_t *mac);
  34. extern uint32_t
  35. Hacl_Chacha20Poly1305_128_aead_decrypt(uint8_t *k, uint8_t *n1, uint32_t aadlen,
  36. uint8_t *aad, uint32_t mlen, uint8_t *m,
  37. uint8_t *cipher, uint8_t *mac);
  38. // Forward declaration from Hacl_Chacha20_Vec256.h and Hacl_Chacha20Poly1305_256.h.
  39. extern void Hacl_Chacha20_Vec256_chacha20_encrypt_256(uint32_t len, uint8_t *out,
  40. uint8_t *text, uint8_t *key,
  41. uint8_t *n1, uint32_t ctr);
  42. extern void
  43. Hacl_Chacha20Poly1305_256_aead_encrypt(uint8_t *k, uint8_t *n1, uint32_t aadlen,
  44. uint8_t *aad, uint32_t mlen, uint8_t *m,
  45. uint8_t *cipher, uint8_t *mac);
  46. extern uint32_t
  47. Hacl_Chacha20Poly1305_256_aead_decrypt(uint8_t *k, uint8_t *n1, uint32_t aadlen,
  48. uint8_t *aad, uint32_t mlen, uint8_t *m,
  49. uint8_t *cipher, uint8_t *mac);
  50. // Forward declaration from Hacl_Chacha20.h and Hacl_Chacha20Poly1305_32.h.
  51. extern void Hacl_Chacha20_chacha20_encrypt(uint32_t len, uint8_t *out,
  52. uint8_t *text, uint8_t *key,
  53. uint8_t *n1, uint32_t ctr);
  54. extern void
  55. Hacl_Chacha20Poly1305_32_aead_encrypt(uint8_t *k, uint8_t *n1, uint32_t aadlen,
  56. uint8_t *aad, uint32_t mlen, uint8_t *m,
  57. uint8_t *cipher, uint8_t *mac);
  58. extern uint32_t
  59. Hacl_Chacha20Poly1305_32_aead_decrypt(uint8_t *k, uint8_t *n1, uint32_t aadlen,
  60. uint8_t *aad, uint32_t mlen, uint8_t *m,
  61. uint8_t *cipher, uint8_t *mac);
  62. SECStatus
  63. ChaCha20Poly1305_InitContext(ChaCha20Poly1305Context *ctx,
  64. const unsigned char *key, unsigned int keyLen,
  65. unsigned int tagLen)
  66. {
  67. #ifdef NSS_DISABLE_CHACHAPOLY
  68. return SECFailure;
  69. #else
  70. if (keyLen != 32) {
  71. PORT_SetError(SEC_ERROR_BAD_KEY);
  72. return SECFailure;
  73. }
  74. if (tagLen == 0 || tagLen > 16) {
  75. PORT_SetError(SEC_ERROR_INPUT_LEN);
  76. return SECFailure;
  77. }
  78. PORT_Memcpy(ctx->key, key, sizeof(ctx->key));
  79. ctx->tagLen = tagLen;
  80. return SECSuccess;
  81. #endif
  82. }
  83. ChaCha20Poly1305Context *
  84. ChaCha20Poly1305_CreateContext(const unsigned char *key, unsigned int keyLen,
  85. unsigned int tagLen)
  86. {
  87. #ifdef NSS_DISABLE_CHACHAPOLY
  88. return NULL;
  89. #else
  90. ChaCha20Poly1305Context *ctx;
  91. ctx = PORT_New(ChaCha20Poly1305Context);
  92. if (ctx == NULL) {
  93. return NULL;
  94. }
  95. if (ChaCha20Poly1305_InitContext(ctx, key, keyLen, tagLen) != SECSuccess) {
  96. PORT_Free(ctx);
  97. ctx = NULL;
  98. }
  99. return ctx;
  100. #endif
  101. }
  102. void
  103. ChaCha20Poly1305_DestroyContext(ChaCha20Poly1305Context *ctx, PRBool freeit)
  104. {
  105. #ifndef NSS_DISABLE_CHACHAPOLY
  106. PORT_Memset(ctx, 0, sizeof(*ctx));
  107. if (freeit) {
  108. PORT_Free(ctx);
  109. }
  110. #endif
  111. }
  112. #ifndef NSS_DISABLE_CHACHAPOLY
  113. void
  114. ChaCha20Xor(uint8_t *output, uint8_t *block, uint32_t len, uint8_t *k,
  115. uint8_t *nonce, uint32_t ctr)
  116. {
  117. #ifdef NSS_X64
  118. if (ssse3_support() && sse4_1_support() && avx_support()) {
  119. #ifdef NSS_DISABLE_AVX2
  120. Hacl_Chacha20_Vec128_chacha20_encrypt_128(len, output, block, k, nonce, ctr);
  121. #else
  122. if (avx2_support()) {
  123. Hacl_Chacha20_Vec256_chacha20_encrypt_256(len, output, block, k, nonce, ctr);
  124. } else {
  125. Hacl_Chacha20_Vec128_chacha20_encrypt_128(len, output, block, k, nonce, ctr);
  126. }
  127. #endif
  128. } else
  129. #endif
  130. {
  131. Hacl_Chacha20_chacha20_encrypt(len, output, block, k, nonce, ctr);
  132. }
  133. }
  134. #endif /* NSS_DISABLE_CHACHAPOLY */
  135. SECStatus
  136. ChaCha20_Xor(unsigned char *output, const unsigned char *block, unsigned int len,
  137. const unsigned char *k, const unsigned char *nonce, PRUint32 ctr)
  138. {
  139. #ifdef NSS_DISABLE_CHACHAPOLY
  140. return SECFailure;
  141. #else
  142. // ChaCha has a 64 octet block, with a 32-bit block counter.
  143. if (sizeof(len) > 4 && len >= (1ULL << (6 + 32))) {
  144. PORT_SetError(SEC_ERROR_INPUT_LEN);
  145. return SECFailure;
  146. }
  147. ChaCha20Xor(output, (uint8_t *)block, len, (uint8_t *)k,
  148. (uint8_t *)nonce, ctr);
  149. return SECSuccess;
  150. #endif
  151. }
  152. SECStatus
  153. ChaCha20Poly1305_Seal(const ChaCha20Poly1305Context *ctx, unsigned char *output,
  154. unsigned int *outputLen, unsigned int maxOutputLen,
  155. const unsigned char *input, unsigned int inputLen,
  156. const unsigned char *nonce, unsigned int nonceLen,
  157. const unsigned char *ad, unsigned int adLen)
  158. {
  159. #ifdef NSS_DISABLE_CHACHAPOLY
  160. return SECFailure;
  161. #else
  162. if (nonceLen != 12) {
  163. PORT_SetError(SEC_ERROR_INPUT_LEN);
  164. return SECFailure;
  165. }
  166. // ChaCha has a 64 octet block, with a 32-bit block counter.
  167. if (sizeof(inputLen) > 4 && inputLen >= (1ULL << (6 + 32))) {
  168. PORT_SetError(SEC_ERROR_INPUT_LEN);
  169. return SECFailure;
  170. }
  171. if (maxOutputLen < inputLen + ctx->tagLen) {
  172. PORT_SetError(SEC_ERROR_OUTPUT_LEN);
  173. return SECFailure;
  174. }
  175. #ifdef NSS_X64
  176. if (ssse3_support() && sse4_1_support() && avx_support()) {
  177. #ifdef NSS_DISABLE_AVX2
  178. Hacl_Chacha20Poly1305_128_aead_encrypt(
  179. (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, inputLen,
  180. (uint8_t *)input, output, output + inputLen);
  181. #else
  182. if (avx2_support()) {
  183. Hacl_Chacha20Poly1305_256_aead_encrypt(
  184. (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, inputLen,
  185. (uint8_t *)input, output, output + inputLen);
  186. } else {
  187. Hacl_Chacha20Poly1305_128_aead_encrypt(
  188. (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, inputLen,
  189. (uint8_t *)input, output, output + inputLen);
  190. }
  191. #endif
  192. } else
  193. #endif
  194. {
  195. Hacl_Chacha20Poly1305_32_aead_encrypt(
  196. (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, inputLen,
  197. (uint8_t *)input, output, output + inputLen);
  198. }
  199. *outputLen = inputLen + ctx->tagLen;
  200. return SECSuccess;
  201. #endif
  202. }
  203. SECStatus
  204. ChaCha20Poly1305_Open(const ChaCha20Poly1305Context *ctx, unsigned char *output,
  205. unsigned int *outputLen, unsigned int maxOutputLen,
  206. const unsigned char *input, unsigned int inputLen,
  207. const unsigned char *nonce, unsigned int nonceLen,
  208. const unsigned char *ad, unsigned int adLen)
  209. {
  210. #ifdef NSS_DISABLE_CHACHAPOLY
  211. return SECFailure;
  212. #else
  213. unsigned int ciphertextLen;
  214. if (nonceLen != 12) {
  215. PORT_SetError(SEC_ERROR_INPUT_LEN);
  216. return SECFailure;
  217. }
  218. if (inputLen < ctx->tagLen) {
  219. PORT_SetError(SEC_ERROR_INPUT_LEN);
  220. return SECFailure;
  221. }
  222. ciphertextLen = inputLen - ctx->tagLen;
  223. if (maxOutputLen < ciphertextLen) {
  224. PORT_SetError(SEC_ERROR_OUTPUT_LEN);
  225. return SECFailure;
  226. }
  227. // ChaCha has a 64 octet block, with a 32-bit block counter.
  228. if (inputLen >= (1ULL << (6 + 32)) + ctx->tagLen) {
  229. PORT_SetError(SEC_ERROR_INPUT_LEN);
  230. return SECFailure;
  231. }
  232. uint32_t res = 1;
  233. #ifdef NSS_X64
  234. if (ssse3_support() && sse4_1_support() && avx_support()) {
  235. #ifdef NSS_DISABLE_AVX2
  236. res = Hacl_Chacha20Poly1305_128_aead_decrypt(
  237. (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, ciphertextLen,
  238. (uint8_t *)output, (uint8_t *)input, (uint8_t *)input + ciphertextLen);
  239. #else
  240. if (avx2_support()) {
  241. res = Hacl_Chacha20Poly1305_256_aead_decrypt(
  242. (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, ciphertextLen,
  243. (uint8_t *)output, (uint8_t *)input, (uint8_t *)input + ciphertextLen);
  244. } else {
  245. res = Hacl_Chacha20Poly1305_128_aead_decrypt(
  246. (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, ciphertextLen,
  247. (uint8_t *)output, (uint8_t *)input, (uint8_t *)input + ciphertextLen);
  248. }
  249. #endif
  250. } else
  251. #endif
  252. {
  253. res = Hacl_Chacha20Poly1305_32_aead_decrypt(
  254. (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, ciphertextLen,
  255. (uint8_t *)output, (uint8_t *)input, (uint8_t *)input + ciphertextLen);
  256. }
  257. if (res) {
  258. PORT_SetError(SEC_ERROR_BAD_DATA);
  259. return SECFailure;
  260. }
  261. *outputLen = ciphertextLen;
  262. return SECSuccess;
  263. #endif
  264. }
  265. SECStatus
  266. ChaCha20Poly1305_Encrypt(const ChaCha20Poly1305Context *ctx,
  267. unsigned char *output, unsigned int *outputLen,
  268. unsigned int maxOutputLen, const unsigned char *input,
  269. unsigned int inputLen, const unsigned char *nonce,
  270. unsigned int nonceLen, const unsigned char *ad,
  271. unsigned int adLen, unsigned char *outTag)
  272. {
  273. #ifdef NSS_DISABLE_CHACHAPOLY
  274. return SECFailure;
  275. #else
  276. if (nonceLen != 12) {
  277. PORT_SetError(SEC_ERROR_INPUT_LEN);
  278. return SECFailure;
  279. }
  280. // ChaCha has a 64 octet block, with a 32-bit block counter.
  281. if (sizeof(inputLen) > 4 && inputLen >= (1ULL << (6 + 32))) {
  282. PORT_SetError(SEC_ERROR_INPUT_LEN);
  283. return SECFailure;
  284. }
  285. if (maxOutputLen < inputLen) {
  286. PORT_SetError(SEC_ERROR_OUTPUT_LEN);
  287. return SECFailure;
  288. }
  289. #ifdef NSS_X64
  290. if (ssse3_support() && sse4_1_support() && avx_support()) {
  291. Hacl_Chacha20Poly1305_128_aead_encrypt(
  292. (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, inputLen,
  293. (uint8_t *)input, output, outTag);
  294. } else
  295. #endif
  296. {
  297. Hacl_Chacha20Poly1305_32_aead_encrypt(
  298. (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, inputLen,
  299. (uint8_t *)input, output, outTag);
  300. }
  301. *outputLen = inputLen;
  302. return SECSuccess;
  303. #endif
  304. }
  305. SECStatus
  306. ChaCha20Poly1305_Decrypt(const ChaCha20Poly1305Context *ctx,
  307. unsigned char *output, unsigned int *outputLen,
  308. unsigned int maxOutputLen, const unsigned char *input,
  309. unsigned int inputLen, const unsigned char *nonce,
  310. unsigned int nonceLen, const unsigned char *ad,
  311. unsigned int adLen, const unsigned char *tagIn)
  312. {
  313. #ifdef NSS_DISABLE_CHACHAPOLY
  314. return SECFailure;
  315. #else
  316. unsigned int ciphertextLen;
  317. if (nonceLen != 12) {
  318. PORT_SetError(SEC_ERROR_INPUT_LEN);
  319. return SECFailure;
  320. }
  321. ciphertextLen = inputLen;
  322. if (maxOutputLen < ciphertextLen) {
  323. PORT_SetError(SEC_ERROR_OUTPUT_LEN);
  324. return SECFailure;
  325. }
  326. // ChaCha has a 64 octet block, with a 32-bit block counter.
  327. if (sizeof(inputLen) > 4 && inputLen >= (1ULL << (6 + 32))) {
  328. PORT_SetError(SEC_ERROR_INPUT_LEN);
  329. return SECFailure;
  330. }
  331. uint32_t res = 1;
  332. #ifdef NSS_X64
  333. if (ssse3_support() && sse4_1_support() && avx_support()) {
  334. res = Hacl_Chacha20Poly1305_128_aead_decrypt(
  335. (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, ciphertextLen,
  336. (uint8_t *)output, (uint8_t *)input, (uint8_t *)tagIn);
  337. } else
  338. #endif
  339. {
  340. res = Hacl_Chacha20Poly1305_32_aead_decrypt(
  341. (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, ciphertextLen,
  342. (uint8_t *)output, (uint8_t *)input, (uint8_t *)tagIn);
  343. }
  344. if (res) {
  345. PORT_SetError(SEC_ERROR_BAD_DATA);
  346. return SECFailure;
  347. }
  348. *outputLen = ciphertextLen;
  349. return SECSuccess;
  350. #endif
  351. }