cipher_chacha20_hw.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /*
  2. * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License 2.0 (the "License"). You may not use
  5. * this file except in compliance with the License. You can obtain a copy
  6. * in the file LICENSE in the source distribution or at
  7. * https://www.openssl.org/source/license.html
  8. */
  9. /* chacha20 cipher implementation */
  10. #include "cipher_chacha20.h"
  11. static int chacha20_initkey(PROV_CIPHER_CTX *bctx, const uint8_t *key,
  12. size_t keylen)
  13. {
  14. PROV_CHACHA20_CTX *ctx = (PROV_CHACHA20_CTX *)bctx;
  15. unsigned int i;
  16. if (key != NULL) {
  17. for (i = 0; i < CHACHA_KEY_SIZE; i += 4)
  18. ctx->key.d[i / 4] = CHACHA_U8TOU32(key + i);
  19. }
  20. ctx->partial_len = 0;
  21. return 1;
  22. }
  23. static int chacha20_initiv(PROV_CIPHER_CTX *bctx)
  24. {
  25. PROV_CHACHA20_CTX *ctx = (PROV_CHACHA20_CTX *)bctx;
  26. unsigned int i;
  27. if (bctx->iv_set) {
  28. for (i = 0; i < CHACHA_CTR_SIZE; i += 4)
  29. ctx->counter[i / 4] = CHACHA_U8TOU32(bctx->oiv + i);
  30. }
  31. ctx->partial_len = 0;
  32. return 1;
  33. }
  34. static int chacha20_cipher(PROV_CIPHER_CTX *bctx, unsigned char *out,
  35. const unsigned char *in, size_t inl)
  36. {
  37. PROV_CHACHA20_CTX *ctx = (PROV_CHACHA20_CTX *)bctx;
  38. unsigned int n, rem, ctr32;
  39. n = ctx->partial_len;
  40. if (n > 0) {
  41. while (inl > 0 && n < CHACHA_BLK_SIZE) {
  42. *out++ = *in++ ^ ctx->buf[n++];
  43. inl--;
  44. }
  45. ctx->partial_len = n;
  46. if (inl == 0)
  47. return 1;
  48. if (n == CHACHA_BLK_SIZE) {
  49. ctx->partial_len = 0;
  50. ctx->counter[0]++;
  51. if (ctx->counter[0] == 0)
  52. ctx->counter[1]++;
  53. }
  54. }
  55. rem = (unsigned int)(inl % CHACHA_BLK_SIZE);
  56. inl -= rem;
  57. ctr32 = ctx->counter[0];
  58. while (inl >= CHACHA_BLK_SIZE) {
  59. size_t blocks = inl / CHACHA_BLK_SIZE;
  60. /*
  61. * 1<<28 is just a not-so-small yet not-so-large number...
  62. * Below condition is practically never met, but it has to
  63. * be checked for code correctness.
  64. */
  65. if (sizeof(size_t) > sizeof(unsigned int) && blocks > (1U << 28))
  66. blocks = (1U << 28);
  67. /*
  68. * As ChaCha20_ctr32 operates on 32-bit counter, caller
  69. * has to handle overflow. 'if' below detects the
  70. * overflow, which is then handled by limiting the
  71. * amount of blocks to the exact overflow point...
  72. */
  73. ctr32 += (unsigned int)blocks;
  74. if (ctr32 < blocks) {
  75. blocks -= ctr32;
  76. ctr32 = 0;
  77. }
  78. blocks *= CHACHA_BLK_SIZE;
  79. ChaCha20_ctr32(out, in, blocks, ctx->key.d, ctx->counter);
  80. inl -= blocks;
  81. in += blocks;
  82. out += blocks;
  83. ctx->counter[0] = ctr32;
  84. if (ctr32 == 0) ctx->counter[1]++;
  85. }
  86. if (rem > 0) {
  87. memset(ctx->buf, 0, sizeof(ctx->buf));
  88. ChaCha20_ctr32(ctx->buf, ctx->buf, CHACHA_BLK_SIZE,
  89. ctx->key.d, ctx->counter);
  90. for (n = 0; n < rem; n++)
  91. out[n] = in[n] ^ ctx->buf[n];
  92. ctx->partial_len = rem;
  93. }
  94. return 1;
  95. }
  96. static const PROV_CIPHER_HW_CHACHA20 chacha20_hw = {
  97. { chacha20_initkey, chacha20_cipher },
  98. chacha20_initiv
  99. };
  100. const PROV_CIPHER_HW *ossl_prov_cipher_hw_chacha20(size_t keybits)
  101. {
  102. return (PROV_CIPHER_HW *)&chacha20_hw;
  103. }