blake2b.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #pragma once
  2. #include <util/generic/yexception.h>
  3. #include <util/system/compiler.h>
  4. #include <library/cpp/digest/argonish/blake2b.h>
  5. namespace NArgonish {
  6. const ui32 BLAKE2B_BLOCKBYTES = 128;
  7. const ui32 BLAKE2B_BLOCKQWORDS = BLAKE2B_BLOCKBYTES / 8;
  8. const ui32 BLAKE2B_OUTBYTES = 64;
  9. const ui32 BLAKE2B_KEYBYTES = 64;
  10. const ui32 BLAKE2B_SALTBYTES = 16;
  11. const ui32 BLAKE2B_PERSONALBYTES = 16;
  12. template <NArgonish::EInstructionSet instructionSet>
  13. class TBlake2B final: public IBlake2Base {
  14. public:
  15. virtual ~TBlake2B<instructionSet>() {
  16. SecureZeroMemory_((void*)&State_, sizeof(State_));
  17. SecureZeroMemory_((void*)&Param_, sizeof(Param_));
  18. }
  19. EInstructionSet GetInstructionSet() {
  20. return instructionSet;
  21. }
  22. protected:
  23. struct TBlake2BState {
  24. ui64 H[8];
  25. ui64 T[2];
  26. ui64 F[2];
  27. ui64 Buf[BLAKE2B_BLOCKQWORDS];
  28. size_t BufLen;
  29. size_t OutLen;
  30. ui8 LastNode;
  31. };
  32. struct TBlake2BParam {
  33. ui8 DigestLen; /* 1 */
  34. ui8 KeyLen; /* 2 */
  35. ui8 Fanout; /* 3 */
  36. ui8 Depth; /* 4 */
  37. ui32 LeafLength; /* 8 */
  38. ui32 NodeOffset; /* 12 */
  39. ui32 XofLength; /* 16 */
  40. ui8 NodeDepth; /* 17 */
  41. ui8 InnerLength; /* 18 */
  42. ui8 Reserved[14]; /* 32 */
  43. ui8 Salt[BLAKE2B_SALTBYTES]; /* 48 */
  44. ui8 Personal[BLAKE2B_PERSONALBYTES]; /* 64 */
  45. } Y_PACKED;
  46. TBlake2BState State_;
  47. TBlake2BParam Param_;
  48. protected:
  49. void Compress_(const ui64 block[BLAKE2B_BLOCKQWORDS]);
  50. void InitialXor_(ui8* h, const ui8* p);
  51. void* GetIV_() const;
  52. static void SecureZeroMemory_(void* src, size_t len) {
  53. static void* (*const volatile memsetv)(void*, int, size_t) = &memset;
  54. memsetv(src, 0, len);
  55. }
  56. void InitParam_() {
  57. memset(&State_, 0, sizeof(State_));
  58. InitialXor_((ui8*)(State_.H), (const ui8*)(&Param_));
  59. State_.OutLen = Param_.DigestLen;
  60. }
  61. void IncrementCounter_(const ui64 inc) {
  62. State_.T[0] += inc;
  63. State_.T[1] += (State_.T[0] < inc) ? 1 : 0;
  64. }
  65. bool IsLastBlock_() {
  66. return State_.F[0] != 0;
  67. }
  68. void SetLastNode_() {
  69. State_.F[1] = (ui64)-1;
  70. }
  71. void SetLastBlock_() {
  72. if (State_.LastNode)
  73. SetLastNode_();
  74. State_.F[0] = (ui64)-1;
  75. }
  76. public:
  77. TBlake2B(size_t outlen) {
  78. /*
  79. * Note that outlen check was moved to proxy class
  80. */
  81. Param_.DigestLen = (ui8)outlen;
  82. Param_.KeyLen = 0;
  83. Param_.Fanout = 1;
  84. Param_.Depth = 1;
  85. Param_.LeafLength = 0;
  86. Param_.NodeOffset = 0;
  87. Param_.XofLength = 0;
  88. Param_.NodeDepth = 0;
  89. Param_.InnerLength = 0;
  90. memset(Param_.Reserved, 0, sizeof(Param_.Reserved));
  91. memset(Param_.Salt, 0, sizeof(Param_.Salt));
  92. memset(Param_.Personal, 0, sizeof(Param_.Personal));
  93. InitParam_();
  94. }
  95. TBlake2B(size_t outlen, const void* key, size_t keylen) {
  96. /**
  97. * Note that key and outlen checks were moved to proxy classes
  98. */
  99. Param_.DigestLen = (ui8)outlen;
  100. Param_.KeyLen = (ui8)keylen;
  101. Param_.Fanout = 1;
  102. Param_.Depth = 1;
  103. Param_.LeafLength = 0;
  104. Param_.NodeOffset = 0;
  105. Param_.XofLength = 0;
  106. Param_.NodeDepth = 0;
  107. Param_.InnerLength = 0;
  108. memset(Param_.Reserved, 0, sizeof(Param_.Reserved));
  109. memset(Param_.Salt, 0, sizeof(Param_.Salt));
  110. memset(Param_.Personal, 0, sizeof(Param_.Personal));
  111. InitParam_();
  112. ui8 block[BLAKE2B_BLOCKBYTES] = {0};
  113. memcpy(block, key, keylen);
  114. Update(block, BLAKE2B_BLOCKBYTES);
  115. SecureZeroMemory_(block, BLAKE2B_BLOCKBYTES);
  116. }
  117. void Update(ui32 in) override {
  118. Update((const void*)&in, sizeof(in));
  119. }
  120. void Update(const void* pin, size_t inlen) override {
  121. const ui8* in = (ui8*)pin;
  122. if (inlen > 0) {
  123. size_t left = State_.BufLen;
  124. size_t fill = BLAKE2B_BLOCKBYTES - left;
  125. if (inlen > fill) {
  126. State_.BufLen = 0;
  127. memcpy((ui8*)State_.Buf + left, in, fill); /* Fill buffer */
  128. IncrementCounter_(BLAKE2B_BLOCKBYTES);
  129. Compress_(State_.Buf); /* Compress */
  130. in += fill;
  131. inlen -= fill;
  132. while (inlen > BLAKE2B_BLOCKBYTES) {
  133. /* to fix ubsan's unaligned report */
  134. ui64 tmpbuf[BLAKE2B_BLOCKQWORDS];
  135. memcpy(tmpbuf, in, BLAKE2B_BLOCKBYTES);
  136. IncrementCounter_(BLAKE2B_BLOCKBYTES);
  137. Compress_(tmpbuf);
  138. in += BLAKE2B_BLOCKBYTES;
  139. inlen -= BLAKE2B_BLOCKBYTES;
  140. }
  141. }
  142. memcpy((ui8*)State_.Buf + State_.BufLen, in, inlen);
  143. State_.BufLen += inlen;
  144. }
  145. }
  146. void Final(void* out, size_t outlen) override {
  147. if (out == nullptr || outlen < State_.OutLen)
  148. ythrow yexception() << "out is null or outlen is too long";
  149. if (IsLastBlock_())
  150. ythrow yexception() << "Final can't be called several times";
  151. IncrementCounter_(State_.BufLen);
  152. SetLastBlock_();
  153. memset((ui8*)State_.Buf + State_.BufLen, 0, BLAKE2B_BLOCKBYTES - State_.BufLen);
  154. Compress_(State_.Buf);
  155. memcpy(out, (void*)&State_.H[0], outlen);
  156. }
  157. };
  158. }