blockwise.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  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 "handy.h"
  17. #include "tassert.h"
  18. #include <string.h>
  19. void cf_blockwise_accumulate(uint8_t *partial, size_t *npartial, size_t nblock,
  20. const void *inp, size_t nbytes,
  21. cf_blockwise_in_fn process,
  22. void *ctx)
  23. {
  24. cf_blockwise_accumulate_final(partial, npartial, nblock,
  25. inp, nbytes,
  26. process, process, ctx);
  27. }
  28. void cf_blockwise_accumulate_final(uint8_t *partial, size_t *npartial, size_t nblock,
  29. const void *inp, size_t nbytes,
  30. cf_blockwise_in_fn process,
  31. cf_blockwise_in_fn process_final,
  32. void *ctx)
  33. {
  34. const uint8_t *bufin = inp;
  35. assert(partial && *npartial < nblock);
  36. assert(inp || !nbytes);
  37. assert(process && ctx);
  38. /* If we have partial data, copy in to buffer. */
  39. if (*npartial && nbytes)
  40. {
  41. size_t space = nblock - *npartial;
  42. size_t taken = MIN(space, nbytes);
  43. memcpy(partial + *npartial, bufin, taken);
  44. bufin += taken;
  45. nbytes -= taken;
  46. *npartial += taken;
  47. /* If that gives us a full block, process it. */
  48. if (*npartial == nblock)
  49. {
  50. if (nbytes == 0)
  51. process_final(ctx, partial);
  52. else
  53. process(ctx, partial);
  54. *npartial = 0;
  55. }
  56. }
  57. /* now nbytes < nblock or *npartial == 0. */
  58. /* If we have a full block of data, process it directly. */
  59. while (nbytes >= nblock)
  60. {
  61. /* Partial buffer must be empty, or we're ignoring extant data */
  62. assert(*npartial == 0);
  63. if (nbytes == nblock)
  64. process_final(ctx, bufin);
  65. else
  66. process(ctx, bufin);
  67. bufin += nblock;
  68. nbytes -= nblock;
  69. }
  70. /* Finally, if we have remaining data, buffer it. */
  71. while (nbytes)
  72. {
  73. size_t space = nblock - *npartial;
  74. size_t taken = MIN(space, nbytes);
  75. memcpy(partial + *npartial, bufin, taken);
  76. bufin += taken;
  77. nbytes -= taken;
  78. *npartial += taken;
  79. /* If we started with *npartial, we must have copied it
  80. * in first. */
  81. assert(*npartial < nblock);
  82. }
  83. }
  84. void cf_blockwise_xor(uint8_t *partial, size_t *npartial, size_t nblock,
  85. const void *inp, void *outp, size_t nbytes,
  86. cf_blockwise_out_fn process, void *ctx)
  87. {
  88. const uint8_t *inb = inp;
  89. uint8_t *outb = outp;
  90. assert(partial && *npartial < nblock);
  91. assert(inp || !nbytes);
  92. assert(process && ctx);
  93. while (nbytes)
  94. {
  95. /* If we're out of material, and need more, produce a block. */
  96. if (*npartial == 0)
  97. {
  98. process(ctx, partial);
  99. *npartial = nblock;
  100. }
  101. size_t offset = nblock - *npartial;
  102. size_t taken = MIN(*npartial, nbytes);
  103. xor_bb(outb, inb, partial + offset, taken);
  104. *npartial -= taken;
  105. nbytes -= taken;
  106. outb += taken;
  107. inb += taken;
  108. }
  109. }
  110. void cf_blockwise_acc_byte(uint8_t *partial, size_t *npartial,
  111. size_t nblock,
  112. uint8_t byte, size_t nbytes,
  113. cf_blockwise_in_fn process,
  114. void *ctx)
  115. {
  116. /* only memset the whole of the block once */
  117. int filled = 0;
  118. while (nbytes)
  119. {
  120. size_t start = *npartial;
  121. size_t count = MIN(nbytes, nblock - start);
  122. if (!filled)
  123. memset(partial + start, byte, count);
  124. if (start == 0 && count == nblock)
  125. filled = 1;
  126. if (start + count == nblock)
  127. {
  128. process(ctx, partial);
  129. *npartial = 0;
  130. } else {
  131. *npartial += count;
  132. }
  133. nbytes -= count;
  134. }
  135. }
  136. void cf_blockwise_acc_pad(uint8_t *partial, size_t *npartial,
  137. size_t nblock,
  138. uint8_t fbyte, uint8_t mbyte, uint8_t lbyte,
  139. size_t nbytes,
  140. cf_blockwise_in_fn process,
  141. void *ctx)
  142. {
  143. switch (nbytes)
  144. {
  145. case 0: break;
  146. case 1: fbyte ^= lbyte;
  147. cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx);
  148. break;
  149. case 2:
  150. cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx);
  151. cf_blockwise_accumulate(partial, npartial, nblock, &lbyte, 1, process, ctx);
  152. break;
  153. default:
  154. cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx);
  155. /* If the middle and last bytes differ, then process the last byte separately.
  156. * Otherwise, just extend the middle block size. */
  157. if (lbyte != mbyte)
  158. {
  159. cf_blockwise_acc_byte(partial, npartial, nblock, mbyte, nbytes - 2, process, ctx);
  160. cf_blockwise_accumulate(partial, npartial, nblock, &lbyte, 1, process, ctx);
  161. } else {
  162. cf_blockwise_acc_byte(partial, npartial, nblock, mbyte, nbytes - 1, process, ctx);
  163. }
  164. break;
  165. }
  166. }