diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 42c0df02a0..491b8e00c8 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -139,6 +139,7 @@ PSEUDOMODULES += mpu_stack_guard ## This is a protection mechanism which makes exploitation of buffer overflows significantly harder. PSEUDOMODULES += mpu_noexec_ram +PSEUDOMODULES += md5sum PSEUDOMODULES += mtd_write_page PSEUDOMODULES += nanocoap_% PSEUDOMODULES += netdev_default @@ -196,6 +197,8 @@ PSEUDOMODULES += semtech_loramac_rx PSEUDOMODULES += senml_cbor PSEUDOMODULES += senml_phydat PSEUDOMODULES += senml_saul +PSEUDOMODULES += sha1sum +PSEUDOMODULES += sha256sum PSEUDOMODULES += shell_hooks PSEUDOMODULES += slipdev_stdio PSEUDOMODULES += slipdev_l2addr diff --git a/sys/Makefile.dep b/sys/Makefile.dep index c901784c60..019c00483f 100644 --- a/sys/Makefile.dep +++ b/sys/Makefile.dep @@ -334,6 +334,11 @@ ifneq (,$(filter shell_commands,$(USEMODULE))) endif endif +ifneq (,$(filter md5sum sha1sum sha256sum,$(USEMODULE))) + USEMODULE += vfs_util + USEMODULE += hashes +endif + ifneq (,$(filter posix_semaphore,$(USEMODULE))) USEMODULE += sema_deprecated USEMODULE += ztimer64_usec diff --git a/sys/include/vfs_util.h b/sys/include/vfs_util.h index aa70a20007..a6ae1ec911 100644 --- a/sys/include/vfs_util.h +++ b/sys/include/vfs_util.h @@ -51,6 +51,56 @@ int vfs_file_from_buffer(const char *file, const void *buf, size_t len); */ int vfs_file_to_buffer(const char* file, void* buf, size_t len); +#if MODULE_HASHES || DOXYGEN +/** + * @brief Compute the MD5 message digest of a file + * + * Requires the `hashes` module. + * + * @param[in] file Source file path + * @param[out] digest Destination buffer, must fit @ref MD5_DIGEST_LENGTH bytes + * @param[out] work_buf Work buffer + * @param[in] work_buf_len Size of the work buffer + * + * @return 0 on success + * @return negative error + */ +int vfs_file_md5(const char* file, void *digest, + void *work_buf, size_t work_buf_len); + +/** + * @brief Compute the SHA1 message digest of a file + * + * Requires the `hashes` module. + * + * @param[in] file Source file path + * @param[out] digest Destination buffer, must fit @ref SHA1_DIGEST_LENGTH bytes + * @param[out] work_buf Work buffer + * @param[in] work_buf_len Size of the work buffer + * + * @return 0 on success + * @return negative error + */ +int vfs_file_sha1(const char* file, void *digest, + void *work_buf, size_t work_buf_len); + +/** + * @brief Compute the SHA256 message digest of a file + * + * Requires the `hashes` module. + * + * @param[in] file Source file path + * @param[out] digest Destination buffer, must fit @ref SHA256_DIGEST_LENGTH bytes + * @param[out] work_buf Work buffer + * @param[in] work_buf_len Size of the work buffer + * + * @return 0 on success + * @return negative error + */ +int vfs_file_sha256(const char* file, void *digest, + void *work_buf, size_t work_buf_len); +#endif + #ifdef __cplusplus } #endif diff --git a/sys/shell/commands/sc_vfs.c b/sys/shell/commands/sc_vfs.c index 98c15b00c2..aef82cabbc 100644 --- a/sys/shell/commands/sc_vfs.c +++ b/sys/shell/commands/sc_vfs.c @@ -30,6 +30,9 @@ #include #include "vfs.h" +#if MODULE_VFS_UTIL +#include "vfs_util.h" +#endif #define SHELL_VFS_BUFSIZE 256 static uint8_t _shell_vfs_data_buffer[SHELL_VFS_BUFSIZE]; @@ -634,4 +637,93 @@ int _vfs_handler(int argc, char **argv) return 1; } } + +static inline void _print_digest(const uint8_t *digest, size_t len, const char *file) +{ + for (unsigned i = 0; i < len; ++i) { + printf("%02x", digest[i]); + } + printf(" %s\n", file); +} + +#if MODULE_MD5SUM +#include "hashes/md5.h" +int _vfs_md5sum_cmd(int argc, char **argv) +{ + int res; + uint8_t digest[MD5_DIGEST_LENGTH]; + + if (argc < 2) { + printf("usage: %s [file] …\n", argv[0]); + return -1; + } + + for (int i = 1; i < argc; ++i) { + const char *file = argv[i]; + res = vfs_file_md5(file, digest, + _shell_vfs_data_buffer, sizeof(_shell_vfs_data_buffer)); + if (res < 0) { + printf("%s: error %d\n", file, res); + } else { + _print_digest(digest, sizeof(digest), file); + } + } + + return 0; +} +#endif + +#if MODULE_SHA1SUM +#include "hashes/sha1.h" +int _vfs_sha1sum_cmd(int argc, char **argv) +{ + int res; + uint8_t digest[SHA1_DIGEST_LENGTH]; + + if (argc < 2) { + printf("usage: %s [file] …\n", argv[0]); + return -1; + } + + for (int i = 1; i < argc; ++i) { + const char *file = argv[i]; + res = vfs_file_sha1(file, digest, + _shell_vfs_data_buffer, sizeof(_shell_vfs_data_buffer)); + if (res < 0) { + printf("%s: error %d\n", file, res); + } else { + _print_digest(digest, sizeof(digest), file); + } + } + + return 0; +} +#endif + +#if MODULE_SHA256SUM +#include "hashes/sha256.h" +int _vfs_sha256sum_cmd(int argc, char **argv) +{ + int res; + uint8_t digest[SHA256_DIGEST_LENGTH]; + + if (argc < 2) { + printf("usage: %s [file] …\n", argv[0]); + return -1; + } + + for (int i = 1; i < argc; ++i) { + const char *file = argv[i]; + res = vfs_file_sha256(file, digest, + _shell_vfs_data_buffer, sizeof(_shell_vfs_data_buffer)); + if (res < 0) { + printf("%s: error %d\n", file, res); + } else { + _print_digest(digest, sizeof(digest), file); + } + } + + return 0; +} +#endif #endif diff --git a/sys/shell/commands/shell_commands.c b/sys/shell/commands/shell_commands.c index 33a948a4d2..1b82f5aeeb 100644 --- a/sys/shell/commands/shell_commands.c +++ b/sys/shell/commands/shell_commands.c @@ -215,6 +215,18 @@ extern int _bootloader_handler(int argc, char **argv); extern int _gnrc_udp_cmd(int argc, char **argv); #endif +#ifdef MODULE_MD5SUM +extern int _vfs_md5sum_cmd(int argc, char **argv); +#endif + +#ifdef MODULE_SHA1SUM +extern int _vfs_sha1sum_cmd(int argc, char **argv); +#endif + +#ifdef MODULE_SHA256SUM +extern int _vfs_sha256sum_cmd(int argc, char **argv); +#endif + const shell_command_t _shell_command_list[] = { {"reboot", "Reboot the node", _reboot_handler}, {"version", "Prints current RIOT_VERSION", _version_handler}, @@ -268,6 +280,15 @@ const shell_command_t _shell_command_list[] = { #ifdef MODULE_RTT_CMD {"rtt", "control RTC peripheral interface", _rtt_handler}, #endif +#ifdef MODULE_MD5SUM + {"md5sum", "Compute and check MD5 message digest", _vfs_md5sum_cmd}, +#endif +#ifdef MODULE_SHA1SUM + {"sha1sum", "Compute and check SHA1 message digest", _vfs_sha1sum_cmd}, +#endif +#ifdef MODULE_SHA256SUM + {"sha256sum", "Compute and check SHA256 message digest", _vfs_sha256sum_cmd}, +#endif #ifdef MODULE_GNRC_IPV6_NIB {"nib", "Configure neighbor information base", _gnrc_ipv6_nib}, #endif diff --git a/sys/vfs_util/vfs_util.c b/sys/vfs_util/vfs_util.c index a8ad75f3f5..adf7e7f13f 100644 --- a/sys/vfs_util/vfs_util.c +++ b/sys/vfs_util/vfs_util.c @@ -79,3 +79,78 @@ int vfs_file_to_buffer(const char* file, void* buf, size_t len) return res; } + +#if MODULE_HASHES +#include "hashes/md5.h" +#include "hashes/sha1.h" +#include "hashes/sha256.h" + +int vfs_file_md5(const char* file, void *digest, + void *work_buf, size_t work_buf_len) +{ + md5_ctx_t ctx; + + int res, fd = vfs_open(file, O_RDONLY, 0); + + if (fd < 0) { + DEBUG("can't open %s for reading\n", file); + return fd; + } + + md5_init(&ctx); + while ((res = vfs_read(fd, work_buf, work_buf_len)) > 0) { + md5_update(&ctx, work_buf, res); + } + md5_final(&ctx, digest); + + vfs_close(fd); + + return res > 0 ? 0 : res; +} + +int vfs_file_sha1(const char* file, void *digest, + void *work_buf, size_t work_buf_len) +{ + sha1_context ctx; + int res, fd = vfs_open(file, O_RDONLY, 0); + + if (fd < 0) { + DEBUG("can't open %s for reading\n", file); + return fd; + } + + sha1_init(&ctx); + while ((res = vfs_read(fd, work_buf, work_buf_len)) > 0) { + sha1_update(&ctx, work_buf, res); + } + sha1_final(&ctx, digest); + + vfs_close(fd); + + return res > 0 ? 0 : res; + +} + +int vfs_file_sha256(const char* file, void *digest, + void *work_buf, size_t work_buf_len) +{ + sha256_context_t ctx; + int res, fd = vfs_open(file, O_RDONLY, 0); + + if (fd < 0) { + DEBUG("can't open %s for reading\n", file); + return fd; + } + + sha256_init(&ctx); + while ((res = vfs_read(fd, work_buf, work_buf_len)) > 0) { + sha256_update(&ctx, work_buf, res); + } + sha256_final(&ctx, digest); + + vfs_close(fd); + + return res > 0 ? 0 : res; + +} +#endif /* MODULE_HASHES */