| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 | 
							- /*
 
-  * SHA-3, as defined in FIPS PUB 202.
 
-  */
 
- #include <assert.h>
 
- #include <string.h>
 
- #include "ssh.h"
 
- static inline uint64_t rol(uint64_t x, unsigned shift)
 
- {
 
-     unsigned L = (+shift) & 63;
 
- #pragma option push -w-ngu // WINSCP
 
-     unsigned R = (-shift) & 63;
 
- #pragma option pop // WINSCP
 
-     return (x << L) | (x >> R);
 
- }
 
- /*
 
-  * General Keccak is defined such that its state is a 5x5 array of
 
-  * words which can be any power-of-2 size from 1 up to 64. SHA-3 fixes
 
-  * on 64, and so do we.
 
-  *
 
-  * The number of rounds is defined as 12 + 2k if the word size is 2^k.
 
-  * Here we have 64-bit words only, so k=6, so 24 rounds always.
 
-  */
 
- typedef uint64_t keccak_core_state[5][5];
 
- #define NROUNDS 24               /* would differ for other word sizes */
 
- static const uint64_t round_constants[NROUNDS];
 
- static const unsigned rotation_counts[5][5];
 
- /*
 
-  * Core Keccak transform: just squodge the state around internally,
 
-  * without adding or extracting any data from it.
 
-  */
 
- static void keccak_transform(keccak_core_state A)
 
- {
 
-     union {
 
-         uint64_t C[5];
 
-         uint64_t B[5][5];
 
-     } u;
 
-     unsigned round; // WINSCP
 
-     for (round = 0; round < NROUNDS; round++) {
 
-         /* theta step */
 
-         unsigned x; // WINSCP
 
-         for (x = 0; x < 5; x++)
 
-             u.C[x] = A[x][0] ^ A[x][1] ^ A[x][2] ^ A[x][3] ^ A[x][4];
 
-         for (x = 0; x < 5; x++) { // WINSCP
 
-             uint64_t D = rol(u.C[(x+1) % 5], 1) ^ u.C[(x+4) % 5];
 
-             { // WINSCP
 
-             unsigned y; // WINSCP
 
-             for (y = 0; y < 5; y++)
 
-                 A[x][y] ^= D;
 
-             } // WINSCP
 
-         }
 
-         /* rho and pi steps */
 
-         for (x = 0; x < 5; x++) // WINSCP
 
-         { // WINSCP
 
-             unsigned y; // WINSCP
 
-             for (y = 0; y < 5; y++)
 
-                 u.B[y][(2*x+3*y) % 5] = rol(A[x][y], rotation_counts[x][y]);
 
-         } // WINSCP
 
-         /* chi step */
 
-         for (x = 0; x < 5; x++) // WINSCP
 
-         { // WINSCP
 
-             unsigned y; // WINSCP
 
-             for (y = 0; y < 5; y++)
 
-                 A[x][y] = u.B[x][y] ^ (u.B[(x+2)%5][y] & ~u.B[(x+1)%5][y]);
 
-         } // WINSCP
 
-         /* iota step */
 
-         A[0][0] ^= round_constants[round];
 
-     }
 
-     smemclr(&u, sizeof(u));
 
- }
 
- typedef struct {
 
-     keccak_core_state A;
 
-     unsigned char bytes[25*8];
 
-     unsigned char first_pad_byte;
 
-     size_t bytes_got, bytes_wanted, hash_bytes;
 
- } keccak_state;
 
- /*
 
-  * Keccak accumulation function: given a piece of message, add it to
 
-  * the hash.
 
-  */
 
- static void keccak_accumulate(keccak_state *s, const void *vdata, size_t len)
 
- {
 
-     const unsigned char *data = (const unsigned char *)vdata;
 
-     while (len >= s->bytes_wanted - s->bytes_got) {
 
-         size_t b = s->bytes_wanted - s->bytes_got;
 
-         memcpy(s->bytes + s->bytes_got, data, b);
 
-         len -= b;
 
-         data += b;
 
-         { // WINSCP
 
-         size_t n = 0;
 
-         unsigned y; // WINSCP
 
-         for (y = 0; y < 5; y++) {
 
-             unsigned x; // WINSCP
 
-             for (x = 0; x < 5; x++) {
 
-                 if (n >= s->bytes_wanted)
 
-                     break;
 
-                 s->A[x][y] ^= GET_64BIT_LSB_FIRST(s->bytes + n);
 
-                 n += 8;
 
-             }
 
-         }
 
-         keccak_transform(s->A);
 
-         s->bytes_got = 0;
 
-         } // WINSCP
 
-     }
 
-     memcpy(s->bytes + s->bytes_got, data, len);
 
-     s->bytes_got += len;
 
- }
 
