Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitrij <kvarkas@gmail.com>2022-10-31 00:45:23 +0300
committerDimitrij <kvarkas@gmail.com>2022-10-31 00:45:23 +0300
commit302fb2e8ddea1c993552c9a30c02f41d01ca54a9 (patch)
treed6cf1b32664296ef2cecda33caeafbe39e6695c1 /crypto/blake2.c
parent59105d9b26363e47f00676bd365b2ac8d4cb536a (diff)
parent4ff82ab29a22936b78510c68f544a99e677efed3 (diff)
Merge tag 'tags/0.78'HEADmaster
Diffstat (limited to 'crypto/blake2.c')
-rw-r--r--crypto/blake2.c223
1 files changed, 223 insertions, 0 deletions
diff --git a/crypto/blake2.c b/crypto/blake2.c
new file mode 100644
index 00000000..a4d42f21
--- /dev/null
+++ b/crypto/blake2.c
@@ -0,0 +1,223 @@
+/*
+ * BLAKE2 (RFC 7693) implementation for PuTTY.
+ *
+ * The BLAKE2 hash family includes BLAKE2s, in which the hash state is
+ * operated on as a collection of 32-bit integers, and BLAKE2b, based
+ * on 64-bit integers. At present this code implements BLAKE2b only.
+ */
+
+#include <assert.h>
+#include "ssh.h"
+
+static inline uint64_t ror(uint64_t x, unsigned rotation)
+{
+ unsigned lshift = 63 & -rotation, rshift = 63 & rotation;
+ return (x << lshift) | (x >> rshift);
+}
+
+/* RFC 7963 section 2.1 */
+enum { R1 = 32, R2 = 24, R3 = 16, R4 = 63 };
+
+/* RFC 7693 section 2.6 */
+static const uint64_t iv[] = {
+ 0x6a09e667f3bcc908, /* floor(2^64 * frac(sqrt(2))) */
+ 0xbb67ae8584caa73b, /* floor(2^64 * frac(sqrt(3))) */
+ 0x3c6ef372fe94f82b, /* floor(2^64 * frac(sqrt(5))) */
+ 0xa54ff53a5f1d36f1, /* floor(2^64 * frac(sqrt(7))) */
+ 0x510e527fade682d1, /* floor(2^64 * frac(sqrt(11))) */
+ 0x9b05688c2b3e6c1f, /* floor(2^64 * frac(sqrt(13))) */
+ 0x1f83d9abfb41bd6b, /* floor(2^64 * frac(sqrt(17))) */
+ 0x5be0cd19137e2179, /* floor(2^64 * frac(sqrt(19))) */
+};
+
+/* RFC 7693 section 2.7 */
+static const unsigned char sigma[][16] = {
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+ {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
+ {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
+ { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
+ { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
+ { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
+ {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
+ {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
+ { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
+ {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},
+ /* This array recycles if you have more than 10 rounds. BLAKE2b
+ * has 12, so we repeat the first two rows again. */
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+ {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
+};
+
+static inline void g_half(uint64_t v[16], unsigned a, unsigned b, unsigned c,
+ unsigned d, uint64_t x, unsigned r1, unsigned r2)
+{
+ v[a] += v[b] + x;
+ v[d] ^= v[a];
+ v[d] = ror(v[d], r1);
+ v[c] += v[d];
+ v[b] ^= v[c];
+ v[b] = ror(v[b], r2);
+}
+
+static inline void g(uint64_t v[16], unsigned a, unsigned b, unsigned c,
+ unsigned d, uint64_t x, uint64_t y)
+{
+ g_half(v, a, b, c, d, x, R1, R2);
+ g_half(v, a, b, c, d, y, R3, R4);
+}
+
+static inline void f(uint64_t h[8], uint64_t m[16], uint64_t offset_hi,
+ uint64_t offset_lo, unsigned final)
+{
+ uint64_t v[16];
+ memcpy(v, h, 8 * sizeof(*v));
+ memcpy(v + 8, iv, 8 * sizeof(*v));
+ v[12] ^= offset_lo;
+ v[13] ^= offset_hi;
+ v[14] ^= -(uint64_t)final;
+ for (unsigned round = 0; round < 12; round++) {
+ const unsigned char *s = sigma[round];
+ g(v, 0, 4, 8, 12, m[s[ 0]], m[s[ 1]]);
+ g(v, 1, 5, 9, 13, m[s[ 2]], m[s[ 3]]);
+ g(v, 2, 6, 10, 14, m[s[ 4]], m[s[ 5]]);
+ g(v, 3, 7, 11, 15, m[s[ 6]], m[s[ 7]]);
+ g(v, 0, 5, 10, 15, m[s[ 8]], m[s[ 9]]);
+ g(v, 1, 6, 11, 12, m[s[10]], m[s[11]]);
+ g(v, 2, 7, 8, 13, m[s[12]], m[s[13]]);
+ g(v, 3, 4, 9, 14, m[s[14]], m[s[15]]);
+ }
+ for (unsigned i = 0; i < 8; i++)
+ h[i] ^= v[i] ^ v[i+8];
+ smemclr(v, sizeof(v));
+}
+
+static inline void f_outer(uint64_t h[8], uint8_t blk[128], uint64_t offset_hi,
+ uint64_t offset_lo, unsigned final)
+{
+ uint64_t m[16];
+ for (unsigned i = 0; i < 16; i++)
+ m[i] = GET_64BIT_LSB_FIRST(blk + 8*i);
+ f(h, m, offset_hi, offset_lo, final);
+ smemclr(m, sizeof(m));
+}
+
+typedef struct blake2b {
+ uint64_t h[8];
+ unsigned hashlen;
+
+ uint8_t block[128];
+ size_t used;
+ uint64_t lenhi, lenlo;
+
+ BinarySink_IMPLEMENTATION;
+ ssh_hash hash;
+} blake2b;
+
+static void blake2b_write(BinarySink *bs, const void *vp, size_t len);
+
+static ssh_hash *blake2b_new_inner(unsigned hashlen)
+{
+ assert(hashlen <= ssh_blake2b.hlen);
+
+ blake2b *s = snew(blake2b);
+ s->hash.vt = &ssh_blake2b;
+ s->hashlen = hashlen;
+ BinarySink_INIT(s, blake2b_write);
+ BinarySink_DELEGATE_INIT(&s->hash, s);
+ return &s->hash;
+}
+
+static ssh_hash *blake2b_new(const ssh_hashalg *alg)
+{
+ return blake2b_new_inner(alg->hlen);
+}
+
+ssh_hash *blake2b_new_general(unsigned hashlen)
+{
+ ssh_hash *h = blake2b_new_inner(hashlen);
+ ssh_hash_reset(h);
+ return h;
+}
+
+static void blake2b_reset(ssh_hash *hash)
+{
+ blake2b *s = container_of(hash, blake2b, hash);
+
+ /* Initialise the hash to the standard IV */
+ memcpy(s->h, iv, sizeof(s->h));
+
+ /* XOR in the parameters: secret key length (here always 0) in
+ * byte 1, and hash length in byte 0. */
+ s->h[0] ^= 0x01010000 ^ s->hashlen;
+
+ s->used = 0;
+ s->lenhi = s->lenlo = 0;
+}
+
+static void blake2b_copyfrom(ssh_hash *hcopy, ssh_hash *horig)
+{
+ blake2b *copy = container_of(hcopy, blake2b, hash);
+ blake2b *orig = container_of(horig, blake2b, hash);
+
+ memcpy(copy, orig, sizeof(*copy));
+ BinarySink_COPIED(copy);
+ BinarySink_DELEGATE_INIT(&copy->hash, copy);
+}
+
+static void blake2b_free(ssh_hash *hash)
+{
+ blake2b *s = container_of(hash, blake2b, hash);
+
+ smemclr(s, sizeof(*s));
+ sfree(s);
+}
+
+static void blake2b_write(BinarySink *bs, const void *vp, size_t len)
+{
+ blake2b *s = BinarySink_DOWNCAST(bs, blake2b);
+ const uint8_t *p = vp;
+
+ while (len > 0) {
+ if (s->used == sizeof(s->block)) {
+ f_outer(s->h, s->block, s->lenhi, s->lenlo, 0);
+ s->used = 0;
+ }
+
+ size_t chunk = sizeof(s->block) - s->used;
+ if (chunk > len)
+ chunk = len;
+
+ memcpy(s->block + s->used, p, chunk);
+ s->used += chunk;
+ p += chunk;
+ len -= chunk;
+
+ s->lenlo += chunk;
+ s->lenhi += (s->lenlo < chunk);
+ }
+}
+
+static void blake2b_digest(ssh_hash *hash, uint8_t *digest)
+{
+ blake2b *s = container_of(hash, blake2b, hash);
+
+ memset(s->block + s->used, 0, sizeof(s->block) - s->used);
+ f_outer(s->h, s->block, s->lenhi, s->lenlo, 1);
+
+ uint8_t hash_pre[128];
+ for (unsigned i = 0; i < 8; i++)
+ PUT_64BIT_LSB_FIRST(hash_pre + 8*i, s->h[i]);
+ memcpy(digest, hash_pre, s->hashlen);
+ smemclr(hash_pre, sizeof(hash_pre));
+}
+
+const ssh_hashalg ssh_blake2b = {
+ .new = blake2b_new,
+ .reset = blake2b_reset,
+ .copyfrom = blake2b_copyfrom,
+ .digest = blake2b_digest,
+ .free = blake2b_free,
+ .hlen = 64,
+ .blocklen = 128,
+ HASHALG_NAMES_BARE("BLAKE2b-64"),
+};