chacha20poly1305.c (18255B)
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 5 #ifdef FREEBL_NO_DEPEND 6 #include "stubs.h" 7 #endif 8 9 #include <string.h> 10 #include <stdio.h> 11 12 #include "seccomon.h" 13 #include "secerr.h" 14 #include "blapit.h" 15 #include "blapii.h" 16 #include "chacha20poly1305.h" 17 18 // There are three implementations of ChaCha20Poly1305: 19 // 1) 128-bit with AVX hardware acceleration used on x64 20 // 2) 256-bit with AVX2 hardware acceleration used on x64 21 // 3) 32-bit used on all other platforms 22 23 // On x64 when AVX2 and other necessary registers are available, 24 // the 256bit-verctorized version will be used. When AVX2 features 25 // are unavailable or disabled but AVX registers are available, the 26 // 128bit-vectorized version will be used. In all other cases the 27 // scalar version of the HACL* code will be used. 28 29 // Instead of including the headers (they bring other things we don't want), 30 // we declare the functions here. 31 // Usage is guarded by runtime checks of required hardware features. 32 33 // Forward declaration from Hacl_Chacha20_Vec128.h and Hacl_Chacha20Poly1305_128.h. 34 extern void Hacl_Chacha20_Vec128_chacha20_encrypt_128(uint32_t len, uint8_t *out, 35 uint8_t *text, uint8_t *key, 36 uint8_t *n1, uint32_t ctr); 37 extern void 38 Hacl_Chacha20Poly1305_128_aead_encrypt(uint8_t *k, uint8_t *n1, uint32_t aadlen, 39 uint8_t *aad, uint32_t mlen, uint8_t *m, 40 uint8_t *cipher, uint8_t *mac); 41 extern uint32_t 42 Hacl_Chacha20Poly1305_128_aead_decrypt(uint8_t *k, uint8_t *n1, uint32_t aadlen, 43 uint8_t *aad, uint32_t mlen, uint8_t *m, 44 uint8_t *cipher, uint8_t *mac); 45 46 // Forward declaration from Hacl_Chacha20_Vec256.h and Hacl_Chacha20Poly1305_256.h. 47 extern void Hacl_Chacha20_Vec256_chacha20_encrypt_256(uint32_t len, uint8_t *out, 48 uint8_t *text, uint8_t *key, 49 uint8_t *n1, uint32_t ctr); 50 extern void 51 Hacl_Chacha20Poly1305_256_aead_encrypt(uint8_t *k, uint8_t *n1, uint32_t aadlen, 52 uint8_t *aad, uint32_t mlen, uint8_t *m, 53 uint8_t *cipher, uint8_t *mac); 54 extern uint32_t 55 Hacl_Chacha20Poly1305_256_aead_decrypt(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 59 // Forward declaration from Hacl_Chacha20.h and Hacl_Chacha20Poly1305_32.h. 60 extern void Hacl_Chacha20_chacha20_encrypt(uint32_t len, uint8_t *out, 61 uint8_t *text, uint8_t *key, 62 uint8_t *n1, uint32_t ctr); 63 extern void 64 Hacl_Chacha20Poly1305_32_aead_encrypt(uint8_t *k, uint8_t *n1, uint32_t aadlen, 65 uint8_t *aad, uint32_t mlen, uint8_t *m, 66 uint8_t *cipher, uint8_t *mac); 67 extern uint32_t 68 Hacl_Chacha20Poly1305_32_aead_decrypt(uint8_t *k, uint8_t *n1, uint32_t aadlen, 69 uint8_t *aad, uint32_t mlen, uint8_t *m, 70 uint8_t *cipher, uint8_t *mac); 71 72 // Forward declaration from chacha20-ppc64le.S 73 void chacha20vsx(uint32_t len, uint8_t *output, uint8_t *block, uint8_t *k, 74 uint8_t *nonce, uint32_t ctr); 75 76 // Forward declaration from chacha20poly1305-ppc.c 77 extern void 78 Chacha20Poly1305_vsx_aead_encrypt(uint8_t *k, uint8_t *n1, uint32_t aadlen, 79 uint8_t *aad, uint32_t mlen, uint8_t *m, 80 uint8_t *cipher, uint8_t *mac); 81 extern uint32_t 82 Chacha20Poly1305_vsx_aead_decrypt(uint8_t *k, uint8_t *n1, uint32_t aadlen, 83 uint8_t *aad, uint32_t mlen, uint8_t *m, 84 uint8_t *cipher, uint8_t *mac); 85 86 SECStatus 87 ChaCha20_InitContext(ChaCha20Context *ctx, const unsigned char *key, 88 unsigned int keyLen, const unsigned char *nonce, 89 unsigned int nonceLen, PRUint32 ctr) 90 { 91 #ifdef NSS_DISABLE_CHACHAPOLY 92 return SECFailure; 93 #else 94 if (keyLen != 32) { 95 PORT_SetError(SEC_ERROR_BAD_KEY); 96 return SECFailure; 97 } 98 if (nonceLen != 12) { 99 PORT_SetError(SEC_ERROR_INVALID_ARGS); 100 return SECFailure; 101 } 102 103 ctx->counter = ctr; 104 PORT_Memcpy(ctx->key, key, sizeof(ctx->key)); 105 PORT_Memcpy(ctx->nonce, nonce, sizeof(ctx->nonce)); 106 107 NSS_CLASSIFY(ctx->nonce, sizeof(ctx->nonce)); 108 NSS_CLASSIFY(ctx->key, sizeof(ctx->key)); 109 110 return SECSuccess; 111 #endif 112 } 113 114 ChaCha20Context * 115 ChaCha20_CreateContext(const unsigned char *key, unsigned int keyLen, 116 const unsigned char *nonce, unsigned int nonceLen, 117 PRUint32 ctr) 118 { 119 #ifdef NSS_DISABLE_CHACHAPOLY 120 return NULL; 121 #else 122 ChaCha20Context *ctx; 123 124 ctx = PORT_New(ChaCha20Context); 125 if (ctx == NULL) { 126 return NULL; 127 } 128 129 if (ChaCha20_InitContext(ctx, key, keyLen, nonce, nonceLen, ctr) != SECSuccess) { 130 PORT_Free(ctx); 131 ctx = NULL; 132 } 133 134 return ctx; 135 #endif 136 } 137 138 void 139 ChaCha20_DestroyContext(ChaCha20Context *ctx, PRBool freeit) 140 { 141 #ifndef NSS_DISABLE_CHACHAPOLY 142 PORT_Memset(ctx, 0, sizeof(*ctx)); 143 if (freeit) { 144 PORT_Free(ctx); 145 } 146 #endif 147 } 148 149 SECStatus 150 ChaCha20Poly1305_InitContext(ChaCha20Poly1305Context *ctx, 151 const unsigned char *key, unsigned int keyLen, 152 unsigned int tagLen) 153 { 154 #ifdef NSS_DISABLE_CHACHAPOLY 155 return SECFailure; 156 #else 157 if (keyLen != 32) { 158 PORT_SetError(SEC_ERROR_BAD_KEY); 159 return SECFailure; 160 } 161 if (tagLen != 16) { 162 PORT_SetError(SEC_ERROR_INPUT_LEN); 163 return SECFailure; 164 } 165 166 PORT_Memcpy(ctx->key, key, sizeof(ctx->key)); 167 ctx->tagLen = tagLen; 168 169 NSS_CLASSIFY(ctx->key, sizeof(ctx->key)); 170 171 return SECSuccess; 172 #endif 173 } 174 175 ChaCha20Poly1305Context * 176 ChaCha20Poly1305_CreateContext(const unsigned char *key, unsigned int keyLen, 177 unsigned int tagLen) 178 { 179 #ifdef NSS_DISABLE_CHACHAPOLY 180 return NULL; 181 #else 182 ChaCha20Poly1305Context *ctx; 183 184 ctx = PORT_New(ChaCha20Poly1305Context); 185 if (ctx == NULL) { 186 return NULL; 187 } 188 189 if (ChaCha20Poly1305_InitContext(ctx, key, keyLen, tagLen) != SECSuccess) { 190 PORT_Free(ctx); 191 ctx = NULL; 192 } 193 194 return ctx; 195 #endif 196 } 197 198 void 199 ChaCha20Poly1305_DestroyContext(ChaCha20Poly1305Context *ctx, PRBool freeit) 200 { 201 #ifndef NSS_DISABLE_CHACHAPOLY 202 PORT_Memset(ctx, 0, sizeof(*ctx)); 203 if (freeit) { 204 PORT_Free(ctx); 205 } 206 #endif 207 } 208 209 #ifndef NSS_DISABLE_CHACHAPOLY 210 void 211 ChaCha20Xor(uint8_t *output, uint8_t *block, uint32_t len, uint8_t *k, 212 uint8_t *nonce, uint32_t ctr) 213 { 214 #ifdef NSS_X64 215 #ifndef NSS_DISABLE_AVX2 216 if (avx2_support()) { 217 Hacl_Chacha20_Vec256_chacha20_encrypt_256(len, output, block, k, nonce, ctr); 218 return; 219 } 220 #endif 221 222 #ifndef NSS_DISABLE_SSE3 223 if (ssse3_support() && sse4_1_support() && avx_support()) { 224 Hacl_Chacha20_Vec128_chacha20_encrypt_128(len, output, block, k, nonce, ctr); 225 return; 226 } 227 #endif 228 229 #elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__) && \ 230 !defined(NSS_DISABLE_ALTIVEC) && !defined(NSS_DISABLE_CRYPTO_VSX) 231 if (ppc_crypto_support()) { 232 chacha20vsx(len, output, block, k, nonce, ctr); 233 return; 234 } 235 #endif 236 { 237 Hacl_Chacha20_chacha20_encrypt(len, output, block, k, nonce, ctr); 238 return; 239 } 240 } 241 #endif /* NSS_DISABLE_CHACHAPOLY */ 242 243 SECStatus 244 ChaCha20_Xor(unsigned char *output, const unsigned char *block, unsigned int len, 245 const unsigned char *k, const unsigned char *nonce, PRUint32 ctr) 246 { 247 #ifdef NSS_DISABLE_CHACHAPOLY 248 return SECFailure; 249 #else 250 // ChaCha has a 64 octet block, with a 32-bit block counter. 251 if (sizeof(len) > 4) { 252 unsigned long long len_ull = len; 253 if (len_ull >= (1ULL << (6 + 32))) { 254 PORT_SetError(SEC_ERROR_INPUT_LEN); 255 return SECFailure; 256 } 257 } 258 ChaCha20Xor(output, (uint8_t *)block, len, (uint8_t *)k, 259 (uint8_t *)nonce, ctr); 260 return SECSuccess; 261 #endif 262 } 263 264 SECStatus 265 ChaCha20Poly1305_Seal(const ChaCha20Poly1305Context *ctx, unsigned char *output, 266 unsigned int *outputLen, unsigned int maxOutputLen, 267 const unsigned char *input, unsigned int inputLen, 268 const unsigned char *nonce, unsigned int nonceLen, 269 const unsigned char *ad, unsigned int adLen) 270 { 271 #ifdef NSS_DISABLE_CHACHAPOLY 272 return SECFailure; 273 #else 274 275 if (nonceLen != 12) { 276 PORT_SetError(SEC_ERROR_INPUT_LEN); 277 return SECFailure; 278 } 279 // ChaCha has a 64 octet block, with a 32-bit block counter. 280 if (sizeof(inputLen) > 4) { 281 unsigned long long inputLen_ull = inputLen; 282 if (inputLen_ull >= (1ULL << (6 + 32))) { 283 PORT_SetError(SEC_ERROR_INPUT_LEN); 284 return SECFailure; 285 } 286 } 287 if (maxOutputLen < inputLen + ctx->tagLen) { 288 PORT_SetError(SEC_ERROR_OUTPUT_LEN); 289 return SECFailure; 290 } 291 292 #ifdef NSS_X64 293 #ifndef NSS_DISABLE_AVX2 294 if (avx2_support()) { 295 Hacl_Chacha20Poly1305_256_aead_encrypt( 296 (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, inputLen, 297 (uint8_t *)input, output, output + inputLen); 298 goto finish; 299 } 300 #endif 301 302 #ifndef NSS_DISABLE_SSE3 303 if (ssse3_support() && sse4_1_support() && avx_support()) { 304 Hacl_Chacha20Poly1305_128_aead_encrypt( 305 (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, inputLen, 306 (uint8_t *)input, output, output + inputLen); 307 goto finish; 308 } 309 #endif 310 311 #elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__) && \ 312 !defined(NSS_DISABLE_ALTIVEC) && !defined(NSS_DISABLE_CRYPTO_VSX) 313 if (ppc_crypto_support()) { 314 Chacha20Poly1305_vsx_aead_encrypt( 315 (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, inputLen, 316 (uint8_t *)input, output, output + inputLen); 317 goto finish; 318 } 319 #endif 320 { 321 Hacl_Chacha20Poly1305_32_aead_encrypt( 322 (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, inputLen, 323 (uint8_t *)input, output, output + inputLen); 324 goto finish; 325 } 326 327 finish: 328 *outputLen = inputLen + ctx->tagLen; 329 return SECSuccess; 330 #endif 331 } 332 333 SECStatus 334 ChaCha20Poly1305_Open(const ChaCha20Poly1305Context *ctx, unsigned char *output, 335 unsigned int *outputLen, unsigned int maxOutputLen, 336 const unsigned char *input, unsigned int inputLen, 337 const unsigned char *nonce, unsigned int nonceLen, 338 const unsigned char *ad, unsigned int adLen) 339 { 340 #ifdef NSS_DISABLE_CHACHAPOLY 341 return SECFailure; 342 #else 343 unsigned int ciphertextLen; 344 345 if (nonceLen != 12) { 346 PORT_SetError(SEC_ERROR_INPUT_LEN); 347 return SECFailure; 348 } 349 if (inputLen < ctx->tagLen) { 350 PORT_SetError(SEC_ERROR_INPUT_LEN); 351 return SECFailure; 352 } 353 ciphertextLen = inputLen - ctx->tagLen; 354 if (maxOutputLen < ciphertextLen) { 355 PORT_SetError(SEC_ERROR_OUTPUT_LEN); 356 return SECFailure; 357 } 358 // ChaCha has a 64 octet block, with a 32-bit block counter. 359 if (inputLen >= (1ULL << (6 + 32)) + ctx->tagLen) { 360 PORT_SetError(SEC_ERROR_INPUT_LEN); 361 return SECFailure; 362 } 363 364 uint32_t res = 1; 365 #ifdef NSS_X64 366 #ifndef NSS_DISABLE_AVX2 367 if (avx2_support()) { 368 res = Hacl_Chacha20Poly1305_256_aead_decrypt( 369 (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, ciphertextLen, 370 (uint8_t *)output, (uint8_t *)input, (uint8_t *)input + ciphertextLen); 371 goto finish; 372 } 373 #endif 374 375 #ifndef NSS_DISABLE_SSE3 376 if (ssse3_support() && sse4_1_support() && avx_support()) { 377 res = Hacl_Chacha20Poly1305_128_aead_decrypt( 378 (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, ciphertextLen, 379 (uint8_t *)output, (uint8_t *)input, (uint8_t *)input + ciphertextLen); 380 goto finish; 381 } 382 #endif 383 384 #elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__) && \ 385 !defined(NSS_DISABLE_ALTIVEC) && !defined(NSS_DISABLE_CRYPTO_VSX) 386 if (ppc_crypto_support()) { 387 res = Chacha20Poly1305_vsx_aead_decrypt( 388 (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, ciphertextLen, 389 (uint8_t *)output, (uint8_t *)input, (uint8_t *)input + ciphertextLen); 390 goto finish; 391 } 392 #endif 393 { 394 res = Hacl_Chacha20Poly1305_32_aead_decrypt( 395 (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, ciphertextLen, 396 (uint8_t *)output, (uint8_t *)input, (uint8_t *)input + ciphertextLen); 397 goto finish; 398 } 399 400 finish: 401 if (res) { 402 PORT_SetError(SEC_ERROR_BAD_DATA); 403 return SECFailure; 404 } 405 406 *outputLen = ciphertextLen; 407 return SECSuccess; 408 #endif 409 } 410 411 SECStatus 412 ChaCha20Poly1305_Encrypt(const ChaCha20Poly1305Context *ctx, 413 unsigned char *output, unsigned int *outputLen, 414 unsigned int maxOutputLen, const unsigned char *input, 415 unsigned int inputLen, const unsigned char *nonce, 416 unsigned int nonceLen, const unsigned char *ad, 417 unsigned int adLen, unsigned char *outTag) 418 { 419 #ifdef NSS_DISABLE_CHACHAPOLY 420 return SECFailure; 421 #else 422 423 if (nonceLen != 12) { 424 PORT_SetError(SEC_ERROR_INPUT_LEN); 425 return SECFailure; 426 } 427 // ChaCha has a 64 octet block, with a 32-bit block counter. 428 if (sizeof(inputLen) > 4) { 429 unsigned long long inputLen_ull = inputLen; 430 if (inputLen_ull >= (1ULL << (6 + 32))) { 431 PORT_SetError(SEC_ERROR_INPUT_LEN); 432 return SECFailure; 433 } 434 } 435 if (maxOutputLen < inputLen) { 436 PORT_SetError(SEC_ERROR_OUTPUT_LEN); 437 return SECFailure; 438 } 439 440 #ifdef NSS_X64 441 #ifndef NSS_DISABLE_AVX2 442 if (avx2_support()) { 443 Hacl_Chacha20Poly1305_256_aead_encrypt( 444 (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, inputLen, 445 (uint8_t *)input, output, outTag); 446 goto finish; 447 } 448 #endif 449 450 #ifndef NSS_DISABLE_SSE3 451 if (ssse3_support() && sse4_1_support() && avx_support()) { 452 Hacl_Chacha20Poly1305_128_aead_encrypt( 453 (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, inputLen, 454 (uint8_t *)input, output, outTag); 455 goto finish; 456 } 457 #endif 458 #elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__) && \ 459 !defined(NSS_DISABLE_ALTIVEC) && !defined(NSS_DISABLE_CRYPTO_VSX) 460 if (ppc_crypto_support()) { 461 Chacha20Poly1305_vsx_aead_encrypt( 462 (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, inputLen, 463 (uint8_t *)input, output, outTag); 464 goto finish; 465 } 466 #endif 467 { 468 Hacl_Chacha20Poly1305_32_aead_encrypt( 469 (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, inputLen, 470 (uint8_t *)input, output, outTag); 471 goto finish; 472 } 473 474 finish: 475 *outputLen = inputLen; 476 return SECSuccess; 477 #endif 478 } 479 480 SECStatus 481 ChaCha20Poly1305_Decrypt(const ChaCha20Poly1305Context *ctx, 482 unsigned char *output, unsigned int *outputLen, 483 unsigned int maxOutputLen, const unsigned char *input, 484 unsigned int inputLen, const unsigned char *nonce, 485 unsigned int nonceLen, const unsigned char *ad, 486 unsigned int adLen, /* const */ unsigned char *tagIn) 487 { 488 #ifdef NSS_DISABLE_CHACHAPOLY 489 return SECFailure; 490 #else 491 unsigned int ciphertextLen; 492 493 if (nonceLen != 12) { 494 PORT_SetError(SEC_ERROR_INPUT_LEN); 495 return SECFailure; 496 } 497 ciphertextLen = inputLen; 498 if (maxOutputLen < ciphertextLen) { 499 PORT_SetError(SEC_ERROR_OUTPUT_LEN); 500 return SECFailure; 501 } 502 // ChaCha has a 64 octet block, with a 32-bit block counter. 503 if (sizeof(inputLen) > 4) { 504 unsigned long long inputLen_ull = inputLen; 505 if (inputLen_ull >= (1ULL << (6 + 32))) { 506 PORT_SetError(SEC_ERROR_INPUT_LEN); 507 return SECFailure; 508 } 509 } 510 511 uint32_t res = 1; 512 #ifdef NSS_X64 513 #ifndef NSS_DISABLE_AVX2 514 if (avx2_support()) { 515 res = Hacl_Chacha20Poly1305_256_aead_decrypt( 516 (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, ciphertextLen, 517 (uint8_t *)output, (uint8_t *)input, (uint8_t *)tagIn); 518 goto finish; 519 } 520 #endif 521 522 #ifndef NSS_DISABLE_SSE3 523 if (ssse3_support() && sse4_1_support() && avx_support()) { 524 res = Hacl_Chacha20Poly1305_128_aead_decrypt( 525 (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, ciphertextLen, 526 (uint8_t *)output, (uint8_t *)input, (uint8_t *)tagIn); 527 goto finish; 528 } 529 #endif 530 531 #elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__) && \ 532 !defined(NSS_DISABLE_ALTIVEC) && !defined(NSS_DISABLE_CRYPTO_VSX) 533 if (ppc_crypto_support()) { 534 res = Chacha20Poly1305_vsx_aead_decrypt( 535 (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, ciphertextLen, 536 (uint8_t *)output, (uint8_t *)input, (uint8_t *)tagIn); 537 goto finish; 538 } 539 #endif 540 { 541 res = Hacl_Chacha20Poly1305_32_aead_decrypt( 542 (uint8_t *)ctx->key, (uint8_t *)nonce, adLen, (uint8_t *)ad, ciphertextLen, 543 (uint8_t *)output, (uint8_t *)input, (uint8_t *)tagIn); 544 goto finish; 545 } 546 547 finish: 548 if (res) { 549 PORT_SetError(SEC_ERROR_BAD_DATA); 550 return SECFailure; 551 } 552 553 *outputLen = ciphertextLen; 554 return SECSuccess; 555 #endif 556 }