crypto_aesctr_arm.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #include "cpusupport.h"
  2. #ifdef CPUSUPPORT_ARM_AES
  3. /**
  4. * CPUSUPPORT CFLAGS: ARM_AES
  5. */
  6. #include <assert.h>
  7. #include <stdint.h>
  8. #include <string.h>
  9. #ifdef __ARM_NEON
  10. #include <arm_neon.h>
  11. #endif
  12. #include "crypto_aes.h"
  13. #include "crypto_aes_arm_u8.h"
  14. #include "sysendian.h"
  15. #include "crypto_aesctr_arm.h"
  16. /**
  17. * In order to optimize AES-CTR, it is desirable to separate out the handling
  18. * of individual bytes of data vs. the handling of complete (16 byte) blocks.
  19. * The handling of blocks in turn can be optimized further using CPU
  20. * intrinsics, e.g. SSE2 on x86 CPUs; however while the byte-at-once code
  21. * remains the same across platforms it should be inlined into the same (CPU
  22. * feature specific) routines for performance reasons.
  23. *
  24. * In order to allow those generic functions to be inlined into multiple
  25. * functions in separate translation units, we place them into a "shared" C
  26. * file which is included in each of the platform-specific variants.
  27. */
  28. #include "crypto_aesctr_shared.c"
  29. /* Process multiple whole blocks by generating & using a cipherblock. */
  30. static void
  31. crypto_aesctr_arm_stream_wholeblocks(struct crypto_aesctr * stream,
  32. const uint8_t ** inbuf, uint8_t ** outbuf, size_t * buflen)
  33. {
  34. uint8x16_t bufarm;
  35. uint8x16_t inbufarm;
  36. uint8x8_t nonce_be;
  37. uint8x8_t block_counter_be;
  38. uint8_t block_counter_be_arr[8];
  39. uint64_t block_counter;
  40. size_t num_blocks;
  41. size_t i;
  42. /* Load local variables from stream. */
  43. nonce_be = vld1_u8(stream->pblk);
  44. block_counter = stream->bytectr / 16;
  45. /* How many blocks should we process? */
  46. num_blocks = (*buflen) / 16;
  47. /*
  48. * This is 'for (i = num_blocks; i > 0; i--)', but ensuring that the
  49. * compiler knows that we will execute the loop at least once.
  50. */
  51. i = num_blocks;
  52. do {
  53. /* Prepare counter. */
  54. be64enc(block_counter_be_arr, block_counter);
  55. /* Encrypt the cipherblock. */
  56. block_counter_be = vld1_u8(block_counter_be_arr);
  57. bufarm = vcombine_u8(nonce_be, block_counter_be);
  58. bufarm = crypto_aes_encrypt_block_arm_u8(bufarm, stream->key);
  59. /* Encrypt the byte(s). */
  60. inbufarm = vld1q_u8(*inbuf);
  61. bufarm = veorq_u8(inbufarm, bufarm);
  62. vst1q_u8(*outbuf, bufarm);
  63. /* Update the positions. */
  64. block_counter++;
  65. *inbuf += 16;
  66. *outbuf += 16;
  67. /* Update the counter. */
  68. i--;
  69. } while (i > 0);
  70. /* Update the overall buffer length. */
  71. *buflen -= 16 * num_blocks;
  72. /* Update variables in stream. */
  73. memcpy(stream->pblk + 8, block_counter_be_arr, 8);
  74. stream->bytectr += 16 * num_blocks;
  75. }
  76. /**
  77. * crypto_aesctr_arm_stream(stream, inbuf, outbuf, buflen):
  78. * Generate the next ${buflen} bytes of the AES-CTR stream ${stream} and xor
  79. * them with bytes from ${inbuf}, writing the result into ${outbuf}. If the
  80. * buffers ${inbuf} and ${outbuf} overlap, they must be identical.
  81. */
  82. void
  83. crypto_aesctr_arm_stream(struct crypto_aesctr * stream, const uint8_t * inbuf,
  84. uint8_t * outbuf, size_t buflen)
  85. {
  86. /* Process any bytes before we can process a whole block. */
  87. if (crypto_aesctr_stream_pre_wholeblock(stream, &inbuf, &outbuf,
  88. &buflen))
  89. return;
  90. /* Process whole blocks of 16 bytes. */
  91. if (buflen >= 16)
  92. crypto_aesctr_arm_stream_wholeblocks(stream, &inbuf, &outbuf,
  93. &buflen);
  94. /* Process any final bytes after finishing all whole blocks. */
  95. crypto_aesctr_stream_post_wholeblock(stream, &inbuf, &outbuf, &buflen);
  96. }
  97. #endif /* CPUSUPPORT_ARM_AES */