ffx.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * Copyright (c) 2016 Christian Huitema <huitema@huitema.net>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #ifdef _WINDOWS
  17. #include "wincompat.h"
  18. #else
  19. #include <unistd.h>
  20. #endif
  21. #include <errno.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include "picotls.h"
  25. #include "picotls/minicrypto.h"
  26. #include "picotls/ffx.h"
  27. static void ffx_dispose(ptls_cipher_context_t *_ctx);
  28. static void ffx_encrypt(ptls_cipher_context_t *_ctx, void *output, const void *input, size_t len);
  29. static void ffx_init(struct st_ptls_cipher_context_t *ctx, const void *iv);
  30. int ptls_ffx_setup_crypto(ptls_cipher_context_t *_ctx, ptls_cipher_algorithm_t *algo, int is_enc, int nb_rounds, size_t bit_length,
  31. const void *key)
  32. {
  33. int ret = 0;
  34. ptls_ffx_context_t *ctx = (ptls_ffx_context_t *)_ctx;
  35. ptls_cipher_context_t *enc_ctx = NULL;
  36. size_t len = (bit_length + 7) / 8;
  37. uint8_t last_byte_mask[8] = {0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80};
  38. assert(len <= 32 && len >= 2);
  39. assert(ctx->super.do_dispose == NULL);
  40. assert(ctx->super.do_init == NULL);
  41. assert(ctx->super.do_transform == NULL);
  42. assert(ctx->super.algo == NULL || algo->key_size == ctx->super.algo->key_size);
  43. assert(ctx->super.algo == NULL || algo->iv_size == ctx->super.algo->iv_size);
  44. assert(ctx->super.algo == NULL || ctx->super.algo->block_size == len);
  45. assert(algo->iv_size == 16);
  46. if (len <= 32 && len >= 2) {
  47. /* len must be lower than 32 */
  48. enc_ctx = ptls_cipher_new(algo, 1, key);
  49. if (enc_ctx == NULL) {
  50. ret = PTLS_ERROR_LIBRARY;
  51. }
  52. } else {
  53. ret = PTLS_ERROR_LIBRARY;
  54. }
  55. if (ret == 0) {
  56. ctx->enc_ctx = enc_ctx;
  57. ctx->nb_rounds = nb_rounds;
  58. ctx->is_enc = is_enc;
  59. ctx->byte_length = len;
  60. ctx->nb_left = (int)len / 2;
  61. ctx->nb_right = (int)len - ctx->nb_left;
  62. ctx->mask_last_byte = last_byte_mask[bit_length % 8];
  63. ptls_clear_memory(ctx->tweaks, sizeof(ctx->tweaks));
  64. ctx->super.do_dispose = ffx_dispose;
  65. ctx->super.do_init = ffx_init;
  66. ctx->super.do_transform = ffx_encrypt;
  67. } else {
  68. ffx_dispose(_ctx);
  69. }
  70. return ret;
  71. }
  72. static void ffx_dispose(ptls_cipher_context_t *_ctx)
  73. {
  74. ptls_ffx_context_t *ctx = (ptls_ffx_context_t *)_ctx;
  75. assert(ctx->super.do_dispose == ffx_dispose);
  76. if (ctx->enc_ctx != NULL) {
  77. ptls_cipher_free(ctx->enc_ctx);
  78. }
  79. ctx->enc_ctx = NULL;
  80. ctx->nb_rounds = 0;
  81. ctx->byte_length = 0;
  82. ctx->nb_left = 0;
  83. ctx->nb_right = 0;
  84. ctx->mask_last_byte = 0;
  85. ctx->is_enc = 0;
  86. ctx->super.do_dispose = NULL;
  87. ctx->super.do_init = NULL;
  88. ctx->super.do_transform = NULL;
  89. }
  90. ptls_cipher_context_t *ptls_ffx_new(ptls_cipher_algorithm_t *algo, int is_enc, int nb_rounds, size_t bit_length, const void *key)
  91. {
  92. ptls_cipher_context_t *ctx = (ptls_cipher_context_t *)malloc(sizeof(ptls_ffx_context_t));
  93. if (ctx != NULL) {
  94. memset(ctx, 0, sizeof(ptls_ffx_context_t));
  95. if (ptls_ffx_setup_crypto(ctx, algo, is_enc, nb_rounds, bit_length, key) != 0) {
  96. free(ctx);
  97. ctx = NULL;
  98. }
  99. }
  100. return ctx;
  101. }
  102. static void ptls_ffx_one_pass(ptls_cipher_context_t *enc_ctx, uint8_t *source, size_t source_size, uint8_t *target,
  103. size_t target_size, uint8_t mask_last_byte, uint8_t *confusion, uint8_t *iv, uint8_t *tweaks,
  104. uint8_t round, uint8_t nb_rounds)
  105. {
  106. static const uint8_t zeros[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  107. memcpy(iv, tweaks, 16);
  108. iv[round & 15] ^= nb_rounds;
  109. for (size_t i = 0; i < source_size; i++) {
  110. iv[i] ^= source[i];
  111. }
  112. ptls_cipher_init(enc_ctx, iv);
  113. ptls_cipher_encrypt(enc_ctx, confusion, zeros, 16);
  114. for (size_t j = 0; j < target_size - 1; j++) {
  115. target[j] ^= confusion[j];
  116. }
  117. target[target_size - 1] ^= (confusion[target_size - 1] & mask_last_byte);
  118. }
  119. static void ffx_encrypt(ptls_cipher_context_t *_ctx, void *output, const void *input, size_t len)
  120. {
  121. ptls_ffx_context_t *ctx = (ptls_ffx_context_t *)_ctx;
  122. uint8_t left[16], right[16], confusion[32], iv[16];
  123. uint8_t last_byte;
  124. assert(ctx->super.do_transform == ffx_encrypt);
  125. /* len must match context definition */
  126. assert(len == ctx->byte_length);
  127. if (len != ctx->byte_length) {
  128. memset(output, 0, len); /* so that we do not leak anything in production mode */
  129. return;
  130. }
  131. /* Split the input in two halves */
  132. memcpy(left, input, ctx->nb_left);
  133. memcpy(right, ((uint8_t *)input) + ctx->nb_left, ctx->nb_right);
  134. memset(left + ctx->nb_left, 0, 16 - ctx->nb_left);
  135. memset(right + ctx->nb_right, 0, 16 - ctx->nb_right);
  136. last_byte = right[ctx->nb_right - 1];
  137. right[ctx->nb_right - 1] &= ctx->mask_last_byte;
  138. if (ctx->is_enc) {
  139. /* Feistel construct, using the specified algorithm as S-Box */
  140. for (int i = 0; i < ctx->nb_rounds; i += 2) {
  141. /* Each pass encrypts a zero field with a cipher using one
  142. * half of the message as IV. This construct lets us use
  143. * either AES or chacha 20 */
  144. ptls_ffx_one_pass(ctx->enc_ctx, right, ctx->nb_right, left, ctx->nb_left, 0xFF, confusion, iv, ctx->tweaks, i,
  145. ctx->nb_rounds);
  146. ptls_ffx_one_pass(ctx->enc_ctx, left, ctx->nb_left, right, ctx->nb_right, ctx->mask_last_byte, confusion, iv,
  147. ctx->tweaks, i + 1, ctx->nb_rounds);
  148. }
  149. } else {
  150. /* Feistel construct, using the specified algorithm as S-Box,
  151. * in the opposite order of the encryption */
  152. for (int i = 0; i < ctx->nb_rounds; i += 2) {
  153. /* Each pass encrypts a zero field with a cipher using one
  154. * half of the message as IV. This construct lets us use
  155. * either AES or chacha 20 */
  156. ptls_ffx_one_pass(ctx->enc_ctx, left, ctx->nb_left, right, ctx->nb_right, ctx->mask_last_byte, confusion, iv,
  157. ctx->tweaks, ctx->nb_rounds - 1 - i, ctx->nb_rounds);
  158. ptls_ffx_one_pass(ctx->enc_ctx, right, ctx->nb_right, left, ctx->nb_left, 0xFF, confusion, iv, ctx->tweaks,
  159. ctx->nb_rounds - 2 - i, ctx->nb_rounds);
  160. }
  161. }
  162. /* After enough passes, we have a very strong length preserving
  163. * encryption, only that many times slower than the underlying
  164. * algorithm. We copy the result to the output */
  165. memcpy(output, left, ctx->nb_left);
  166. right[ctx->nb_right - 1] &= ctx->mask_last_byte;
  167. right[ctx->nb_right - 1] |= (last_byte & ~ctx->mask_last_byte);
  168. memcpy(((uint8_t *)output) + ctx->nb_left, right, ctx->nb_right);
  169. ptls_clear_memory(left, sizeof(left));
  170. ptls_clear_memory(right, sizeof(right));
  171. ptls_clear_memory(confusion, sizeof(confusion));
  172. }
  173. static void ffx_init(struct st_ptls_cipher_context_t *_ctx, const void *iv)
  174. {
  175. ptls_ffx_context_t *ctx = (ptls_ffx_context_t *)_ctx;
  176. assert(ctx->super.do_init == ffx_init);
  177. memcpy(ctx->tweaks, iv, 16);
  178. }