[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[PATCH] libdpkg: Use OpenSSL for hashing.



This a quick hack to get some feedback regarding this change: Use
OpenSSL crypto library for hashing instead of libmd.
OpenSSL provides a slightly assembly optimized version for amd64 while
libmd is pure C. This passes the testsuite and I was able to perform an
upgrade so it can't be that bad ;) If I read this right, the checksum is
computed during package installation.
Would it be acceptable to to switch it?

While at it, why do we use md5? I'm asking because a small upgrade to
sha1 would improve the performance since sha1 performs better on
architectures that provide optimisation for it which includes a lot.
_If_ we are changing things here then we could decide if something like
checksum (e.g. xxhash) is enough to catch a bitflip or if a
cryptographic checksum is really required.

I don't know _why_ we have it: The .deb file was verified by apt after
the download, the decompressor has also a checksum.
The md5sum file isn't signed in any way, so whoever modified the binary
in the system could update md5sum file in case it is verified later.

Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
---
 configure.ac      |   6 ++-
 debian/control    |   3 +-
 lib/dpkg/buffer.c | 110 ++++++++++++++++++++++++++++++++++++++++------
 3 files changed, 103 insertions(+), 16 deletions(-)

diff --git a/configure.ac b/configure.ac
index afc6d2bf7e0bc..72458d50586b8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -96,7 +96,11 @@ AC_SYS_LARGEFILE
 
 # Checks for libraries.
 DPKG_LIB_RT
-DPKG_LIB_MD
+#DPKG_LIB_MD
+AC_ARG_VAR([MD_LIBS], [linker flags for md library])
+MD_LIBS=-lcrypto
+have_libmd=openssl
+AC_SEARCH_LIBS([EVP_MD_fetch], [crypto])
 DPKG_LIB_Z
 DPKG_LIB_BZ2
 DPKG_LIB_LZMA
diff --git a/debian/control b/debian/control
index d1b304546ef45..6fd7c29387bd2 100644
--- a/debian/control
+++ b/debian/control
@@ -16,7 +16,8 @@ Rules-Requires-Root: no
  gettext (>= 0.19.7),
 # Version needed for --porefs defaults, conditional addenda and mode=eof.
  po4a (>= 0.59),
- libmd-dev,
+# libmd-dev,
+ libssl-dev,
  zlib1g-dev,
  libbz2-dev,
 # Version needed for multi-threaded decompressor support.
diff --git a/lib/dpkg/buffer.c b/lib/dpkg/buffer.c
index ed05f4b4ab5cb..213268699bbd5 100644
--- a/lib/dpkg/buffer.c
+++ b/lib/dpkg/buffer.c
@@ -26,7 +26,6 @@
 #include <sys/types.h>
 
 #include <errno.h>
-#include <md5.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -37,6 +36,13 @@
 #include <dpkg/fdio.h>
 #include <dpkg/buffer.h>
 
+#ifdef USE_LIB_MD
+#include <md5.h>
+#else
+#include <openssl/evp.h>
+#endif
+
+#ifdef USE_LIB_MD
 struct buffer_md5_ctx {
 	MD5_CTX ctx;
 	char *hash;
@@ -53,19 +59,6 @@ buffer_md5_init(struct buffer_data *data)
 	MD5Init(&ctx->ctx);
 }
 
-static off_t
-buffer_digest_init(struct buffer_data *data)
-{
-	switch (data->type) {
-	case BUFFER_DIGEST_NULL:
-		break;
-	case BUFFER_DIGEST_MD5:
-		buffer_md5_init(data);
-		break;
-	}
-	return 0;
-}
-
 static off_t
 buffer_digest_update(struct buffer_data *digest, const void *buf, off_t length)
 {
@@ -104,6 +97,95 @@ buffer_md5_done(struct buffer_data *data)
 	free(ctx);
 }
 
+
+#else
+struct buffer_md5_ctx {
+	EVP_MD_CTX *ctx;
+	char *hash;
+};
+
+static void
+buffer_md5_init(struct buffer_data *data)
+{
+	struct buffer_md5_ctx *ctx;
+	static EVP_MD *md_md5;
+
+	if (!md_md5) {
+		md_md5 = EVP_MD_fetch(NULL, "md5", NULL);
+		if (!md_md5)
+			internerr("EVP_MD_fetch() failed.");
+	}
+	ctx = m_malloc(sizeof(*ctx));
+
+	ctx->ctx = EVP_MD_CTX_new();
+	if (ctx->ctx== NULL)
+		internerr("EVP_MD_CTX_new() failed.");
+
+	if (!EVP_DigestInit_ex(ctx->ctx, md_md5, NULL))
+		internerr("EVP_DigestInit_ex() failed.");
+
+	ctx->hash = data->arg.ptr;
+	data->arg.ptr = ctx;
+}
+
+static off_t
+buffer_digest_update(struct buffer_data *digest, const void *buf, off_t length)
+{
+	off_t ret = length;
+
+	switch (digest->type) {
+	case BUFFER_DIGEST_NULL:
+		break;
+	case BUFFER_DIGEST_MD5:
+		if (!EVP_DigestUpdate(((struct buffer_md5_ctx *)digest->arg.ptr)->ctx,
+				      buf, length))
+			internerr("Digest update failed %i", digest->type);
+		break;
+	default:
+		internerr("unknown data type %i", digest->type);
+	}
+
+	return ret;
+}
+
+static void
+buffer_md5_done(struct buffer_data *data)
+{
+	struct buffer_md5_ctx *ctx;
+	unsigned char digest[16], *p = digest;
+	char *hash;
+	int i;
+
+	ctx = (struct buffer_md5_ctx *)data->arg.ptr;
+	hash = ctx->hash;
+	if (!EVP_DigestFinal_ex(ctx->ctx, digest, NULL))
+		internerr("EVP_DigestFinal_ex() failed.");
+
+	for (i = 0; i < 16; ++i) {
+		sprintf(hash, "%02x", *p++);
+		hash += 2;
+	}
+	*hash = '\0';
+	EVP_MD_CTX_free(ctx->ctx);
+	free(ctx);
+}
+
+
+#endif
+
+static off_t
+buffer_digest_init(struct buffer_data *data)
+{
+	switch (data->type) {
+	case BUFFER_DIGEST_NULL:
+		break;
+	case BUFFER_DIGEST_MD5:
+		buffer_md5_init(data);
+		break;
+	}
+	return 0;
+}
+
 static off_t
 buffer_digest_done(struct buffer_data *data)
 {
-- 
2.40.1


Reply to: