rfc7539.c 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
  1. // Implementation of the ChaCha20 + Poly1305 AEAD construction
  2. // as described in RFC 7539.
  3. #include <string.h>
  4. #include "rfc7539.h"
  5. #include "ecrypt_portable.h"
  6. // Initialize the ChaCha20 + Poly1305 context for encryption or decryption
  7. // using a 32 byte key and 12 byte nonce as in the RFC 7539 style.
  8. void rfc7539_init(chacha20poly1305_ctx* ctx, const uint8_t key[32], const uint8_t nonce[12]) {
  9. unsigned char block0[64] = {0};
  10. ECRYPT_keysetup(&ctx->chacha20, key, 256, 16);
  11. ctx->chacha20.input[12] = 0;
  12. ctx->chacha20.input[13] = U8TO32_LITTLE(nonce + 0);
  13. ctx->chacha20.input[14] = U8TO32_LITTLE(nonce + 4);
  14. ctx->chacha20.input[15] = U8TO32_LITTLE(nonce + 8);
  15. // Encrypt 64 bytes of zeros and use the first 32 bytes
  16. // as the Poly1305 key.
  17. ECRYPT_encrypt_bytes(&ctx->chacha20, block0, block0, 64);
  18. poly1305_init(&ctx->poly1305, block0);
  19. }
  20. // Include authenticated data in the Poly1305 MAC using the RFC 7539
  21. // style with 16 byte padding. This must only be called once and prior
  22. // to encryption or decryption.
  23. void rfc7539_auth(chacha20poly1305_ctx* ctx, const uint8_t* in, size_t n) {
  24. uint8_t padding[16] = {0};
  25. poly1305_update(&ctx->poly1305, in, n);
  26. if(n % 16 != 0) poly1305_update(&ctx->poly1305, padding, 16 - n % 16);
  27. }
  28. // Compute RFC 7539-style Poly1305 MAC.
  29. void rfc7539_finish(chacha20poly1305_ctx* ctx, int64_t alen, int64_t plen, uint8_t mac[16]) {
  30. uint8_t padding[16] = {0};
  31. uint8_t lengths[16] = {0};
  32. memcpy(lengths, &alen, sizeof(int64_t));
  33. memcpy(lengths + 8, &plen, sizeof(int64_t));
  34. if(plen % 16 != 0) poly1305_update(&ctx->poly1305, padding, 16 - plen % 16);
  35. poly1305_update(&ctx->poly1305, lengths, 16);
  36. poly1305_finish(&ctx->poly1305, mac);
  37. }