- /*
 
-  * Keccak output function.
 
-  */
 
- static void keccak_output(keccak_state *s, void *voutput)
 
- {
 
-     unsigned char *output = (unsigned char *)voutput;
 
-     /*
 
-      * Add message padding.
 
-      */
 
-     {
 
-         unsigned char padding[25*8];
 
-         size_t len = s->bytes_wanted - s->bytes_got;
 
-         if (len == 0)
 
-             len = s->bytes_wanted;
 
-         memset(padding, 0, len);
 
-         padding[0] |= s->first_pad_byte;
 
-         padding[len-1] |= 0x80;
 
-         keccak_accumulate(s, padding, len);
 
-     }
 
-     { // WINSCP
 
-     size_t n = 0;
 
-     unsigned y; // WINSCP
 
-     for (y = 0; y < 5; y++) {
 
-         unsigned x; // WINSCP
 
-         for (x = 0; x < 5; x++) {
 
-             size_t to_copy = s->hash_bytes - n;
 
-             if (to_copy == 0)
 
-                 break;
 
-             if (to_copy > 8)
 
-                 to_copy = 8;
 
-             { // WINSCP
 
-             unsigned char outbytes[8];
 
-             PUT_64BIT_LSB_FIRST(outbytes, s->A[x][y]);
 
-             memcpy(output + n, outbytes, to_copy);
 
-             n += to_copy;
 
-             } // WINSCP
 
-         }
 
-     }
 
-     } // WINSCP
 
- }
 
- static void keccak_init(keccak_state *s, unsigned hashbits, unsigned ratebits,
 
-                         unsigned char first_pad_byte)
 
- {
 
-     int x, y;
 
-     assert(hashbits % 8 == 0);
 
-     assert(ratebits % 8 == 0);
 
-     s->hash_bytes = hashbits / 8;
 
-     s->bytes_wanted = (25 * 64 - ratebits) / 8;
 
-     s->bytes_got = 0;
 
-     s->first_pad_byte = first_pad_byte;
 
-     assert(s->bytes_wanted % 8 == 0);
 
-     for (y = 0; y < 5; y++)
 
-         for (x = 0; x < 5; x++)
 
-             s->A[x][y] = 0;
 
- }
 
- static void keccak_sha3_init(keccak_state *s, int hashbits)
 
- {
 
-     keccak_init(s, hashbits, hashbits * 2, 0x06);
 
- }
 
- static void keccak_shake_init(keccak_state *s, int parambits, int hashbits)
 
- {
 
-     keccak_init(s, hashbits, parambits * 2, 0x1f);
 
- }
 
- /*
 
-  * Keccak round constants, generated via the LFSR specified in the
 
-  * Keccak reference by the following piece of Python:
 
- import textwrap
 
- from functools import reduce
 
- rbytes = [1]
 
- while len(rbytes) < 7*24:
 
-     k = rbytes[-1] * 2
 
-     rbytes.append(k ^ (0x171 * (k >> 8)))
 
- rbits = [byte & 1 for byte in rbytes]
 
- rwords = [sum(rbits[i+j] << ((1 << j) - 1) for j in range(7))
 
-           for i in range(0, len(rbits), 7)]
 
- print(textwrap.indent("\n".join(textwrap.wrap(", ".join(
 
-     map("0x{:016x}".format, rwords)))), " "*4))
 
- */
 
- static const uint64_t round_constants[24] = {
 
-     // WINSCP (ULL)
 
-     0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL,
 
-     0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL,
 
-     0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL,
 
-     0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL,
 
-     0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL,
 
-     0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL,
 
-     0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL,
 
-     0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL
 
- };
 
- /*
 
-  * Keccak per-element rotation counts, generated from the matrix
 
-  * formula in the Keccak reference by the following piece of Python:
 
- coords = [1, 0]
 
- while len(coords) < 26:
 
-     coords.append((2*coords[-2] + 3*coords[-1]) % 5)
 
- matrix = { (coords[i], coords[i+1]) : i for i in range(24) }
 
- matrix[0,0] = -1
 
- f = lambda t: (t+1) * (t+2) // 2 % 64
 
- for y in range(5):
 
-     print("    {{{}}},".format(", ".join("{:2d}".format(f(matrix[y,x]))
 
-                                          for x in range(5))))
 
- */
 
- static const unsigned rotation_counts[5][5] = {
 
-     { 0, 36,  3, 41, 18},
 
-     { 1, 44, 10, 45,  2},
 
-     {62,  6, 43, 15, 61},
 
-     {28, 55, 25, 21, 56},
 
-     {27, 20, 39,  8, 14},
 
- };
 
