# HG changeset patch # User Matt Johnston # Date 1648611844 -28800 # Node ID 3f4cdf839a1a4ff7a0fa65c1ae52ec89df4eadf1 # Parent 13cb8cc1b0e4eb3af71aeb363ee0487e0bbe56db 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. diff -r 13cb8cc1b0e4 -r 3f4cdf839a1a common-kex.c --- a/common-kex.c Wed Mar 30 10:23:39 2022 +0800 +++ b/common-kex.c Wed Mar 30 11:44:04 2022 +0800 @@ -249,7 +249,7 @@ /* 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 -r 13cb8cc1b0e4 -r 3f4cdf839a1a crypto_desc.c --- a/crypto_desc.c Wed Mar 30 10:23:39 2022 +0800 +++ b/crypto_desc.c Wed Mar 30 11:44:04 2022 +0800 @@ -31,8 +31,9 @@ }; 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 @@ &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 -r 13cb8cc1b0e4 -r 3f4cdf839a1a dbrandom.c --- a/dbrandom.c Wed Mar 30 10:23:39 2022 +0800 +++ b/dbrandom.c Wed Mar 30 11:44:04 2022 +0800 @@ -34,7 +34,7 @@ /* 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 @@ } goto out; } - sha1_process(hs, readbuf, readlen); + sha256_process(hs, readbuf, readlen); readcount += readlen; } ret = DROPBEAR_SUCCESS; @@ -120,13 +120,13 @@ #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 @@ #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 @@ 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 @@ /* 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 @@ #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 @@ #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 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 @@ } 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 -r 13cb8cc1b0e4 -r 3f4cdf839a1a default_options.h --- a/default_options.h Wed Mar 30 10:23:39 2022 +0800 +++ b/default_options.h Wed Mar 30 11:44:04 2022 +0800 @@ -116,7 +116,7 @@ * 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 @@ * 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 -r 13cb8cc1b0e4 -r 3f4cdf839a1a dropbearkey.c --- a/dropbearkey.c Wed Mar 30 10:23:39 2022 +0800 +++ b/dropbearkey.c Wed Mar 30 11:44:04 2022 +0800 @@ -341,7 +341,7 @@ 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 -r 13cb8cc1b0e4 -r 3f4cdf839a1a libtomcrypt/src/headers/tomcrypt_dropbear.h --- a/libtomcrypt/src/headers/tomcrypt_dropbear.h Wed Mar 30 10:23:39 2022 +0800 +++ b/libtomcrypt/src/headers/tomcrypt_dropbear.h Wed Mar 30 11:44:04 2022 +0800 @@ -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 -r 13cb8cc1b0e4 -r 3f4cdf839a1a signkey.c --- a/signkey.c Wed Mar 30 10:23:39 2022 +0800 +++ b/signkey.c Wed Mar 30 11:44:04 2022 +0800 @@ -544,98 +544,42 @@ 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, +static char * sign_key_sha256_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; + unsigned char hash[SHA256_HASH_SIZE]; + unsigned int b64chars, start; + unsigned long b64size; + const char *prefix = "SHA256:"; + int err; - md5_init(&hs); - - /* skip the size int of the string - this is a bit messy */ - md5_process(&hs, keyblob, keybloblen); - - md5_done(&hs, hash); + sha256_init(&hs); + sha256_process(&hs, keyblob, keybloblen); + sha256_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 "); + /* 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); - 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] = ':'; + memcpy(ret, prefix, start); + err = base64_encode(hash, SHA256_HASH_SIZE, &ret[start], &b64size); + if (err != CRYPT_OK) { + dropbear_exit("base64 failed"); } - ret[buflen-1] = 0x0; - + ret[start + b64chars] = '\0'; return ret; } -#else /* use SHA1 rather than MD5 for fingerprint */ -static char * sign_key_sha1_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; - - 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 -r 13cb8cc1b0e4 -r 3f4cdf839a1a sysoptions.h --- a/sysoptions.h Wed Mar 30 10:23:39 2022 +0800 +++ b/sysoptions.h Wed Mar 30 11:44:04 2022 +0800 @@ -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) \