From 6fa95f0d470b8fe1cf0a807717dd9ec807ff3335 Mon Sep 17 00:00:00 2001 From: hanez Date: Thu, 19 Feb 2026 14:19:17 +0100 Subject: [PATCH] Added OpenSSL RIPEMD-160 fun. (0.38.14) --- docs/examples.md | 1 + docs/external/README.md | 2 +- docs/external/openssl.md | 11 +++++-- docs/opcodes.md | 1 + examples/crypto/openssl_md5.fun | 2 +- examples/crypto/openssl_ripemd160.fun | 28 +++++++++++++++++ src/bytecode.c | 1 + src/bytecode.h | 1 + src/external/openssl.c | 44 +++++++++++++++++++++++++-- src/parser.c | 8 +++++ src/vm.c | 3 +- src/vm/openssl/md5.c | 13 +++++++- src/vm/openssl/ripemd160.c | 16 ++++++++++ src/vm/openssl/sha256.c | 11 +++++++ src/vm/openssl/sha512.c | 11 +++++++ 15 files changed, 144 insertions(+), 9 deletions(-) create mode 100644 examples/crypto/openssl_ripemd160.fun create mode 100644 src/vm/openssl/ripemd160.c diff --git a/docs/examples.md b/docs/examples.md index abd6614..93a792c 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -45,6 +45,7 @@ FUN_LIB_DIR="$(pwd)/lib" fun examples/crypto/openssl_md5.fun Browse the `examples/` tree for areas of interest: - crypto — crypto demonstrations (e.g., OpenSSL MD5/SHA-256/SHA-512 helpers; requires build with `-DFUN_WITH_OPENSSL=ON`) + - crypto — crypto demonstrations (e.g., OpenSSL MD5/SHA-256/SHA-512/RIPEMD‑160 helpers; requires build with `-DFUN_WITH_OPENSSL=ON`) - blocking / interactive — I/O or user-interactive patterns - error / broken — negative tests and error showcases - math — numeric operations diff --git a/docs/external/README.md b/docs/external/README.md index 8f3391e..15950cb 100644 --- a/docs/external/README.md +++ b/docs/external/README.md @@ -18,7 +18,7 @@ Extensions: - [PC/SC (Smart cards)](./pcsc.md) - [Notcurses (TUI)](./notcurses.md) - [Tcl/Tk (GUI)](./tcltk.md) -- [OpenSSL (MD5 helper)](./openssl.md) +- [OpenSSL](./openssl.md) Notes: - These integrations are optional; the VM compiles without them. diff --git a/docs/external/openssl.md b/docs/external/openssl.md index c0a743b..7606280 100644 --- a/docs/external/openssl.md +++ b/docs/external/openssl.md @@ -1,7 +1,7 @@ # OpenSSL extension (optional) - CMake option: FUN_WITH_OPENSSL=ON -- Purpose: provide small crypto helpers backed by OpenSSL. Includes md5, sha256, sha512 helpers. +- Purpose: provide small crypto helpers backed by OpenSSL. Includes md5, sha256, sha512, ripemd160 helpers. - Homepage: https://www.openssl.org/ Build notes: @@ -12,7 +12,8 @@ Provided helper/opcodes: - Function: openssl_md5(data:string) -> string (lowercase hex). Falls back to empty string when the extension is disabled, mirroring other optional modules. - Function: openssl_sha256(data:string) -> string (lowercase hex). - Function: openssl_sha512(data:string) -> string (lowercase hex). -- Opcodes: OP_OPENSSL_MD5, OP_OPENSSL_SHA256, OP_OPENSSL_SHA512 (internal mappings for the functions above). +- Function: openssl_ripemd160(data:string) -> string (lowercase hex). Note: On OpenSSL 3.x this may require the legacy provider; if the digest is unavailable, the helper returns an empty string. +- Opcodes: OP_OPENSSL_MD5, OP_OPENSSL_SHA256, OP_OPENSSL_SHA512, OP_OPENSSL_RIPEMD160 (internal mappings for the functions above). Quickstart: - Configure: cmake -S . -B build -DFUN_WITH_OPENSSL=ON @@ -21,6 +22,7 @@ Quickstart: - ./build/fun examples/crypto/openssl_md5.fun - ./build/fun examples/crypto/openssl_sha256.fun - ./build/fun examples/crypto/openssl_sha512.fun + - ./build/fun examples/crypto/openssl_ripemd160.fun Example output: - md5(abc) = 900150983cd24fb0d6963f7d28e17f72 @@ -29,3 +31,8 @@ Example output: - sha256("") = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 - sha512(abc) = ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f - sha512("") = cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e + - ripemd160(abc) = 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc + - ripemd160("") = 9c1185a5c5e9fc54612808977ee8f548b2258d31 + +Notes: +- The OpenSSL 3.x provider configuration on your system determines availability of RIPEMD‑160. If the legacy provider is not enabled, openssl_ripemd160() will return an empty string. diff --git a/docs/opcodes.md b/docs/opcodes.md index 5ea6c86..47e2b01 100644 --- a/docs/opcodes.md +++ b/docs/opcodes.md @@ -207,6 +207,7 @@ This document provides an overview of the available VM opcodes implemented under - OP_OPENSSL_MD5: Compute MD5 digest and return lowercase hex string; pops data:string; pushes md5:string. - OP_OPENSSL_SHA256: Compute SHA‑256 digest and return lowercase hex string; pops data:string; pushes sha256:string. - OP_OPENSSL_SHA512: Compute SHA‑512 digest and return lowercase hex string; pops data:string; pushes sha512:string. + - OP_OPENSSL_RIPEMD160: Compute RIPEMD‑160 digest and return lowercase hex string; pops data:string; pushes ripemd160:string. On OpenSSL 3.x this may require the legacy provider; if unavailable, the helper returns an empty string. - Requires building with `-DFUN_WITH_OPENSSL=ON`. When disabled, these opcodes still exist but return an empty string to match other optional extensions’ fallback behavior. ## PCRE2 (Regex) diff --git a/examples/crypto/openssl_md5.fun b/examples/crypto/openssl_md5.fun index 7002721..63f906b 100644 --- a/examples/crypto/openssl_md5.fun +++ b/examples/crypto/openssl_md5.fun @@ -4,7 +4,7 @@ * This file is part of the Fun programming language. * https://fun-lang.xyz/ * - * Copyright 2025 Johannes Findeisen + * Copyright 2026 Johannes Findeisen * Licensed under the terms of the Apache-2.0 license. * https://opensource.org/license/apache-2-0 * diff --git a/examples/crypto/openssl_ripemd160.fun b/examples/crypto/openssl_ripemd160.fun new file mode 100644 index 0000000..65d0f85 --- /dev/null +++ b/examples/crypto/openssl_ripemd160.fun @@ -0,0 +1,28 @@ +#!/usr/bin/env fun + +/* + * This file is part of the Fun programming language. + * https://fun-lang.xyz/ + * + * Copyright 2026 Johannes Findeisen + * Licensed under the terms of the Apache-2.0 license. + * https://opensource.org/license/apache-2-0 + * + * Added: 2026-02-19 + */ + +// OpenSSL RIPEMD-160 example +// Enable with -DFUN_WITH_OPENSSL=ON during build for real hashing. + +s = "abc" +d = openssl_ripemd160(s) +print("ripemd160(abc) = " + d) + +// Another quick check (empty string) +e = "" +print("ripemd160(\"\") = " + openssl_ripemd160(e)) + +/* Expected output (if RIPEMD-160 is available in your OpenSSL build): +ripemd160(abc) = 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc +ripemd160("") = 9c1185a5c5e9fc54612808977ee8f548b2258d31 +*/ diff --git a/src/bytecode.c b/src/bytecode.c index caf6029..405e6b7 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -172,6 +172,7 @@ static const char *opcode_name(OpCode op) { case OP_OPENSSL_MD5: return "OPENSSL_MD5"; case OP_OPENSSL_SHA256: return "OPENSSL_SHA256"; case OP_OPENSSL_SHA512: return "OPENSSL_SHA512"; + case OP_OPENSSL_RIPEMD160: return "OPENSSL_RIPEMD160"; case OP_INI_LOAD: return "INI_LOAD"; case OP_INI_FREE: return "INI_FREE"; case OP_INI_GET_STRING: return "INI_GET_STRING"; diff --git a/src/bytecode.h b/src/bytecode.h index 446dd21..5f89650 100644 --- a/src/bytecode.h +++ b/src/bytecode.h @@ -185,6 +185,7 @@ typedef enum { OP_OPENSSL_MD5, // pops data string; pushes md5 hex string OP_OPENSSL_SHA256, // pops data string; pushes sha256 hex string OP_OPENSSL_SHA512, // pops data string; pushes sha512 hex string + OP_OPENSSL_RIPEMD160, // pops data string; pushes ripemd160 hex string // INI (iniparser 4.2.6) optional OP_INI_LOAD, // pops path; pushes handle (>0) or 0 diff --git a/src/external/openssl.c b/src/external/openssl.c index cbec06e..810e430 100644 --- a/src/external/openssl.c +++ b/src/external/openssl.c @@ -2,7 +2,7 @@ * This file is part of the Fun programming language. * https://fun-lang.xyz/ * - * Copyright 2025 Johannes Findeisen + * Copyright 2026 Johannes Findeisen * Licensed under the terms of the Apache-2.0 license. * https://opensource.org/license/apache-2-0 * @@ -10,11 +10,11 @@ */ /* - * OpenSSL integration helpers (MD5, SHA-256, SHA-512) + * OpenSSL integration helpers (MD5, RIPEMD-160, SHA-256, SHA-512) */ #ifdef FUN_WITH_OPENSSL -# include +#include #endif #include @@ -128,3 +128,41 @@ static char *fun_openssl_sha512_hex(const unsigned char *data, size_t len) { return hex; #endif } + +/* Compute RIPEMD-160 hex of input buffer; returns malloc'ed C string (lowercase hex). + * Note: On OpenSSL 3.x, RIPEMD160 may require the legacy provider; if unavailable, + * EVP_ripemd160() can return NULL. In that case we return NULL and the VM opcode + * will fall back to empty string behavior. When OpenSSL is disabled, return empty string. */ +static char *fun_openssl_ripemd160_hex(const unsigned char *data, size_t len) { + static const char hexdig[] = "0123456789abcdef"; + if (!data && len != 0) return NULL; +#ifdef FUN_WITH_OPENSSL + const EVP_MD *md = EVP_ripemd160(); + if (!md) return NULL; + int dlen = EVP_MD_get_size(md); + if (dlen <= 0) return NULL; + unsigned char *digest = (unsigned char*)malloc((size_t)dlen); + if (!digest) return NULL; + unsigned int out_len = 0; + int ok; + if (len == 0) { + ok = EVP_Digest(NULL, 0, digest, &out_len, md, NULL); + } else { + ok = EVP_Digest(data, len, digest, &out_len, md, NULL); + } + if (ok != 1 || (int)out_len != dlen) { free(digest); return NULL; } + char *hex = (char*)malloc((size_t)dlen * 2 + 1); + if (!hex) { free(digest); return NULL; } + for (int i = 0; i < dlen; ++i) { + hex[2*i] = hexdig[(digest[i] >> 4) & 0xF]; + hex[2*i+1] = hexdig[digest[i] & 0xF]; + } + hex[dlen * 2] = '\0'; + free(digest); + return hex; +#else + char *hex = (char*)malloc(1); + if (hex) hex[0] = '\0'; + return hex; +#endif +} diff --git a/src/parser.c b/src/parser.c index b27055e..faa2944 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1222,6 +1222,14 @@ static int emit_primary(Bytecode *bc, const char *src, size_t len, size_t *pos) free(name); return 1; } + if (strcmp(name, "openssl_ripemd160") == 0) { + (*pos)++; /* '(' */ + if (!emit_expression(bc, src, len, pos)) { parser_fail(*pos, "openssl_ripemd160 expects (data)"); free(name); return 0; } + if (!consume_char(src, len, pos, ')')) { parser_fail(*pos, "Expected ')' after openssl_ripemd160 arg"); free(name); return 0; } + bytecode_add_instruction(bc, OP_OPENSSL_RIPEMD160, 0); + free(name); + return 1; + } /* PCSC builtins */ if (strcmp(name, "pcsc_establish") == 0) { (*pos)++; /* '(' */ diff --git a/src/vm.c b/src/vm.c index 19d9181..eb9af8d 100644 --- a/src/vm.c +++ b/src/vm.c @@ -869,10 +869,11 @@ void vm_run(VM *vm, Bytecode *entry) { #include "vm/curl/download.c" #endif - /* OpenSSL ops (md5/sha256/sha512) */ + /* OpenSSL ops (md5/sha256/sha512/ripemd160) */ #include "vm/openssl/md5.c" #include "vm/openssl/sha256.c" #include "vm/openssl/sha512.c" + #include "vm/openssl/ripemd160.c" /* Tk (Tcl/Tk) ops */ #ifdef FUN_WITH_TCLTK diff --git a/src/vm/openssl/md5.c b/src/vm/openssl/md5.c index 473605d..a741dd3 100644 --- a/src/vm/openssl/md5.c +++ b/src/vm/openssl/md5.c @@ -1,4 +1,15 @@ -/** +/* +* This file is part of the Fun programming language. + * https://fun-lang.xyz/ + * + * Copyright 2026 Johannes Findeisen + * Licensed under the terms of the Apache-2.0 license. + * https://opensource.org/license/apache-2-0 + * + * Added: 2026-02-19 + */ + + /** * OpenSSL MD5 builtin */ case OP_OPENSSL_MD5: { diff --git a/src/vm/openssl/ripemd160.c b/src/vm/openssl/ripemd160.c new file mode 100644 index 0000000..2fc7b77 --- /dev/null +++ b/src/vm/openssl/ripemd160.c @@ -0,0 +1,16 @@ +/* + * OpenSSL RIPEMD-160 builtin + */ +case OP_OPENSSL_RIPEMD160: { + Value vdata = pop_value(vm); + char *s = value_to_string_alloc(&vdata); + free_value(vdata); + if (!s) { push_value(vm, make_string("")); break; } + char *hex = fun_openssl_ripemd160_hex((const unsigned char*)s, strlen(s)); + free(s); + if (!hex) { push_value(vm, make_string("")); break; } + Value out = make_string(hex); + free(hex); + push_value(vm, out); + break; +} diff --git a/src/vm/openssl/sha256.c b/src/vm/openssl/sha256.c index bed86f0..342fbd7 100644 --- a/src/vm/openssl/sha256.c +++ b/src/vm/openssl/sha256.c @@ -1,3 +1,14 @@ +/* +* This file is part of the Fun programming language. + * https://fun-lang.xyz/ + * + * Copyright 2026 Johannes Findeisen + * Licensed under the terms of the Apache-2.0 license. + * https://opensource.org/license/apache-2-0 + * + * Added: 2026-02-19 + */ + /** * OpenSSL SHA-256 builtin */ diff --git a/src/vm/openssl/sha512.c b/src/vm/openssl/sha512.c index 2e091b1..63c71fa 100644 --- a/src/vm/openssl/sha512.c +++ b/src/vm/openssl/sha512.c @@ -1,3 +1,14 @@ +/* +* This file is part of the Fun programming language. + * https://fun-lang.xyz/ + * + * Copyright 2026 Johannes Findeisen + * Licensed under the terms of the Apache-2.0 license. + * https://opensource.org/license/apache-2-0 + * + * Added: 2026-02-19 + */ + /** * OpenSSL SHA-512 builtin */