- /*
 
-  * The PuTTY ssh_hashalg abstraction.
 
-  */
 
- struct keccak_hash {
 
-     keccak_state state;
 
-     ssh_hash hash;
 
-     BinarySink_IMPLEMENTATION;
 
- };
 
- static void keccak_BinarySink_write(BinarySink *bs, const void *p, size_t len)
 
- {
 
-     struct keccak_hash *kh = BinarySink_DOWNCAST(bs, struct keccak_hash);
 
-     keccak_accumulate(&kh->state, p, len);
 
- }
 
- static ssh_hash *keccak_new(const ssh_hashalg *alg)
 
- {
 
-     struct keccak_hash *kh = snew(struct keccak_hash);
 
-     kh->hash.vt = alg;
 
-     BinarySink_INIT(kh, keccak_BinarySink_write);
 
-     BinarySink_DELEGATE_INIT(&kh->hash, kh);
 
-     return ssh_hash_reset(&kh->hash);
 
- }
 
- static void keccak_free(ssh_hash *hash)
 
- {
 
-     struct keccak_hash *kh = container_of(hash, struct keccak_hash, hash);
 
-     smemclr(kh, sizeof(*kh));
 
-     sfree(kh);
 
- }
 
- static void keccak_copyfrom(ssh_hash *hnew, ssh_hash *hold)
 
- {
 
-     struct keccak_hash *khold = container_of(hold, struct keccak_hash, hash);
 
-     struct keccak_hash *khnew = container_of(hnew, struct keccak_hash, hash);
 
-     khnew->state = khold->state;
 
- }
 
- static void keccak_digest(ssh_hash *hash, unsigned char *output)
 
- {
 
-     struct keccak_hash *kh = container_of(hash, struct keccak_hash, hash);
 
-     keccak_output(&kh->state, output);
 
- }
 
- static void sha3_reset(ssh_hash *hash)
 
- {
 
-     struct keccak_hash *kh = container_of(hash, struct keccak_hash, hash);
 
-     keccak_sha3_init(&kh->state, hash->vt->hlen * 8);
 
- }
 
- #define DEFINE_SHA3(bits)                       \
 
-     const ssh_hashalg ssh_sha3_##bits = {       \
 
-         /* WINSCP */ \
 
-         /*.new =*/ keccak_new,                      \
 
-         /*.reset =*/ sha3_reset,                    \
 
-         /*.copyfrom =*/ keccak_copyfrom,            \
 
-         /*.digest =*/ keccak_digest,                \
 
-         /*.free =*/ keccak_free,                    \
 
-         /*.hlen =*/ bits/8,                         \
 
-         /*.blocklen =*/ 200 - 2*(bits/8),           \
 
-         HASHALG_NAMES_BARE("SHA3-" #bits),      \
 
-         NULL, /* WINSCP */ \
 
-     }
 
- DEFINE_SHA3(224);
 
- DEFINE_SHA3(256);
 
- DEFINE_SHA3(384);
 
- DEFINE_SHA3(512);
 
- static void shake256_reset(ssh_hash *hash)
 
- {
 
-     struct keccak_hash *kh = container_of(hash, struct keccak_hash, hash);
 
-     keccak_shake_init(&kh->state, 256, hash->vt->hlen * 8);
 
- }
 
- /*
 
-  * There is some confusion over the output length parameter for the
 
-  * SHAKE functions. By my reading, FIPS PUB 202 defines SHAKE256(M,d)
 
-  * to generate d _bits_ of output. But RFC 8032 (defining Ed448) talks
 
-  * about "SHAKE256(x,114)" in a context where it definitely means
 
-  * generating 114 _bytes_ of output.
 
-  *
 
-  * Our internal ID therefore suffixes the output length with "bytes",
 
-  * to be clear which we're talking about
 
-  */
 
- #define DEFINE_SHAKE(param, hashbytes)                          \
 
-     const ssh_hashalg ssh_shake##param##_##hashbytes##bytes = { \
 
-         /* WINSCP */ \
 
-         /*.new =*/ keccak_new,                                      \
 
-         /*.reset =*/ shake##param##_reset,                          \
 
-         /*.copyfrom =*/ keccak_copyfrom,                            \
 
-         /*.digest =*/ keccak_digest,                                \
 
-         /*.free =*/ keccak_free,                                    \
 
-         /*.hlen =*/ hashbytes,                                      \
 
-         /*.blocklen =*/ 0,                                          \
 
-         HASHALG_NAMES_BARE("SHAKE" #param),                     \
 
-         NULL, /*NULL*/ \
 
-     }
 
- DEFINE_SHAKE(256, 114);
 
 
  |