blake2.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * BLAKE2 (RFC 7693) implementation for PuTTY.
  3. *
  4. * The BLAKE2 hash family includes BLAKE2s, in which the hash state is
  5. * operated on as a collection of 32-bit integers, and BLAKE2b, based
  6. * on 64-bit integers. At present this code implements BLAKE2b only.
  7. */
  8. #include <assert.h>
  9. #include "ssh.h"
  10. static inline uint64_t ror(uint64_t x, unsigned rotation)
  11. {
  12. #pragma option push -w-ngu // WINSCP
  13. unsigned lshift = 63 & -rotation, rshift = 63 & rotation;
  14. #pragma option pop // WINSCP
  15. return (x << lshift) | (x >> rshift);
  16. }
  17. /* RFC 7963 section 2.1 */
  18. enum { R1 = 32, R2 = 24, R3 = 16, R4 = 63 };
  19. /* RFC 7693 section 2.6 */
  20. static const uint64_t iv[] = {
  21. // WINSCP (ULL)
  22. 0x6a09e667f3bcc908ULL, /* floor(2^64 * frac(sqrt(2))) */
  23. 0xbb67ae8584caa73bULL, /* floor(2^64 * frac(sqrt(3))) */
  24. 0x3c6ef372fe94f82bULL, /* floor(2^64 * frac(sqrt(5))) */
  25. 0xa54ff53a5f1d36f1ULL, /* floor(2^64 * frac(sqrt(7))) */
  26. 0x510e527fade682d1ULL, /* floor(2^64 * frac(sqrt(11))) */
  27. 0x9b05688c2b3e6c1fULL, /* floor(2^64 * frac(sqrt(13))) */
  28. 0x1f83d9abfb41bd6bULL, /* floor(2^64 * frac(sqrt(17))) */
  29. 0x5be0cd19137e2179ULL, /* floor(2^64 * frac(sqrt(19))) */
  30. };
  31. /* RFC 7693 section 2.7 */
  32. static const unsigned char sigma[][16] = {
  33. { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
  34. {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
  35. {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
  36. { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
  37. { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
  38. { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
  39. {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
  40. {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
  41. { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
  42. {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},
  43. /* This array recycles if you have more than 10 rounds. BLAKE2b
  44. * has 12, so we repeat the first two rows again. */
  45. { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
  46. {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
  47. };
  48. static inline void g_half(uint64_t v[16], unsigned a, unsigned b, unsigned c,
  49. unsigned d, uint64_t x, unsigned r1, unsigned r2)
  50. {
  51. v[a] += v[b] + x;
  52. v[d] ^= v[a];
  53. v[d] = ror(v[d], r1);
  54. v[c] += v[d];
  55. v[b] ^= v[c];
  56. v[b] = ror(v[b], r2);
  57. }
  58. static inline void g(uint64_t v[16], unsigned a, unsigned b, unsigned c,
  59. unsigned d, uint64_t x, uint64_t y)
  60. {
  61. g_half(v, a, b, c, d, x, R1, R2);
  62. g_half(v, a, b, c, d, y, R3, R4);
  63. }
  64. static inline void f(uint64_t h[8], uint64_t m[16], uint64_t offset_hi,
  65. uint64_t offset_lo, unsigned final)
  66. {
  67. uint64_t v[16];
  68. memcpy(v, h, 8 * sizeof(*v));
  69. memcpy(v + 8, iv, 8 * sizeof(*v));
  70. v[12] ^= offset_lo;
  71. v[13] ^= offset_hi;
  72. v[14] ^= -(uint64_t)final;
  73. { // WINSCP
  74. unsigned round; // WINSCP
  75. for (round = 0; round < 12; round++) {
  76. const unsigned char *s = sigma[round];
  77. g(v, 0, 4, 8, 12, m[s[ 0]], m[s[ 1]]);
  78. g(v, 1, 5, 9, 13, m[s[ 2]], m[s[ 3]]);
  79. g(v, 2, 6, 10, 14, m[s[ 4]], m[s[ 5]]);
  80. g(v, 3, 7, 11, 15, m[s[ 6]], m[s[ 7]]);
  81. g(v, 0, 5, 10, 15, m[s[ 8]], m[s[ 9]]);
  82. g(v, 1, 6, 11, 12, m[s[10]], m[s[11]]);
  83. g(v, 2, 7, 8, 13, m[s[12]], m[s[13]]);
  84. g(v, 3, 4, 9, 14, m[s[14]], m[s[15]]);
  85. }
  86. { // WINSCP
  87. unsigned i; // WINSCP
  88. for (i = 0; i < 8; i++)
  89. h[i] ^= v[i] ^ v[i+8];
  90. smemclr(v, sizeof(v));
  91. } // WINSCP
  92. } // WINSCP
  93. }
  94. static inline void f_outer(uint64_t h[8], uint8_t blk[128], uint64_t offset_hi,
  95. uint64_t offset_lo, unsigned final)
  96. {
  97. uint64_t m[16];
  98. unsigned i; // WINSCP
  99. for (i = 0; i < 16; i++)
  100. m[i] = GET_64BIT_LSB_FIRST(blk + 8*i);
  101. f(h, m, offset_hi, offset_lo, final);
  102. smemclr(m, sizeof(m));
  103. }
  104. typedef struct blake2b {
  105. uint64_t h[8];
  106. unsigned hashlen;
  107. uint8_t block[128];
  108. size_t used;
  109. uint64_t lenhi, lenlo;
  110. BinarySink_IMPLEMENTATION;
  111. ssh_hash hash;
  112. } blake2b;
  113. static void blake2b_write(BinarySink *bs, const void *vp, size_t len);
  114. static ssh_hash *blake2b_new_inner(unsigned hashlen)
  115. {
  116. assert(hashlen <= ssh_blake2b.hlen);
  117. { // WINSCP
  118. blake2b *s = snew(blake2b);
  119. s->hash.vt = &ssh_blake2b;
  120. s->hashlen = hashlen;
  121. BinarySink_INIT(s, blake2b_write);
  122. BinarySink_DELEGATE_INIT(&s->hash, s);
  123. return &s->hash;
  124. } // WINSCP
  125. }
  126. static ssh_hash *blake2b_new(const ssh_hashalg *alg)
  127. {
  128. return blake2b_new_inner(alg->hlen);
  129. }
  130. ssh_hash *blake2b_new_general(unsigned hashlen)
  131. {
  132. ssh_hash *h = blake2b_new_inner(hashlen);
  133. ssh_hash_reset(h);
  134. return h;
  135. }
  136. static void blake2b_reset(ssh_hash *hash)
  137. {
  138. blake2b *s = container_of(hash, blake2b, hash);
  139. /* Initialise the hash to the standard IV */
  140. memcpy(s->h, iv, sizeof(s->h));
  141. /* XOR in the parameters: secret key length (here always 0) in
  142. * byte 1, and hash length in byte 0. */
  143. s->h[0] ^= 0x01010000 ^ s->hashlen;
  144. s->used = 0;
  145. s->lenhi = s->lenlo = 0;
  146. }
  147. static void blake2b_copyfrom(ssh_hash *hcopy, ssh_hash *horig)
  148. {
  149. blake2b *copy = container_of(hcopy, blake2b, hash);
  150. blake2b *orig = container_of(horig, blake2b, hash);
  151. memcpy(copy, orig, sizeof(*copy));
  152. BinarySink_COPIED(copy);
  153. BinarySink_DELEGATE_INIT(&copy->hash, copy);
  154. }
  155. static void blake2b_free(ssh_hash *hash)
  156. {
  157. blake2b *s = container_of(hash, blake2b, hash);
  158. smemclr(s, sizeof(*s));
  159. sfree(s);
  160. }
  161. static void blake2b_write(BinarySink *bs, const void *vp, size_t len)
  162. {
  163. blake2b *s = BinarySink_DOWNCAST(bs, blake2b);
  164. const uint8_t *p = vp;
  165. while (len > 0) {
  166. if (s->used == sizeof(s->block)) {
  167. f_outer(s->h, s->block, s->lenhi, s->lenlo, 0);
  168. s->used = 0;
  169. }
  170. { // WINSCP
  171. size_t chunk = sizeof(s->block) - s->used;
  172. if (chunk > len)
  173. chunk = len;
  174. memcpy(s->block + s->used, p, chunk);
  175. s->used += chunk;
  176. p += chunk;
  177. len -= chunk;
  178. s->lenlo += chunk;
  179. s->lenhi += (s->lenlo < chunk);
  180. } // WINSCP
  181. }
  182. }
  183. static void blake2b_digest(ssh_hash *hash, uint8_t *digest)
  184. {
  185. blake2b *s = container_of(hash, blake2b, hash);
  186. memset(s->block + s->used, 0, sizeof(s->block) - s->used);
  187. f_outer(s->h, s->block, s->lenhi, s->lenlo, 1);
  188. { // WINSCP
  189. uint8_t hash_pre[128];
  190. unsigned i; // WINSCP
  191. for (i = 0; i < 8; i++)
  192. PUT_64BIT_LSB_FIRST(hash_pre + 8*i, s->h[i]);
  193. memcpy(digest, hash_pre, s->hashlen);
  194. smemclr(hash_pre, sizeof(hash_pre));
  195. } // WINSCP
  196. }
  197. const ssh_hashalg ssh_blake2b = {
  198. // WINSCP
  199. /*.new =*/ blake2b_new,
  200. /*.reset =*/ blake2b_reset,
  201. /*.copyfrom =*/ blake2b_copyfrom,
  202. /*.digest =*/ blake2b_digest,
  203. /*.free =*/ blake2b_free,
  204. /*.hlen =*/ 64,
  205. /*.blocklen =*/ 128,
  206. HASHALG_NAMES_BARE("BLAKE2b-64"),
  207. NULL, // WINSCP
  208. };