1999-01-08 13:02:13 +00:00
|
|
|
/*
|
2019-01-20 18:44:26 +00:00
|
|
|
* SHA-1 algorithm as described at
|
|
|
|
*
|
|
|
|
* http://csrc.nist.gov/cryptval/shs.html
|
1999-01-08 13:02:13 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "ssh.h"
|
2018-02-18 21:07:06 +00:00
|
|
|
#include <assert.h>
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
/*
|
|
|
|
* Start by deciding whether we can support hardware SHA at all.
|
|
|
|
*/
|
|
|
|
#define HW_SHA1_NONE 0
|
|
|
|
#define HW_SHA1_NI 1
|
|
|
|
|
|
|
|
#ifdef _FORCE_SHA_NI
|
|
|
|
# define HW_SHA1 HW_SHA1_NI
|
|
|
|
#elif defined(__clang__)
|
|
|
|
# if __has_attribute(target) && __has_include(<wmmintrin.h>) && \
|
|
|
|
(defined(__x86_64__) || defined(__i386))
|
|
|
|
# define HW_SHA1 HW_SHA1_NI
|
|
|
|
# endif
|
|
|
|
#elif defined(__GNUC__)
|
|
|
|
# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) && \
|
|
|
|
(defined(__x86_64__) || defined(__i386))
|
|
|
|
# define HW_SHA1 HW_SHA1_NI
|
|
|
|
# endif
|
|
|
|
#elif defined (_MSC_VER)
|
|
|
|
# if (defined(_M_X64) || defined(_M_IX86)) && _MSC_FULL_VER >= 150030729
|
|
|
|
# define HW_SHA1 HW_SHA1_NI
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined _FORCE_SOFTWARE_SHA || !defined HW_SHA1
|
|
|
|
# undef HW_SHA1
|
|
|
|
# define HW_SHA1 HW_SHA1_NONE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The actual query function that asks if hardware acceleration is
|
|
|
|
* available.
|
|
|
|
*/
|
|
|
|
static bool sha1_hw_available(void);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The top-level selection function, caching the results of
|
|
|
|
* sha1_hw_available() so it only has to run once.
|
|
|
|
*/
|
|
|
|
static bool sha1_hw_available_cached(void)
|
|
|
|
{
|
|
|
|
static bool initialised = false;
|
|
|
|
static bool hw_available;
|
|
|
|
if (!initialised) {
|
|
|
|
hw_available = sha1_hw_available();
|
|
|
|
initialised = true;
|
|
|
|
}
|
|
|
|
return hw_available;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssh_hash *sha1_select(const ssh_hashalg *alg)
|
|
|
|
{
|
|
|
|
const ssh_hashalg *real_alg =
|
|
|
|
sha1_hw_available_cached() ? &ssh_sha1_hw : &ssh_sha1_sw;
|
|
|
|
|
|
|
|
return ssh_hash_new(real_alg);
|
|
|
|
}
|
|
|
|
|
|
|
|
const ssh_hashalg ssh_sha1 = {
|
|
|
|
sha1_select, NULL, NULL, NULL,
|
|
|
|
20, 64, "SHA-1",
|
|
|
|
};
|
2019-01-20 16:15:14 +00:00
|
|
|
|
2000-09-05 14:28:17 +00:00
|
|
|
/* ----------------------------------------------------------------------
|
2019-01-20 18:44:26 +00:00
|
|
|
* Definitions likely to be helpful to multiple implementations.
|
2000-09-05 14:28:17 +00:00
|
|
|
*/
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static const uint32_t sha1_initial_state[] = {
|
|
|
|
0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0,
|
|
|
|
};
|
2000-09-05 14:28:17 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
#define SHA1_ROUNDS_PER_STAGE 20
|
|
|
|
#define SHA1_STAGE0_CONSTANT 0x5a827999
|
|
|
|
#define SHA1_STAGE1_CONSTANT 0x6ed9eba1
|
|
|
|
#define SHA1_STAGE2_CONSTANT 0x8f1bbcdc
|
|
|
|
#define SHA1_STAGE3_CONSTANT 0xca62c1d6
|
|
|
|
#define SHA1_ROUNDS (4 * SHA1_ROUNDS_PER_STAGE)
|
|
|
|
|
|
|
|
typedef struct sha1_block sha1_block;
|
|
|
|
struct sha1_block {
|
|
|
|
uint8_t block[64];
|
|
|
|
size_t used;
|
|
|
|
uint64_t len;
|
|
|
|
};
|
2018-02-11 10:40:24 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static inline void sha1_block_setup(sha1_block *blk)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2019-01-20 18:44:26 +00:00
|
|
|
blk->used = 0;
|
|
|
|
blk->len = 0;
|
2000-09-05 14:28:17 +00:00
|
|
|
}
|
1999-12-03 11:32:50 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static inline bool sha1_block_write(
|
|
|
|
sha1_block *blk, const void **vdata, size_t *len)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2019-01-20 18:44:26 +00:00
|
|
|
size_t blkleft = sizeof(blk->block) - blk->used;
|
|
|
|
size_t chunk = *len < blkleft ? *len : blkleft;
|
|
|
|
|
|
|
|
const uint8_t *p = *vdata;
|
|
|
|
memcpy(blk->block + blk->used, p, chunk);
|
|
|
|
*vdata = p + chunk;
|
|
|
|
*len -= chunk;
|
|
|
|
blk->used += chunk;
|
|
|
|
blk->len += chunk;
|
|
|
|
|
|
|
|
if (blk->used == sizeof(blk->block)) {
|
|
|
|
blk->used = 0;
|
|
|
|
return true;
|
2013-07-19 17:44:58 +00:00
|
|
|
}
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
return false;
|
|
|
|
}
|
1999-12-03 11:32:50 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static inline void sha1_block_pad(sha1_block *blk, BinarySink *bs)
|
|
|
|
{
|
|
|
|
uint64_t final_len = blk->len << 3;
|
|
|
|
size_t pad = 1 + (63 & (55 - blk->used));
|
1999-12-03 11:32:50 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
put_byte(bs, 0x80);
|
|
|
|
for (size_t i = 1; i < pad; i++)
|
|
|
|
put_byte(bs, 0);
|
|
|
|
put_uint64(bs, final_len);
|
1999-12-03 11:32:50 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
assert(blk->used == 0 && "Should have exactly hit a block boundary");
|
1999-01-08 13:02:13 +00:00
|
|
|
}
|
2000-09-05 14:28:17 +00:00
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
2019-01-20 18:44:26 +00:00
|
|
|
* Software implementation of SHA-1.
|
2000-09-05 14:28:17 +00:00
|
|
|
*/
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static inline uint32_t rol(uint32_t x, unsigned y)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2019-01-20 18:44:26 +00:00
|
|
|
return (x << (31 & y)) | (x >> (31 & -y));
|
2000-09-05 14:28:17 +00:00
|
|
|
}
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static inline uint32_t Ch(uint32_t ctrl, uint32_t if1, uint32_t if0)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2019-01-20 18:44:26 +00:00
|
|
|
return if0 ^ (ctrl & (if1 ^ if0));
|
|
|
|
}
|
2018-10-26 22:08:58 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static inline uint32_t Maj(uint32_t x, uint32_t y, uint32_t z)
|
|
|
|
{
|
|
|
|
return (x & y) | (z & (x | y));
|
2018-02-11 10:40:24 +00:00
|
|
|
}
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static inline uint32_t Par(uint32_t x, uint32_t y, uint32_t z)
|
2018-02-11 10:40:24 +00:00
|
|
|
{
|
2019-01-20 18:44:26 +00:00
|
|
|
return (x ^ y ^ z);
|
2000-09-05 14:28:17 +00:00
|
|
|
}
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static inline void sha1_sw_round(
|
|
|
|
unsigned round_index, const uint32_t *schedule,
|
|
|
|
uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e,
|
|
|
|
uint32_t f, uint32_t constant)
|
2001-05-06 14:35:20 +00:00
|
|
|
{
|
2019-01-20 18:44:26 +00:00
|
|
|
*e = rol(*a, 5) + f + *e + schedule[round_index] + constant;
|
|
|
|
*b = rol(*b, 30);
|
|
|
|
}
|
2000-09-05 14:28:17 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static void sha1_sw_block(uint32_t *core, const uint8_t *block)
|
|
|
|
{
|
|
|
|
uint32_t w[SHA1_ROUNDS];
|
|
|
|
uint32_t a,b,c,d,e;
|
2000-09-05 14:28:17 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
for (size_t t = 0; t < 16; t++)
|
|
|
|
w[t] = GET_32BIT_MSB_FIRST(block + 4*t);
|
2000-09-05 14:28:17 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
for (size_t t = 16; t < SHA1_ROUNDS; t++)
|
|
|
|
w[t] = rol(w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16], 1);
|
2000-09-05 14:28:17 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
a = core[0]; b = core[1]; c = core[2]; d = core[3];
|
|
|
|
e = core[4];
|
2000-09-05 14:28:17 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
size_t t = 0;
|
|
|
|
for (size_t u = 0; u < SHA1_ROUNDS_PER_STAGE/5; u++) {
|
|
|
|
sha1_sw_round(t++,w, &a,&b,&c,&d,&e, Ch(b,c,d), SHA1_STAGE0_CONSTANT);
|
|
|
|
sha1_sw_round(t++,w, &e,&a,&b,&c,&d, Ch(a,b,c), SHA1_STAGE0_CONSTANT);
|
|
|
|
sha1_sw_round(t++,w, &d,&e,&a,&b,&c, Ch(e,a,b), SHA1_STAGE0_CONSTANT);
|
|
|
|
sha1_sw_round(t++,w, &c,&d,&e,&a,&b, Ch(d,e,a), SHA1_STAGE0_CONSTANT);
|
|
|
|
sha1_sw_round(t++,w, &b,&c,&d,&e,&a, Ch(c,d,e), SHA1_STAGE0_CONSTANT);
|
|
|
|
}
|
|
|
|
for (size_t u = 0; u < SHA1_ROUNDS_PER_STAGE/5; u++) {
|
|
|
|
sha1_sw_round(t++,w, &a,&b,&c,&d,&e, Par(b,c,d), SHA1_STAGE1_CONSTANT);
|
|
|
|
sha1_sw_round(t++,w, &e,&a,&b,&c,&d, Par(a,b,c), SHA1_STAGE1_CONSTANT);
|
|
|
|
sha1_sw_round(t++,w, &d,&e,&a,&b,&c, Par(e,a,b), SHA1_STAGE1_CONSTANT);
|
|
|
|
sha1_sw_round(t++,w, &c,&d,&e,&a,&b, Par(d,e,a), SHA1_STAGE1_CONSTANT);
|
|
|
|
sha1_sw_round(t++,w, &b,&c,&d,&e,&a, Par(c,d,e), SHA1_STAGE1_CONSTANT);
|
|
|
|
}
|
|
|
|
for (size_t u = 0; u < SHA1_ROUNDS_PER_STAGE/5; u++) {
|
|
|
|
sha1_sw_round(t++,w, &a,&b,&c,&d,&e, Maj(b,c,d), SHA1_STAGE2_CONSTANT);
|
|
|
|
sha1_sw_round(t++,w, &e,&a,&b,&c,&d, Maj(a,b,c), SHA1_STAGE2_CONSTANT);
|
|
|
|
sha1_sw_round(t++,w, &d,&e,&a,&b,&c, Maj(e,a,b), SHA1_STAGE2_CONSTANT);
|
|
|
|
sha1_sw_round(t++,w, &c,&d,&e,&a,&b, Maj(d,e,a), SHA1_STAGE2_CONSTANT);
|
|
|
|
sha1_sw_round(t++,w, &b,&c,&d,&e,&a, Maj(c,d,e), SHA1_STAGE2_CONSTANT);
|
|
|
|
}
|
|
|
|
for (size_t u = 0; u < SHA1_ROUNDS_PER_STAGE/5; u++) {
|
|
|
|
sha1_sw_round(t++,w, &a,&b,&c,&d,&e, Par(b,c,d), SHA1_STAGE3_CONSTANT);
|
|
|
|
sha1_sw_round(t++,w, &e,&a,&b,&c,&d, Par(a,b,c), SHA1_STAGE3_CONSTANT);
|
|
|
|
sha1_sw_round(t++,w, &d,&e,&a,&b,&c, Par(e,a,b), SHA1_STAGE3_CONSTANT);
|
|
|
|
sha1_sw_round(t++,w, &c,&d,&e,&a,&b, Par(d,e,a), SHA1_STAGE3_CONSTANT);
|
|
|
|
sha1_sw_round(t++,w, &b,&c,&d,&e,&a, Par(c,d,e), SHA1_STAGE3_CONSTANT);
|
2000-09-05 14:28:17 +00:00
|
|
|
}
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
core[0] += a; core[1] += b; core[2] += c; core[3] += d; core[4] += e;
|
2000-09-05 14:28:17 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
smemclr(w, sizeof(w));
|
2000-09-05 14:28:17 +00:00
|
|
|
}
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
typedef struct sha1_sw {
|
|
|
|
uint32_t core[5];
|
|
|
|
sha1_block blk;
|
|
|
|
BinarySink_IMPLEMENTATION;
|
2018-09-13 15:41:46 +00:00
|
|
|
ssh_hash hash;
|
2019-01-20 18:44:26 +00:00
|
|
|
} sha1_sw;
|
|
|
|
|
|
|
|
static void sha1_sw_write(BinarySink *bs, const void *vp, size_t len);
|
2005-08-31 20:43:06 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static ssh_hash *sha1_sw_new(const ssh_hashalg *alg)
|
2018-09-13 15:41:46 +00:00
|
|
|
{
|
2019-01-20 18:44:26 +00:00
|
|
|
sha1_sw *s = snew(sha1_sw);
|
|
|
|
|
|
|
|
memcpy(s->core, sha1_initial_state, sizeof(s->core));
|
|
|
|
|
|
|
|
sha1_block_setup(&s->blk);
|
|
|
|
|
|
|
|
s->hash.vt = alg;
|
|
|
|
BinarySink_INIT(s, sha1_sw_write);
|
|
|
|
BinarySink_DELEGATE_INIT(&s->hash, s);
|
|
|
|
return &s->hash;
|
2005-08-31 20:43:06 +00:00
|
|
|
}
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static ssh_hash *sha1_sw_copy(ssh_hash *hash)
|
2015-08-21 22:13:59 +00:00
|
|
|
{
|
2019-01-20 18:44:26 +00:00
|
|
|
sha1_sw *s = container_of(hash, sha1_sw, hash);
|
|
|
|
sha1_sw *copy = snew(sha1_sw);
|
|
|
|
|
|
|
|
memcpy(copy, s, sizeof(*copy));
|
|
|
|
BinarySink_COPIED(copy);
|
|
|
|
BinarySink_DELEGATE_INIT(©->hash, copy);
|
2015-08-21 22:13:59 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
return ©->hash;
|
|
|
|
}
|
2015-08-21 22:13:59 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static void sha1_sw_free(ssh_hash *hash)
|
|
|
|
{
|
|
|
|
sha1_sw *s = container_of(hash, sha1_sw, hash);
|
2015-08-21 22:13:59 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
smemclr(s, sizeof(*s));
|
|
|
|
sfree(s);
|
2015-08-21 22:13:59 +00:00
|
|
|
}
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static void sha1_sw_write(BinarySink *bs, const void *vp, size_t len)
|
2005-08-31 20:43:06 +00:00
|
|
|
{
|
2019-01-20 18:44:26 +00:00
|
|
|
sha1_sw *s = BinarySink_DOWNCAST(bs, sha1_sw);
|
2018-09-13 15:41:46 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
while (len > 0)
|
|
|
|
if (sha1_block_write(&s->blk, &vp, &len))
|
|
|
|
sha1_sw_block(s->core, s->blk.block);
|
2005-08-31 20:43:06 +00:00
|
|
|
}
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static void sha1_sw_final(ssh_hash *hash, uint8_t *digest)
|
2005-08-31 20:43:06 +00:00
|
|
|
{
|
2019-01-20 18:44:26 +00:00
|
|
|
sha1_sw *s = container_of(hash, sha1_sw, hash);
|
|
|
|
|
|
|
|
sha1_block_pad(&s->blk, BinarySink_UPCAST(s));
|
|
|
|
for (size_t i = 0; i < 5; i++)
|
|
|
|
PUT_32BIT_MSB_FIRST(digest + 4*i, s->core[i]);
|
|
|
|
sha1_sw_free(hash);
|
2005-08-31 20:43:06 +00:00
|
|
|
}
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
const ssh_hashalg ssh_sha1_sw = {
|
|
|
|
sha1_sw_new, sha1_sw_copy, sha1_sw_final, sha1_sw_free,
|
|
|
|
20, 64, "SHA-1",
|
2005-08-31 20:43:06 +00:00
|
|
|
};
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* Hardware-accelerated implementation of SHA-1 using x86 SHA-NI.
|
|
|
|
*/
|
2018-02-18 21:06:14 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
#if HW_SHA1 == HW_SHA1_NI
|
2018-04-13 03:20:52 +00:00
|
|
|
|
2018-02-18 21:06:14 +00:00
|
|
|
/*
|
|
|
|
* Set target architecture for Clang and GCC
|
|
|
|
*/
|
|
|
|
#if !defined(__clang__) && defined(__GNUC__)
|
|
|
|
# pragma GCC target("sha")
|
|
|
|
# pragma GCC target("sse4.1")
|
|
|
|
#endif
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))
|
2018-02-18 21:06:14 +00:00
|
|
|
# define FUNC_ISA __attribute__ ((target("sse4.1,sha")))
|
|
|
|
#else
|
|
|
|
# define FUNC_ISA
|
|
|
|
#endif
|
|
|
|
|
2018-02-18 21:07:06 +00:00
|
|
|
#include <wmmintrin.h>
|
|
|
|
#include <smmintrin.h>
|
|
|
|
#include <immintrin.h>
|
|
|
|
#if defined(__clang__) || defined(__GNUC__)
|
|
|
|
#include <shaintrin.h>
|
|
|
|
#endif
|
|
|
|
|
2018-02-18 21:06:14 +00:00
|
|
|
#if defined(__clang__) || defined(__GNUC__)
|
|
|
|
#include <cpuid.h>
|
2019-01-20 18:44:26 +00:00
|
|
|
#define GET_CPU_ID_0(out) \
|
|
|
|
__cpuid(0, (out)[0], (out)[1], (out)[2], (out)[3])
|
|
|
|
#define GET_CPU_ID_7(out) \
|
|
|
|
__cpuid_count(7, 0, (out)[0], (out)[1], (out)[2], (out)[3])
|
|
|
|
#else
|
|
|
|
#define GET_CPU_ID_0(out) __cpuid(out, 0)
|
|
|
|
#define GET_CPU_ID_7(out) __cpuidex(out, 7, 0)
|
|
|
|
#endif
|
2018-02-18 21:06:14 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static bool sha1_hw_available(void)
|
2018-02-18 21:06:14 +00:00
|
|
|
{
|
|
|
|
unsigned int CPUInfo[4];
|
2019-01-20 18:44:26 +00:00
|
|
|
GET_CPU_ID_0(CPUInfo);
|
2018-03-22 18:57:38 +00:00
|
|
|
if (CPUInfo[0] < 7)
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
return false;
|
2018-03-22 18:57:38 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
GET_CPU_ID_7(CPUInfo);
|
2018-02-18 21:06:14 +00:00
|
|
|
return CPUInfo[1] & (1 << 29); /* Check SHA */
|
|
|
|
}
|
|
|
|
|
2018-02-18 21:07:06 +00:00
|
|
|
/* SHA1 implementation using new instructions
|
|
|
|
The code is based on Jeffrey Walton's SHA1 implementation:
|
|
|
|
https://github.com/noloader/SHA-Intrinsics
|
|
|
|
*/
|
|
|
|
FUNC_ISA
|
2019-01-20 18:44:26 +00:00
|
|
|
static inline void sha1_ni_block(__m128i *core, const uint8_t *p)
|
2018-02-18 21:07:06 +00:00
|
|
|
{
|
2019-01-20 18:44:26 +00:00
|
|
|
__m128i ABCD, E0, E1, MSG0, MSG1, MSG2, MSG3;
|
|
|
|
const __m128i MASK = _mm_set_epi64x(
|
|
|
|
0x0001020304050607ULL, 0x08090a0b0c0d0e0fULL);
|
|
|
|
|
|
|
|
const __m128i *block = (const __m128i *)p;
|
|
|
|
|
|
|
|
/* Load initial values */
|
|
|
|
ABCD = core[0];
|
|
|
|
E0 = core[1];
|
|
|
|
|
|
|
|
/* Rounds 0-3 */
|
|
|
|
MSG0 = _mm_loadu_si128(block);
|
|
|
|
MSG0 = _mm_shuffle_epi8(MSG0, MASK);
|
|
|
|
E0 = _mm_add_epi32(E0, MSG0);
|
|
|
|
E1 = ABCD;
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0);
|
|
|
|
|
|
|
|
/* Rounds 4-7 */
|
|
|
|
MSG1 = _mm_loadu_si128(block + 1);
|
|
|
|
MSG1 = _mm_shuffle_epi8(MSG1, MASK);
|
|
|
|
E1 = _mm_sha1nexte_epu32(E1, MSG1);
|
|
|
|
E0 = ABCD;
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 0);
|
|
|
|
MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1);
|
|
|
|
|
|
|
|
/* Rounds 8-11 */
|
|
|
|
MSG2 = _mm_loadu_si128(block + 2);
|
|
|
|
MSG2 = _mm_shuffle_epi8(MSG2, MASK);
|
|
|
|
E0 = _mm_sha1nexte_epu32(E0, MSG2);
|
|
|
|
E1 = ABCD;
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0);
|
|
|
|
MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2);
|
|
|
|
MSG0 = _mm_xor_si128(MSG0, MSG2);
|
|
|
|
|
|
|
|
/* Rounds 12-15 */
|
|
|
|
MSG3 = _mm_loadu_si128(block + 3);
|
|
|
|
MSG3 = _mm_shuffle_epi8(MSG3, MASK);
|
|
|
|
E1 = _mm_sha1nexte_epu32(E1, MSG3);
|
|
|
|
E0 = ABCD;
|
|
|
|
MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3);
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 0);
|
|
|
|
MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3);
|
|
|
|
MSG1 = _mm_xor_si128(MSG1, MSG3);
|
|
|
|
|
|
|
|
/* Rounds 16-19 */
|
|
|
|
E0 = _mm_sha1nexte_epu32(E0, MSG0);
|
|
|
|
E1 = ABCD;
|
|
|
|
MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0);
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0);
|
|
|
|
MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0);
|
|
|
|
MSG2 = _mm_xor_si128(MSG2, MSG0);
|
|
|
|
|
|
|
|
/* Rounds 20-23 */
|
|
|
|
E1 = _mm_sha1nexte_epu32(E1, MSG1);
|
|
|
|
E0 = ABCD;
|
|
|
|
MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1);
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1);
|
|
|
|
MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1);
|
|
|
|
MSG3 = _mm_xor_si128(MSG3, MSG1);
|
|
|
|
|
|
|
|
/* Rounds 24-27 */
|
|
|
|
E0 = _mm_sha1nexte_epu32(E0, MSG2);
|
|
|
|
E1 = ABCD;
|
|
|
|
MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2);
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 1);
|
|
|
|
MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2);
|
|
|
|
MSG0 = _mm_xor_si128(MSG0, MSG2);
|
|
|
|
|
|
|
|
/* Rounds 28-31 */
|
|
|
|
E1 = _mm_sha1nexte_epu32(E1, MSG3);
|
|
|
|
E0 = ABCD;
|
|
|
|
MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3);
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1);
|
|
|
|
MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3);
|
|
|
|
MSG1 = _mm_xor_si128(MSG1, MSG3);
|
|
|
|
|
|
|
|
/* Rounds 32-35 */
|
|
|
|
E0 = _mm_sha1nexte_epu32(E0, MSG0);
|
|
|
|
E1 = ABCD;
|
|
|
|
MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0);
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 1);
|
|
|
|
MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0);
|
|
|
|
MSG2 = _mm_xor_si128(MSG2, MSG0);
|
|
|
|
|
|
|
|
/* Rounds 36-39 */
|
|
|
|
E1 = _mm_sha1nexte_epu32(E1, MSG1);
|
|
|
|
E0 = ABCD;
|
|
|
|
MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1);
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1);
|
|
|
|
MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1);
|
|
|
|
MSG3 = _mm_xor_si128(MSG3, MSG1);
|
|
|
|
|
|
|
|
/* Rounds 40-43 */
|
|
|
|
E0 = _mm_sha1nexte_epu32(E0, MSG2);
|
|
|
|
E1 = ABCD;
|
|
|
|
MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2);
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2);
|
|
|
|
MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2);
|
|
|
|
MSG0 = _mm_xor_si128(MSG0, MSG2);
|
|
|
|
|
|
|
|
/* Rounds 44-47 */
|
|
|
|
E1 = _mm_sha1nexte_epu32(E1, MSG3);
|
|
|
|
E0 = ABCD;
|
|
|
|
MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3);
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 2);
|
|
|
|
MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3);
|
|
|
|
MSG1 = _mm_xor_si128(MSG1, MSG3);
|
|
|
|
|
|
|
|
/* Rounds 48-51 */
|
|
|
|
E0 = _mm_sha1nexte_epu32(E0, MSG0);
|
|
|
|
E1 = ABCD;
|
|
|
|
MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0);
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2);
|
|
|
|
MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0);
|
|
|
|
MSG2 = _mm_xor_si128(MSG2, MSG0);
|
|
|
|
|
|
|
|
/* Rounds 52-55 */
|
|
|
|
E1 = _mm_sha1nexte_epu32(E1, MSG1);
|
|
|
|
E0 = ABCD;
|
|
|
|
MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1);
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 2);
|
|
|
|
MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1);
|
|
|
|
MSG3 = _mm_xor_si128(MSG3, MSG1);
|
|
|
|
|
|
|
|
/* Rounds 56-59 */
|
|
|
|
E0 = _mm_sha1nexte_epu32(E0, MSG2);
|
|
|
|
E1 = ABCD;
|
|
|
|
MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2);
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2);
|
|
|
|
MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2);
|
|
|
|
MSG0 = _mm_xor_si128(MSG0, MSG2);
|
|
|
|
|
|
|
|
/* Rounds 60-63 */
|
|
|
|
E1 = _mm_sha1nexte_epu32(E1, MSG3);
|
|
|
|
E0 = ABCD;
|
|
|
|
MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3);
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3);
|
|
|
|
MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3);
|
|
|
|
MSG1 = _mm_xor_si128(MSG1, MSG3);
|
|
|
|
|
|
|
|
/* Rounds 64-67 */
|
|
|
|
E0 = _mm_sha1nexte_epu32(E0, MSG0);
|
|
|
|
E1 = ABCD;
|
|
|
|
MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0);
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 3);
|
|
|
|
MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0);
|
|
|
|
MSG2 = _mm_xor_si128(MSG2, MSG0);
|
|
|
|
|
|
|
|
/* Rounds 68-71 */
|
|
|
|
E1 = _mm_sha1nexte_epu32(E1, MSG1);
|
|
|
|
E0 = ABCD;
|
|
|
|
MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1);
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3);
|
|
|
|
MSG3 = _mm_xor_si128(MSG3, MSG1);
|
|
|
|
|
|
|
|
/* Rounds 72-75 */
|
|
|
|
E0 = _mm_sha1nexte_epu32(E0, MSG2);
|
|
|
|
E1 = ABCD;
|
|
|
|
MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2);
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 3);
|
|
|
|
|
|
|
|
/* Rounds 76-79 */
|
|
|
|
E1 = _mm_sha1nexte_epu32(E1, MSG3);
|
|
|
|
E0 = ABCD;
|
|
|
|
ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3);
|
|
|
|
|
|
|
|
/* Combine state */
|
|
|
|
core[0] = _mm_add_epi32(ABCD, core[0]);
|
|
|
|
core[1] = _mm_sha1nexte_epu32(E0, core[1]);
|
2018-02-18 21:07:06 +00:00
|
|
|
}
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
typedef struct sha1_ni {
|
|
|
|
/*
|
|
|
|
* core[0] stores the first four words of the SHA-1 state. core[1]
|
|
|
|
* stores just the fifth word, in the vector lane at the highest
|
|
|
|
* address.
|
|
|
|
*/
|
|
|
|
__m128i core[2];
|
|
|
|
sha1_block blk;
|
|
|
|
void *pointer_to_free;
|
|
|
|
BinarySink_IMPLEMENTATION;
|
|
|
|
ssh_hash hash;
|
|
|
|
} sha1_ni;
|
|
|
|
|
|
|
|
static void sha1_ni_write(BinarySink *bs, const void *vp, size_t len);
|
|
|
|
|
|
|
|
static sha1_ni *sha1_ni_alloc(void)
|
2018-02-18 13:48:44 +00:00
|
|
|
{
|
2019-01-20 18:44:26 +00:00
|
|
|
/*
|
|
|
|
* The __m128i variables in the context structure need to be
|
|
|
|
* 16-byte aligned, but not all malloc implementations that this
|
|
|
|
* code has to work with will guarantee to return a 16-byte
|
|
|
|
* aligned pointer. So we over-allocate, manually realign the
|
|
|
|
* pointer ourselves, and store the original one inside the
|
|
|
|
* context so we know how to free it later.
|
|
|
|
*/
|
|
|
|
void *allocation = smalloc(sizeof(sha1_ni) + 15);
|
|
|
|
uintptr_t alloc_address = (uintptr_t)allocation;
|
|
|
|
uintptr_t aligned_address = (alloc_address + 15) & ~15;
|
|
|
|
sha1_ni *s = (sha1_ni *)aligned_address;
|
|
|
|
s->pointer_to_free = allocation;
|
|
|
|
return s;
|
2018-02-18 13:48:44 +00:00
|
|
|
}
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
FUNC_ISA static ssh_hash *sha1_ni_new(const ssh_hashalg *alg)
|
|
|
|
{
|
|
|
|
if (!sha1_hw_available_cached())
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
sha1_ni *s = sha1_ni_alloc();
|
|
|
|
|
|
|
|
/* Initialise the core vectors in their storage order */
|
|
|
|
s->core[0] = _mm_set_epi64x(
|
|
|
|
0x67452301efcdab89ULL, 0x98badcfe10325476ULL);
|
|
|
|
s->core[1] = _mm_set_epi32(0xc3d2e1f0, 0, 0, 0);
|
|
|
|
|
|
|
|
sha1_block_setup(&s->blk);
|
|
|
|
|
|
|
|
s->hash.vt = alg;
|
|
|
|
BinarySink_INIT(s, sha1_ni_write);
|
|
|
|
BinarySink_DELEGATE_INIT(&s->hash, s);
|
|
|
|
return &s->hash;
|
|
|
|
}
|
2018-02-18 21:06:14 +00:00
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static ssh_hash *sha1_ni_copy(ssh_hash *hash)
|
2018-02-18 21:07:06 +00:00
|
|
|
{
|
2019-01-20 18:44:26 +00:00
|
|
|
sha1_ni *s = container_of(hash, sha1_ni, hash);
|
|
|
|
sha1_ni *copy = sha1_ni_alloc();
|
|
|
|
|
|
|
|
void *ptf_save = copy->pointer_to_free;
|
|
|
|
*copy = *s; /* structure copy */
|
|
|
|
copy->pointer_to_free = ptf_save;
|
|
|
|
|
|
|
|
BinarySink_COPIED(copy);
|
|
|
|
BinarySink_DELEGATE_INIT(©->hash, copy);
|
|
|
|
|
|
|
|
return ©->hash;
|
2018-02-18 21:07:06 +00:00
|
|
|
}
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static void sha1_ni_free(ssh_hash *hash)
|
|
|
|
{
|
|
|
|
sha1_ni *s = container_of(hash, sha1_ni, hash);
|
|
|
|
|
|
|
|
void *ptf = s->pointer_to_free;
|
|
|
|
smemclr(s, sizeof(*s));
|
|
|
|
sfree(ptf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sha1_ni_write(BinarySink *bs, const void *vp, size_t len)
|
|
|
|
{
|
|
|
|
sha1_ni *s = BinarySink_DOWNCAST(bs, sha1_ni);
|
|
|
|
|
|
|
|
while (len > 0)
|
|
|
|
if (sha1_block_write(&s->blk, &vp, &len))
|
|
|
|
sha1_ni_block(s->core, s->blk.block);
|
|
|
|
}
|
|
|
|
|
|
|
|
FUNC_ISA static void sha1_ni_final(ssh_hash *hash, uint8_t *digest)
|
|
|
|
{
|
|
|
|
sha1_ni *s = container_of(hash, sha1_ni, hash);
|
|
|
|
|
|
|
|
sha1_block_pad(&s->blk, BinarySink_UPCAST(s));
|
|
|
|
|
|
|
|
/* Rearrange the first vector into its output order */
|
|
|
|
__m128i abcd = _mm_shuffle_epi32(s->core[0], 0x1B);
|
|
|
|
|
|
|
|
/* Byte-swap it into the output endianness */
|
|
|
|
const __m128i mask = _mm_setr_epi8(3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12);
|
|
|
|
abcd = _mm_shuffle_epi8(abcd, mask);
|
|
|
|
|
|
|
|
/* And store it */
|
|
|
|
_mm_storeu_si128((__m128i *)digest, abcd);
|
|
|
|
|
|
|
|
/* Finally, store the leftover word */
|
|
|
|
uint32_t e = _mm_extract_epi32(s->core[1], 3);
|
|
|
|
PUT_32BIT_MSB_FIRST(digest + 16, e);
|
|
|
|
|
|
|
|
sha1_ni_free(hash);
|
|
|
|
}
|
|
|
|
|
|
|
|
const ssh_hashalg ssh_sha1_hw = {
|
|
|
|
sha1_ni_new, sha1_ni_copy, sha1_ni_final, sha1_ni_free,
|
|
|
|
20, 64, "SHA-1",
|
|
|
|
};
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------
|
|
|
|
* Stub functions if we have no hardware-accelerated SHA-1. In this
|
|
|
|
* case, sha1_hw_new returns NULL (though it should also never be
|
|
|
|
* selected by sha1_select, so the only thing that should even be
|
|
|
|
* _able_ to call it is testcrypt). As a result, the remaining vtable
|
|
|
|
* functions should never be called at all.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#elif HW_SHA1 == HW_SHA1_NONE
|
|
|
|
|
|
|
|
static bool sha1_hw_available(void)
|
2018-02-18 21:06:14 +00:00
|
|
|
{
|
Convert a lot of 'int' variables to 'bool'.
My normal habit these days, in new code, is to treat int and bool as
_almost_ completely separate types. I'm still willing to use C's
implicit test for zero on an integer (e.g. 'if (!blob.len)' is fine,
no need to spell it out as blob.len != 0), but generally, if a
variable is going to be conceptually a boolean, I like to declare it
bool and assign to it using 'true' or 'false' rather than 0 or 1.
PuTTY is an exception, because it predates the C99 bool, and I've
stuck to its existing coding style even when adding new code to it.
But it's been annoying me more and more, so now that I've decided C99
bool is an acceptable thing to require from our toolchain in the first
place, here's a quite thorough trawl through the source doing
'boolification'. Many variables and function parameters are now typed
as bool rather than int; many assignments of 0 or 1 to those variables
are now spelled 'true' or 'false'.
I managed this thorough conversion with the help of a custom clang
plugin that I wrote to trawl the AST and apply heuristics to point out
where things might want changing. So I've even managed to do a decent
job on parts of the code I haven't looked at in years!
To make the plugin's work easier, I pushed platform front ends
generally in the direction of using standard 'bool' in preference to
platform-specific boolean types like Windows BOOL or GTK's gboolean;
I've left the platform booleans in places they _have_ to be for the
platform APIs to work right, but variables only used by my own code
have been converted wherever I found them.
In a few places there are int values that look very like booleans in
_most_ of the places they're used, but have a rarely-used third value,
or a distinction between different nonzero values that most users
don't care about. In these cases, I've _removed_ uses of 'true' and
'false' for the return values, to emphasise that there's something
more subtle going on than a simple boolean answer:
- the 'multisel' field in dialog.h's list box structure, for which
the GTK front end in particular recognises a difference between 1
and 2 but nearly everything else treats as boolean
- the 'urgent' parameter to plug_receive, where 1 vs 2 tells you
something about the specific location of the urgent pointer, but
most clients only care about 0 vs 'something nonzero'
- the return value of wc_match, where -1 indicates a syntax error in
the wildcard.
- the return values from SSH-1 RSA-key loading functions, which use
-1 for 'wrong passphrase' and 0 for all other failures (so any
caller which already knows it's not loading an _encrypted private_
key can treat them as boolean)
- term->esc_query, and the 'query' parameter in toggle_mode in
terminal.c, which _usually_ hold 0 for ESC[123h or 1 for ESC[?123h,
but can also hold -1 for some other intervening character that we
don't support.
In a few places there's an integer that I haven't turned into a bool
even though it really _can_ only take values 0 or 1 (and, as above,
tried to make the call sites consistent in not calling those values
true and false), on the grounds that I thought it would make it more
confusing to imply that the 0 value was in some sense 'negative' or
bad and the 1 positive or good:
- the return value of plug_accepting uses the POSIXish convention of
0=success and nonzero=error; I think if I made it bool then I'd
also want to reverse its sense, and that's a job for a separate
piece of work.
- the 'screen' parameter to lineptr() in terminal.c, where 0 and 1
represent the default and alternate screens. There's no obvious
reason why one of those should be considered 'true' or 'positive'
or 'success' - they're just indices - so I've left it as int.
ssh_scp_recv had particularly confusing semantics for its previous int
return value: its call sites used '<= 0' to check for error, but it
never actually returned a negative number, just 0 or 1. Now the
function and its call sites agree that it's a bool.
In a couple of places I've renamed variables called 'ret', because I
don't like that name any more - it's unclear whether it means the
return value (in preparation) for the _containing_ function or the
return value received from a subroutine call, and occasionally I've
accidentally used the same variable for both and introduced a bug. So
where one of those got in my way, I've renamed it to 'toret' or 'retd'
(the latter short for 'returned') in line with my usual modern
practice, but I haven't done a thorough job of finding all of them.
Finally, one amusing side effect of doing this is that I've had to
separate quite a few chained assignments. It used to be perfectly fine
to write 'a = b = c = TRUE' when a,b,c were int and TRUE was just a
the 'true' defined by stdbool.h, that idiom provokes a warning from
gcc: 'suggest parentheses around assignment used as truth value'!
2018-11-02 19:23:19 +00:00
|
|
|
return false;
|
2018-02-18 21:06:14 +00:00
|
|
|
}
|
|
|
|
|
2019-01-20 18:44:26 +00:00
|
|
|
static ssh_hash *sha1_stub_new(const ssh_hashalg *alg)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define STUB_BODY { unreachable("Should never be called"); }
|
|
|
|
|
|
|
|
static ssh_hash *sha1_stub_copy(ssh_hash *hash) STUB_BODY
|
|
|
|
static void sha1_stub_free(ssh_hash *hash) STUB_BODY
|
|
|
|
static void sha1_stub_final(ssh_hash *hash, uint8_t *digest) STUB_BODY
|
|
|
|
|
|
|
|
const ssh_hashalg ssh_sha1_hw = {
|
|
|
|
sha1_stub_new, sha1_stub_copy, sha1_stub_final, sha1_stub_free,
|
|
|
|
20, 64, "SHA-1",
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* HW_SHA1 */
|