changeset 1916:3f4cdf839a1a

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.
author Matt Johnston <matt@ucc.asn.au>
date Wed, 30 Mar 2022 11:44:04 +0800
parents 13cb8cc1b0e4
children f8ed10efaaac
files common-kex.c crypto_desc.c dbrandom.c default_options.h dropbearkey.c libtomcrypt/src/headers/tomcrypt_dropbear.h signkey.c sysoptions.h
diffstat 8 files changed, 62 insertions(+), 120 deletions(-) [+]
line wrap: on
line diff
--- 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, 
--- 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");
--- 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;
--- 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
--- 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);
--- 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
--- 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, 
--- 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) \