Salsa20.hpp 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /*
  2. * Based on public domain code available at: http://cr.yp.to/snuffle.html
  3. *
  4. * This therefore is public domain.
  5. */
  6. #ifndef ZT_SALSA20_HPP
  7. #define ZT_SALSA20_HPP
  8. #include <stdio.h>
  9. #include <stdint.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include "Constants.hpp"
  13. #include "Utils.hpp"
  14. #if (!defined(ZT_SALSA20_SSE)) && (defined(__SSE2__) || defined(__WINDOWS__))
  15. #define ZT_SALSA20_SSE 1
  16. #endif
  17. #ifdef ZT_SALSA20_SSE
  18. #include <emmintrin.h>
  19. #endif // ZT_SALSA20_SSE
  20. namespace ZeroTier {
  21. /**
  22. * Salsa20 stream cipher
  23. */
  24. class Salsa20
  25. {
  26. public:
  27. Salsa20() {}
  28. ~Salsa20() { Utils::burn(&_state,sizeof(_state)); }
  29. /**
  30. * XOR d with s
  31. *
  32. * This is done efficiently using e.g. SSE if available. It's used when
  33. * alternative Salsa20 implementations are used in Packet and is here
  34. * since this is where all the SSE stuff is already included.
  35. *
  36. * @param d Destination to XOR
  37. * @param s Source bytes to XOR with destination
  38. * @param len Length of s and d
  39. */
  40. static inline void memxor(uint8_t *d,const uint8_t *s,unsigned int len)
  41. {
  42. #ifdef ZT_SALSA20_SSE
  43. while (len >= 16) {
  44. _mm_storeu_si128(reinterpret_cast<__m128i *>(d),_mm_xor_si128(_mm_loadu_si128(reinterpret_cast<__m128i *>(d)),_mm_loadu_si128(reinterpret_cast<const __m128i *>(s))));
  45. s += 16;
  46. d += 16;
  47. len -= 16;
  48. }
  49. #else
  50. #ifndef ZT_NO_TYPE_PUNNING
  51. while (len >= 16) {
  52. (*reinterpret_cast<uint64_t *>(d)) ^= (*reinterpret_cast<const uint64_t *>(s));
  53. s += 8;
  54. d += 8;
  55. (*reinterpret_cast<uint64_t *>(d)) ^= (*reinterpret_cast<const uint64_t *>(s));
  56. s += 8;
  57. d += 8;
  58. len -= 16;
  59. }
  60. #endif
  61. #endif
  62. while (len--)
  63. *(d++) ^= *(s++);
  64. }
  65. /**
  66. * @param key 256-bit (32 byte) key
  67. * @param iv 64-bit initialization vector
  68. */
  69. Salsa20(const void *key,const void *iv)
  70. {
  71. init(key,iv);
  72. }
  73. /**
  74. * Initialize cipher
  75. *
  76. * @param key Key bits
  77. * @param iv 64-bit initialization vector
  78. */
  79. void init(const void *key,const void *iv);
  80. /**
  81. * Encrypt/decrypt data using Salsa20/12
  82. *
  83. * @param in Input data
  84. * @param out Output buffer
  85. * @param bytes Length of data
  86. */
  87. void crypt12(const void *in,void *out,unsigned int bytes);
  88. /**
  89. * Encrypt/decrypt data using Salsa20/20
  90. *
  91. * @param in Input data
  92. * @param out Output buffer
  93. * @param bytes Length of data
  94. */
  95. void crypt20(const void *in,void *out,unsigned int bytes);
  96. private:
  97. union {
  98. #ifdef ZT_SALSA20_SSE
  99. __m128i v[4];
  100. #endif // ZT_SALSA20_SSE
  101. uint32_t i[16];
  102. } _state;
  103. };
  104. } // namespace ZeroTier
  105. #endif