blockwise.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. * cifra - embedded cryptography library
  3. * Written in 2014 by Joseph Birr-Pixton <jpixton@gmail.com>
  4. *
  5. * To the extent possible under law, the author(s) have dedicated all
  6. * copyright and related and neighboring rights to this software to the
  7. * public domain worldwide. This software is distributed without any
  8. * warranty.
  9. *
  10. * You should have received a copy of the CC0 Public Domain Dedication
  11. * along with this software. If not, see
  12. * <http://creativecommons.org/publicdomain/zero/1.0/>.
  13. */
  14. #include "blockwise.h"
  15. #include "bitops.h"
  16. #include "tassert.h"
  17. #include <string.h>
  18. #ifndef MIN
  19. #define MIN(a, b) (((a) < (b)) ? (a) : (b))
  20. #endif
  21. void cf_blockwise_accumulate(uint8_t *partial, size_t *npartial, size_t nblock,
  22. const void *inp, size_t nbytes,
  23. cf_blockwise_in_fn process,
  24. void *ctx)
  25. {
  26. cf_blockwise_accumulate_final(partial, npartial, nblock,
  27. inp, nbytes,
  28. process, process, ctx);
  29. }
  30. void cf_blockwise_accumulate_final(uint8_t *partial, size_t *npartial, size_t nblock,
  31. const void *inp, size_t nbytes,
  32. cf_blockwise_in_fn process,
  33. cf_blockwise_in_fn process_final,
  34. void *ctx)
  35. {
  36. const uint8_t *bufin = inp;
  37. assert(partial && *npartial < nblock);
  38. assert(inp || !nbytes);
  39. assert(process && ctx);
  40. /* If we have partial data, copy in to buffer. */
  41. if (*npartial && nbytes)
  42. {
  43. size_t space = nblock - *npartial;
  44. size_t taken = MIN(space, nbytes);
  45. memcpy(partial + *npartial, bufin, taken);
  46. bufin += taken;
  47. nbytes -= taken;
  48. *npartial += taken;
  49. /* If that gives us a full block, process it. */
  50. if (*npartial == nblock)
  51. {
  52. if (nbytes == 0)
  53. process_final(ctx, partial);
  54. else
  55. process(ctx, partial);
  56. *npartial = 0;
  57. }
  58. }
  59. /* now nbytes < nblock or *npartial == 0. */
  60. /* If we have a full block of data, process it directly. */
  61. while (nbytes >= nblock)
  62. {
  63. /* Partial buffer must be empty, or we're ignoring extant data */
  64. assert(*npartial == 0);
  65. if (nbytes == nblock)
  66. process_final(ctx, bufin);
  67. else
  68. process(ctx, bufin);
  69. bufin += nblock;
  70. nbytes -= nblock;
  71. }
  72. /* Finally, if we have remaining data, buffer it. */
  73. while (nbytes)
  74. {
  75. size_t space = nblock - *npartial;
  76. size_t taken = MIN(space, nbytes);
  77. memcpy(partial + *npartial, bufin, taken);
  78. bufin += taken;
  79. nbytes -= taken;
  80. *npartial += taken;
  81. /* If we started with *npartial, we must have copied it
  82. * in first. */
  83. assert(*npartial < nblock);
  84. }
  85. }
  86. void cf_blockwise_xor(uint8_t *partial, size_t *npartial, size_t nblock,
  87. const void *inp, void *outp, size_t nbytes,
  88. cf_blockwise_out_fn process, void *ctx)
  89. {
  90. const uint8_t *inb = inp;
  91. uint8_t *outb = outp;
  92. assert(partial && *npartial < nblock);
  93. assert(inp || !nbytes);
  94. assert(process && ctx);
  95. while (nbytes)
  96. {
  97. /* If we're out of material, and need more, produce a block. */
  98. if (*npartial == 0)
  99. {
  100. process(ctx, partial);
  101. *npartial = nblock;
  102. }
  103. size_t offset = nblock - *npartial;
  104. size_t taken = MIN(*npartial, nbytes);
  105. xor_bb(outb, inb, partial + offset, taken);
  106. *npartial -= taken;
  107. nbytes -= taken;
  108. outb += taken;
  109. inb += taken;
  110. }
  111. }
  112. void cf_blockwise_acc_byte(uint8_t *partial, size_t *npartial,
  113. size_t nblock,
  114. uint8_t byte, size_t nbytes,
  115. cf_blockwise_in_fn process,
  116. void *ctx)
  117. {
  118. /* only memset the whole of the block once */
  119. int filled = 0;
  120. while (nbytes)
  121. {
  122. size_t start = *npartial;
  123. size_t count = MIN(nbytes, nblock - start);
  124. if (!filled)
  125. memset(partial + start, byte, count);
  126. if (start == 0 && count == nblock)
  127. filled = 1;
  128. if (start + count == nblock)
  129. {
  130. process(ctx, partial);
  131. *npartial = 0;
  132. } else {
  133. *npartial += count;
  134. }
  135. nbytes -= count;
  136. }
  137. }
  138. void cf_blockwise_acc_pad(uint8_t *partial, size_t *npartial,
  139. size_t nblock,
  140. uint8_t fbyte, uint8_t mbyte, uint8_t lbyte,
  141. size_t nbytes,
  142. cf_blockwise_in_fn process,
  143. void *ctx)
  144. {
  145. switch (nbytes)
  146. {
  147. case 0: break;
  148. case 1: fbyte ^= lbyte;
  149. cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx);
  150. break;
  151. case 2:
  152. cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx);
  153. cf_blockwise_accumulate(partial, npartial, nblock, &lbyte, 1, process, ctx);
  154. break;
  155. default:
  156. cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx);
  157. /* If the middle and last bytes differ, then process the last byte separately.
  158. * Otherwise, just extend the middle block size. */
  159. if (lbyte != mbyte)
  160. {
  161. cf_blockwise_acc_byte(partial, npartial, nblock, mbyte, nbytes - 2, process, ctx);
  162. cf_blockwise_accumulate(partial, npartial, nblock, &lbyte, 1, process, ctx);
  163. } else {
  164. cf_blockwise_acc_byte(partial, npartial, nblock, mbyte, nbytes - 1, process, ctx);
  165. }
  166. break;
  167. }
  168. }