From 2c5bb172117aa21e081ffac7f0ae8ba99c491d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavol=20=C5=BD=C3=A1=C4=8Dik?= Date: Thu, 18 Dec 2025 10:08:16 +0100 Subject: [PATCH] md: Implement one-shot md5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Which can be used for non-cryptographic purposes even in FIPS mode. Signed-off-by: Pavol Žáčik Reviewed-by: Jakub Jelen Reviewed-by: Andreas Schneider --- include/libssh/wrapper.h | 1 + src/md_crypto.c | 49 ++++++++++++++++++++++++++++++++++++++++ src/md_gcrypt.c | 6 +++++ src/md_mbedcrypto.c | 48 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+) diff --git a/include/libssh/wrapper.h b/include/libssh/wrapper.h index c1ddc2a8..9214a928 100644 --- a/include/libssh/wrapper.h +++ b/include/libssh/wrapper.h @@ -75,6 +75,7 @@ MD5CTX md5_init(void); void md5_ctx_free(MD5CTX); int md5_update(MD5CTX c, const void *data, size_t len); int md5_final(unsigned char *md, MD5CTX c); +int md5(const unsigned char *digest, size_t len, unsigned char *hash); SHACTX sha1_init(void); void sha1_ctx_free(SHACTX); diff --git a/src/md_crypto.c b/src/md_crypto.c index f7cda8dd..e7b1cf7a 100644 --- a/src/md_crypto.c +++ b/src/md_crypto.c @@ -322,3 +322,52 @@ md5_final(unsigned char *md, MD5CTX c) } return SSH_OK; } + +/** +* @ brief One-shot MD5. Not intended for use in security-relevant contexts. +*/ +int +md5(const unsigned char *digest, size_t len, unsigned char *hash) +{ + int rc, ret = SSH_ERROR; + unsigned int mdlen = 0; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_MD *md5 = NULL; +#endif + MD5CTX c = EVP_MD_CTX_new(); + if (c == NULL) { + goto out; + } + +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + md5 = EVP_MD_fetch(NULL, "MD5", "provider=default,-fips"); + if (md5 == NULL) { + goto out; + } + rc = EVP_DigestInit(c, md5); +#else + rc = EVP_DigestInit_ex(c, EVP_md5(), NULL); +#endif + if (rc == 0) { + goto out; + } + + rc = EVP_DigestUpdate(c, digest, len); + if (rc != 1) { + goto out; + } + + rc = EVP_DigestFinal(c, hash, &mdlen); + if (rc != 1) { + goto out; + } + + ret = SSH_OK; + +out: + EVP_MD_CTX_free(c); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_MD_free(md5); +#endif + return ret; +} diff --git a/src/md_gcrypt.c b/src/md_gcrypt.c index 93c7b0d9..c8830773 100644 --- a/src/md_gcrypt.c +++ b/src/md_gcrypt.c @@ -244,3 +244,9 @@ md5_final(unsigned char *md, MD5CTX c) gcry_md_close(c); return SSH_OK; } + +int md5(const unsigned char *digest, size_t len, unsigned char *hash) +{ + gcry_md_hash_buffer(GCRY_MD_MD5, hash, digest, len); + return SSH_OK; +} diff --git a/src/md_mbedcrypto.c b/src/md_mbedcrypto.c index b3529b4b..445f644d 100644 --- a/src/md_mbedcrypto.c +++ b/src/md_mbedcrypto.c @@ -405,3 +405,51 @@ md5_final(unsigned char *md, MD5CTX c) } return SSH_OK; } + +int md5(const unsigned char *digest, size_t len, unsigned char *hash) +{ + MD5CTX ctx = NULL; + int rc; + const mbedtls_md_info_t *md_info = + mbedtls_md_info_from_type(MBEDTLS_MD_MD5); + if (md_info == NULL) { + return SSH_ERROR; + } + + ctx = malloc(sizeof(mbedtls_md_context_t)); + if (ctx == NULL) { + return SSH_ERROR; + } + + mbedtls_md_init(ctx); + + rc = mbedtls_md_setup(ctx, md_info, 0); + if (rc != 0) { + mbedtls_md_free(ctx); + SAFE_FREE(ctx); + return SSH_ERROR; + } + + rc = mbedtls_md_starts(ctx); + if (rc != 0) { + mbedtls_md_free(ctx); + SAFE_FREE(ctx); + return SSH_ERROR; + } + + rc = mbedtls_md_update(ctx, digest, len); + if (rc != 0) { + mbedtls_md_free(ctx); + SAFE_FREE(ctx); + return SSH_ERROR; + } + + rc = mbedtls_md_finish(ctx, hash); + mbedtls_md_free(ctx); + SAFE_FREE(ctx); + if (rc != 0) { + return SSH_ERROR; + } + + return SSH_OK; +}