feat: Add modern hash algorithms to crypto package (#1128)

* feat: Add modern hash algorithms to crypto package

Enhance the crypto package to support modern hash algorithms alongside
the existing legacy ones, using OpenSSL's EVP interface for new algorithms.

New algorithms added:
- SHA-3 family: sha3-224, sha3-256, sha3-384, sha3-512
- BLAKE2 family: blake2s256, blake2b512
- SM3 algorithm

Key features:
- Dual implementation approach: direct functions for legacy algorithms,
  EVP interface for modern ones
- Comprehensive OpenSSL version compatibility (1.0.x through 3.x)
- Graceful fallback behavior for unsupported algorithms
- Updated documentation in English and Chinese
- Enhanced test coverage

Compatibility notes:
- Legacy algorithms (MD4, MD5, SHA-1, SHA-2, RIPEMD160): All OpenSSL versions
- MD2, MDC2: OpenSSL 1.x-2.x only (removed in 3.x)
- BLAKE2 family: OpenSSL 1.1.0+
- SHA-3 family and SM3: OpenSSL 1.1.1+

Total supported algorithms: 17 (with version-dependent availability)

* Delete CRYPTO_PACKAGE_ENHANCEMENT.md
This commit is contained in:
M Lange 2025-07-27 22:55:53 -04:00 committed by GitHub
parent cb7e877afd
commit 33de35ca19
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 183 additions and 6 deletions

View file

@ -16,21 +16,64 @@ title: strings / hash
Returns the hash of string `str` by the `algo` algorithm.
Aglorithm `algo` can be one of:
md4 md5 sha1 sha224 sha256 sha384 sha512 ripemd160
Algorithm `algo` can be one of:
**Legacy algorithms:**
md4 md5 ripemd160
**Legacy algorithms (OpenSSL 1.x - 2.x only):**
md2 mdc2
**SHA-1 and SHA-2 family:**
sha1 sha224 sha256 sha384 sha512
**SHA-3 family (recommended):**
sha3-224 sha3-256 sha3-384 sha3-512
**BLAKE2 family (high performance):**
blake2s256 blake2b512
**Other algorithms:**
sm3
This requires PACKAGE_CRYPTO to be enabled when compiling the driver.
**Compatibility Notes:**
- MD2 and MDC2 are only available with OpenSSL 1.x - 2.x (removed in OpenSSL 3.x)
- BLAKE2 family requires OpenSSL 1.1.0+
- SHA-3 family and SM3 require OpenSSL 1.1.1+
Note: For new applications, SHA-3 and BLAKE2 algorithms are recommended over
legacy MD and older SHA algorithms for better security and performance.
### EXAMPLE
// Legacy algorithms
hash("md4", "Something") = "abc554cae9acd8f168101954383335df"
hash("md5", "Something") = "73f9977556584a369800e775b48f3dbe"
hash("ripemd160", "Something") = ...40 characters...
hash("sha1", "Something") = ...40 characters...
// Legacy algorithms (OpenSSL 1.x - 2.x only)
hash("md2", "Something") = ...32 characters... (if available)
hash("mdc2", "Something") = ...32 characters... (if available)
// SHA-2 family
hash("sha224", "Something") = ...56 characters...
hash("sha256", "Something") = ...64 characters...
hash("sha384", "Something") = ...96 characters...
hash("sha512", "Something") = ...128 characters...
// SHA-3 family (recommended for new applications)
hash("sha3-256", "Something") = ...64 characters...
hash("sha3-512", "Something") = ...128 characters...
// BLAKE2 family (high performance)
hash("blake2s256", "Something") = ...64 characters...
hash("blake2b512", "Something") = ...128 characters...
// Other algorithms
hash("ripemd160", "Something") = ...40 characters...
hash("sm3", "Something") = ...64 characters...
### SEE ALSO

View file

@ -14,9 +14,36 @@ title: string / hash
### 描述
返回字符串 `str` 通过 `algo` 算法的哈希值,算法 `algo` 可以是 md4 md5 sha1 sha224 sha256 sha384 sha512 ripemd160
返回字符串 `str` 通过 `algo` 算法的哈希值。
算法 `algo` 可以是以下之一:
**传统算法:**
md4 md5 ripemd160
**传统算法(仅限 OpenSSL 1.x - 2.x**
md2 mdc2
**SHA-1 和 SHA-2 系列:**
sha1 sha224 sha256 sha384 sha512
**SHA-3 系列(推荐):**
sha3-224 sha3-256 sha3-384 sha3-512
**BLAKE2 系列(高性能):**
blake2s256 blake2b512
**其他算法:**
sm3
这是 FLUFFOS 新增的外部函数,需要在编译驱动时启用 PACKAGE_CRYPTO 。
**兼容性说明:**
- MD2 和 MDC2 仅在 OpenSSL 1.x - 2.x 中可用(在 OpenSSL 3.x 中已移除)
- BLAKE2 系列需要 OpenSSL 1.1.0+
- SHA-3 系列和 SM3 需要 OpenSSL 1.1.1+
注意:对于新应用程序,建议使用 SHA-3 和 BLAKE2 算法,而不是传统的 MD 和较旧的 SHA 算法,以获得更好的安全性和性能。
### 翻译 ###

View file

@ -3,15 +3,25 @@
*
* Utilises the OpenSSL crypto library to provide various message digest hashes
* via a hash() efun. It works in almost the same manner as the hash function
* from php, and provides md2, md4, md5, mdc2, sha1 and ripemd160 hashes. You
* must link against the ssl link library (add -lssl to system_libs).
* from php, and provides legacy hashes (md4, md5, sha1, ripemd160),
* SHA-2 family (sha224, sha256, sha384, sha512), and modern hashes
* (sha3-224, sha3-256, sha3-384, sha3-512, blake2s256, blake2b512, sm3).
* You must link against the ssl crypto library (add -lssl -lcrypto to system_libs).
*
* Version compatibility:
* - Legacy algorithms (MD4, MD5, SHA-1, SHA-2, RIPEMD160): OpenSSL 1.0.0+
* - MD2, MDC2: OpenSSL 1.0.0+ to 2.x (deprecated/removed in OpenSSL 3.0+)
* - BLAKE2 family: OpenSSL 1.1.0+
* - SHA-3 family and SM3: OpenSSL 1.1.1+
*
* -- coded by Ajandurah@Demonslair (Mark Lyndoe) 10/03/09
* -- updated to support modern hash algorithms (Matthew Lange) 26/07/25
*/
#include "base/package_api.h"
#include <openssl/opensslconf.h>
#include <openssl/evp.h>
#ifndef OPENSSL_NO_SHA
#include <openssl/sha.h>
@ -49,6 +59,63 @@ static char *hexdump(const unsigned char *data, int len) {
return result;
}
/* Modern EVP-based hash function for newer algorithms (Copilot assisted)
*
* Uses OpenSSL's EVP interface to support modern hash algorithms like SHA-3,
* BLAKE2, and other algorithms not available through direct function calls.
* The EVP interface is the recommended approach for new algorithms in OpenSSL.
*
* This function provides graceful fallback behavior for older OpenSSL versions:
* - Returns nullptr if the algorithm is not supported in the current OpenSSL build
* - The calling code will then show an appropriate error message to the user
*/
static char *evp_hash(const char *algo, const unsigned char *data, int data_len) {
const EVP_MD *md;
EVP_MD_CTX *ctx;
unsigned char hash[EVP_MAX_MD_SIZE];
unsigned int hash_len;
char *result = nullptr;
// Get the message digest algorithm by name (e.g., "sha3-256")
md = EVP_get_digestbyname(algo);
if (!md) {
// Algorithm not found or not supported in this OpenSSL build
return nullptr;
}
// Create a new digest context for this operation
ctx = EVP_MD_CTX_new();
if (!ctx) {
// Memory allocation failed
return nullptr;
}
// Initialize the digest context with the chosen algorithm
if (EVP_DigestInit_ex(ctx, md, nullptr) != 1) {
EVP_MD_CTX_free(ctx);
return nullptr;
}
// Process the input data through the hash function
if (EVP_DigestUpdate(ctx, data, data_len) != 1) {
EVP_MD_CTX_free(ctx);
return nullptr;
}
// Finalize the hash computation and get the result
if (EVP_DigestFinal_ex(ctx, hash, &hash_len) != 1) {
EVP_MD_CTX_free(ctx);
return nullptr;
}
// Clean up the digest context
EVP_MD_CTX_free(ctx);
// Convert binary hash to hexadecimal string representation
result = hexdump(hash, hash_len);
return result;
}
void f_hash() {
const char *algo, *data;
char *result = nullptr;
@ -66,6 +133,13 @@ void f_hash() {
goto result; \
})
#define DO_EVP_HASH_IF(id) \
SAFE(if (strcasecmp(algo, id) == 0) { \
result = evp_hash(id, (unsigned char *)data, data_len); \
goto result; \
})
/* Legacy hash algorithms using direct functions */
#ifndef OPENSSL_NO_SHA1
DO_HASH_IF("sha1", SHA1, SHA_DIGEST_LENGTH);
#endif
@ -100,6 +174,22 @@ void f_hash() {
DO_HASH_IF("ripemd160", RIPEMD160, RIPEMD160_DIGEST_LENGTH);
#endif
/* Modern hash algorithms using EVP interface */
/* These algorithms require OpenSSL 1.1.1+ and will gracefully fail on older versions */
/* SHA-3 family (FIPS 202 standard) - requires OpenSSL 1.1.1+ */
DO_EVP_HASH_IF("sha3-224");
DO_EVP_HASH_IF("sha3-256");
DO_EVP_HASH_IF("sha3-384");
DO_EVP_HASH_IF("sha3-512");
/* BLAKE2 family (RFC 7693) - requires OpenSSL 1.1.0+ */
DO_EVP_HASH_IF("blake2b512");
DO_EVP_HASH_IF("blake2s256");
/* Other modern algorithms - SM3 requires OpenSSL 1.1.1+ */
DO_EVP_HASH_IF("sm3");
result:
if (!result) {
error("hash() unknown hash type: %s\n", algo);

View file

@ -24,5 +24,22 @@ void do_tests() {
ASSERT_EQ(sizeof(hash("sha384", "12345")), 96);
ASSERT_EQ(hash("sha512", "12345"), "3627909a29c31381a071ec27f7c9ca97726182aed29a7ddd2e54353322cfb30abb9e3a6df2ac2c20fe23436311d678564d0c8d305930575f60e2d3d048184d79");
ASSERT_EQ(sizeof(hash("sha512", "12345")), 128);
// Test newer SHA-3 algorithms
ASSERT_EQ(sizeof(hash("sha3-224", "12345")), 56);
ASSERT_EQ(sizeof(hash("sha3-256", "12345")), 64);
ASSERT_EQ(sizeof(hash("sha3-384", "12345")), 96);
ASSERT_EQ(sizeof(hash("sha3-512", "12345")), 128);
// Test BLAKE2 algorithms
ASSERT_EQ(sizeof(hash("blake2s256", "12345")), 64);
ASSERT_EQ(sizeof(hash("blake2b512", "12345")), 128);
// Test other algorithms
ASSERT_EQ(sizeof(hash("sm3", "12345")), 64);
// Test some specific known values for SHA3-256
ASSERT_EQ(hash("sha3-256", "abc"), "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532");
ASSERT_EQ(hash("sha3-256", ""), "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a");
#endif
}