From da8ad3ebc94c72f07cf54db540a762095f3deef2 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 30 Mar 2022 11:44:04 +0800 Subject: Make SHA1 optional, implement SHA256 fingerprints SHA256 is always compiled and only enable SHA1 when needed. Fingerprints are always SHA256: base64 format, md5 and sha1 are removed. dbrandom now uses sha256 its hash function. --- common-kex.c | 2 +- crypto_desc.c | 7 +- dbrandom.c | 47 ++++++------ default_options.h | 4 +- dropbearkey.c | 2 +- libtomcrypt/src/headers/tomcrypt_dropbear.h | 8 +- signkey.c | 112 +++++++--------------------- sysoptions.h | 8 +- 8 files changed, 66 insertions(+), 124 deletions(-) diff --git a/common-kex.c b/common-kex.c index 6aaec29..ac88442 100644 --- a/common-kex.c +++ b/common-kex.c @@ -249,7 +249,7 @@ static void kexinitialise() { /* Helper function for gen_new_keys, creates a hash. It makes a copy of the * already initialised hash_state hs, which should already have processed * the dh_K and hash, since these are common. X is the letter 'A', 'B' etc. - * out must have at least min(SHA1_HASH_SIZE, outlen) bytes allocated. + * out must have at least min(hash_size, outlen) bytes allocated. * * See Section 7.2 of rfc4253 (ssh transport) for details */ static void hashkeys(unsigned char *out, unsigned int outlen, diff --git a/crypto_desc.c b/crypto_desc.c index b370728..5e0e960 100644 --- a/crypto_desc.c +++ b/crypto_desc.c @@ -31,8 +31,9 @@ void crypto_init() { }; const struct ltc_hash_descriptor *reghashes[] = { - /* we need sha1 for hostkey stuff regardless */ +#if DROPBEAR_SHA1_HMAC &sha1_desc, +#endif #if DROPBEAR_MD5_HMAC &md5_desc, #endif @@ -46,9 +47,9 @@ void crypto_init() { &sha512_desc, #endif NULL - }; + }; int i; - + for (i = 0; regciphers[i] != NULL; i++) { if (register_cipher(regciphers[i]) == -1) { dropbear_exit("Error registering crypto"); diff --git a/dbrandom.c b/dbrandom.c index 3f21593..755645c 100644 --- a/dbrandom.c +++ b/dbrandom.c @@ -34,7 +34,7 @@ static uint32_t counter = 0; /* the max value for the counter, so it won't integer overflow */ #define MAX_COUNTER (1<<30) -static unsigned char hashpool[SHA1_HASH_SIZE] = {0}; +static unsigned char hashpool[SHA256_HASH_SIZE] = {0}; static int donerandinit = 0; #define INIT_SEED_SIZE 32 /* 256 bits */ @@ -100,7 +100,7 @@ process_file(hash_state *hs, const char *filename, } goto out; } - sha1_process(hs, readbuf, readlen); + sha256_process(hs, readbuf, readlen); readcount += readlen; } ret = DROPBEAR_SUCCESS; @@ -120,13 +120,13 @@ void addrandom(const unsigned char * buf, unsigned int len) #endif /* hash in the new seed data */ - sha1_init(&hs); + sha256_init(&hs); /* existing state (zeroes on startup) */ - sha1_process(&hs, (void*)hashpool, sizeof(hashpool)); + sha256_process(&hs, (void*)hashpool, sizeof(hashpool)); /* new */ - sha1_process(&hs, buf, len); - sha1_done(&hs, hashpool); + sha256_process(&hs, buf, len); + sha256_done(&hs, hashpool); } static void write_urandom() @@ -152,10 +152,10 @@ static void write_urandom() #if DROPBEAR_FUZZ void fuzz_seed(const unsigned char* dat, unsigned int len) { hash_state hs; - sha1_init(&hs); - sha1_process(&hs, "fuzzfuzzfuzz", strlen("fuzzfuzzfuzz")); - sha1_process(&hs, dat, len); - sha1_done(&hs, hashpool); + sha256_init(&hs); + sha256_process(&hs, "fuzzfuzzfuzz", strlen("fuzzfuzzfuzz")); + sha256_process(&hs, dat, len); + sha256_done(&hs, hashpool); counter = 0; donerandinit = 1; } @@ -209,7 +209,7 @@ static int process_getrandom(hash_state *hs) { if (ret == sizeof(buf)) { /* Success, stir in the entropy */ - sha1_process(hs, (void*)buf, sizeof(buf)); + sha256_process(hs, (void*)buf, sizeof(buf)); return DROPBEAR_SUCCESS; } @@ -221,7 +221,6 @@ static int process_getrandom(hash_state *hs) { /* Initialise the prng from /dev/urandom or prngd. This function can * be called multiple times */ void seedrandom() { - hash_state hs; pid_t pid; @@ -236,10 +235,10 @@ void seedrandom() { #endif /* hash in the new seed data */ - sha1_init(&hs); + sha256_init(&hs); /* existing state */ - sha1_process(&hs, (void*)hashpool, sizeof(hashpool)); + sha256_process(&hs, (void*)hashpool, sizeof(hashpool)); #ifdef HAVE_GETRANDOM if (process_getrandom(&hs) == DROPBEAR_SUCCESS) { @@ -289,21 +288,21 @@ void seedrandom() { #endif pid = getpid(); - sha1_process(&hs, (void*)&pid, sizeof(pid)); + sha256_process(&hs, (void*)&pid, sizeof(pid)); /* gettimeofday() doesn't completely fill out struct timeval on OS X (10.8.3), avoid valgrind warnings by clearing it first */ memset(&tv, 0x0, sizeof(tv)); gettimeofday(&tv, NULL); - sha1_process(&hs, (void*)&tv, sizeof(tv)); + sha256_process(&hs, (void*)&tv, sizeof(tv)); clockval = clock(); - sha1_process(&hs, (void*)&clockval, sizeof(clockval)); + sha256_process(&hs, (void*)&clockval, sizeof(clockval)); /* When a private key is read by the client or server it will * be added to the hashpool - see runopts.c */ - sha1_done(&hs, hashpool); + sha256_done(&hs, hashpool); counter = 0; donerandinit = 1; @@ -317,7 +316,7 @@ void seedrandom() { void genrandom(unsigned char* buf, unsigned int len) { hash_state hs; - unsigned char hash[SHA1_HASH_SIZE]; + unsigned char hash[SHA256_HASH_SIZE]; unsigned int copylen; if (!donerandinit) { @@ -325,17 +324,17 @@ void genrandom(unsigned char* buf, unsigned int len) { } while (len > 0) { - sha1_init(&hs); - sha1_process(&hs, (void*)hashpool, sizeof(hashpool)); - sha1_process(&hs, (void*)&counter, sizeof(counter)); - sha1_done(&hs, hash); + sha256_init(&hs); + sha256_process(&hs, (void*)hashpool, sizeof(hashpool)); + sha256_process(&hs, (void*)&counter, sizeof(counter)); + sha256_done(&hs, hash); counter++; if (counter > MAX_COUNTER) { seedrandom(); } - copylen = MIN(len, SHA1_HASH_SIZE); + copylen = MIN(len, SHA256_HASH_SIZE); memcpy(buf, hash, copylen); len -= copylen; buf += copylen; diff --git a/default_options.h b/default_options.h index d9e7ba2..4a5709a 100644 --- a/default_options.h +++ b/default_options.h @@ -116,7 +116,7 @@ IMPORTANT: Some options will require "make clean" after changes */ * Compiling in will add ~6kB to binary size on x86-64 */ #define DROPBEAR_ENABLE_GCM_MODE 0 -/* Message integrity. sha2-256 is recommended as a default, +/* Message integrity. sha2-256 is recommended as a default, sha1 for compatibility */ #define DROPBEAR_SHA1_HMAC 1 #define DROPBEAR_SHA2_256_HMAC 1 @@ -172,7 +172,7 @@ IMPORTANT: Some options will require "make clean" after changes */ * Small systems should generally include either curve25519 or ecdh for performance. * curve25519 is less widely supported but is faster - */ + */ #define DROPBEAR_DH_GROUP14_SHA1 1 #define DROPBEAR_DH_GROUP14_SHA256 1 #define DROPBEAR_DH_GROUP16 0 diff --git a/dropbearkey.c b/dropbearkey.c index 183e58b..fa1ee39 100644 --- a/dropbearkey.c +++ b/dropbearkey.c @@ -341,7 +341,7 @@ static void printpubkey(sign_key * key, int keytype) { err = base64_encode(buf_getptr(buf, len), len, base64key, &base64len); if (err != CRYPT_OK) { - fprintf(stderr, "base64 failed"); + dropbear_exit("base64 failed"); } typestring = signkey_name_from_type(keytype, NULL); diff --git a/libtomcrypt/src/headers/tomcrypt_dropbear.h b/libtomcrypt/src/headers/tomcrypt_dropbear.h index 3e24ea2..46e84fb 100644 --- a/libtomcrypt/src/headers/tomcrypt_dropbear.h +++ b/libtomcrypt/src/headers/tomcrypt_dropbear.h @@ -16,12 +16,6 @@ #if DROPBEAR_AES #define LTC_RIJNDAEL #endif -/* _TABLES tells it to use tables during setup, _SMALL means to use the smaller scheduled key format - * (saves 4KB of ram), _ALL_TABLES enables all tables during setup */ -#if DROPBEAR_TWOFISH -#define LTC_TWOFISH -#define LTC_TWOFISH_SMALL -#endif #if DROPBEAR_3DES #define LTC_DES @@ -56,7 +50,9 @@ #define LTC_SHA256 #endif +#if DROPBEAR_SHA1 #define LTC_SHA1 +#endif #if DROPBEAR_MD5 #define LTC_MD5 diff --git a/signkey.c b/signkey.c index 597ba65..3f145b0 100644 --- a/signkey.c +++ b/signkey.c @@ -544,98 +544,42 @@ void sign_key_free(sign_key *key) { TRACE2(("leave sign_key_free")) } -static char hexdig(unsigned char x) { - if (x > 0xf) - return 'X'; - - if (x < 10) - return '0' + x; - else - return 'a' + x - 10; -} - -/* Since we're not sure if we'll have md5 or sha1, we present both. - * MD5 is used in preference, but sha1 could still be useful */ -#if DROPBEAR_MD5_HMAC -static char * sign_key_md5_fingerprint(const unsigned char* keyblob, - unsigned int keybloblen) { - - char * ret; - hash_state hs; - unsigned char hash[MD5_HASH_SIZE]; - unsigned int i; - unsigned int buflen; - - md5_init(&hs); - - /* skip the size int of the string - this is a bit messy */ - md5_process(&hs, keyblob, keybloblen); - - md5_done(&hs, hash); - - /* "md5 hexfingerprinthere\0", each hex digit is "AB:" etc */ - buflen = 4 + 3*MD5_HASH_SIZE; - ret = (char*)m_malloc(buflen); - - memset(ret, 'Z', buflen); - strcpy(ret, "md5 "); - - for (i = 0; i < MD5_HASH_SIZE; i++) { - unsigned int pos = 4 + i*3; - ret[pos] = hexdig(hash[i] >> 4); - ret[pos+1] = hexdig(hash[i] & 0x0f); - ret[pos+2] = ':'; - } - ret[buflen-1] = 0x0; - - return ret; -} - -#else /* use SHA1 rather than MD5 for fingerprint */ -static char * sign_key_sha1_fingerprint(const unsigned char* keyblob, +static char * sign_key_sha256_fingerprint(const unsigned char* keyblob, unsigned int keybloblen) { char * ret; hash_state hs; - unsigned char hash[SHA1_HASH_SIZE]; - unsigned int i; - unsigned int buflen; - - sha1_init(&hs); - - /* skip the size int of the string - this is a bit messy */ - sha1_process(&hs, keyblob, keybloblen); - - sha1_done(&hs, hash); - - /* "sha1!! hexfingerprinthere\0", each hex digit is "AB:" etc */ - buflen = 7 + 3*SHA1_HASH_SIZE; - ret = (char*)m_malloc(buflen); - - strcpy(ret, "sha1 "); - - for (i = 0; i < SHA1_HASH_SIZE; i++) { - unsigned int pos = 7 + 3*i; - ret[pos] = hexdig(hash[i] >> 4); - ret[pos+1] = hexdig(hash[i] & 0x0f); - ret[pos+2] = ':'; - } - ret[buflen-1] = 0x0; - + unsigned char hash[SHA256_HASH_SIZE]; + unsigned int b64chars, start; + unsigned long b64size; + const char *prefix = "SHA256:"; + int err; + + sha256_init(&hs); + sha256_process(&hs, keyblob, keybloblen); + sha256_done(&hs, hash); + + /* eg "SHA256:P9szN0L2ls6KxkVv7Bppv3asnZCn03rY7Msm/c8+ZgA" + * 256/6 = 42.66 => 43 base64 chars. OpenSSH discards + * base64 padding output. */ + start = strlen(prefix); + b64chars = 43; + /* space for discarded b64 padding and null terminator */ + b64size = b64chars + 4; + ret = m_malloc(start + b64size); + + memcpy(ret, prefix, start); + err = base64_encode(hash, SHA256_HASH_SIZE, &ret[start], &b64size); + if (err != CRYPT_OK) { + dropbear_exit("base64 failed"); + } + ret[start + b64chars] = '\0'; return ret; } -#endif /* MD5/SHA1 switch */ - -/* This will return a freshly malloced string, containing a fingerprint - * in either sha1 or md5 */ +/* This will return a freshly malloced string */ char * sign_key_fingerprint(const unsigned char* keyblob, unsigned int keybloblen) { - -#if DROPBEAR_MD5_HMAC - return sign_key_md5_fingerprint(keyblob, keybloblen); -#else - return sign_key_sha1_fingerprint(keyblob, keybloblen); -#endif + return sign_key_sha256_fingerprint(keyblob, keybloblen); } void buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype, diff --git a/sysoptions.h b/sysoptions.h index 3267d95..6c164f7 100644 --- a/sysoptions.h +++ b/sysoptions.h @@ -157,9 +157,11 @@ #endif /* hashes which will be linked and registered */ -#define DROPBEAR_SHA256 ((DROPBEAR_SHA2_256_HMAC) || (DROPBEAR_ECC_256) \ - || (DROPBEAR_CURVE25519) || (DROPBEAR_DH_GROUP14_SHA256) \ - || (DROPBEAR_RSA_SHA256)) +#define DROPBEAR_SHA1 (DROPBEAR_RSA_SHA1 || DROPBEAR_DSS \ + || DROPBEAR_SHA1_HMAC || DROPBEAR_SHA1_96_HMAC \ + || DROPBEAR_DH_GROUP1 || DROPBEAR_DH_GROUP14_SHA1 ) +/* sha256 is always used for fingerprints and dbrandom */ +#define DROPBEAR_SHA256 1 #define DROPBEAR_SHA384 (DROPBEAR_ECC_384) /* LTC SHA384 depends on SHA512 */ #define DROPBEAR_SHA512 ((DROPBEAR_SHA2_512_HMAC) || (DROPBEAR_ECC_521) \ -- cgit v1.2.1