From f1b1880cf01a8abb6016954e51b46c453c3d6d94 Mon Sep 17 00:00:00 2001 From: Joel Klinghed Date: Sun, 19 Oct 2025 00:09:53 +0200 Subject: sha1: Add new module SHA1 hasher. Needed by websocket support that is coming soon. Using either libmd or openssl to do the actual hashing. --- meson.build | 38 ++++++++++++++++++++++++++++++++++++++ src/sha1.cc | 16 ++++++++++++++++ src/sha1.hh | 15 +++++++++++++++ src/sha1_md.cc | 16 ++++++++++++++++ src/sha1_openssl.cc | 13 +++++++++++++ test/sha1.cc | 17 +++++++++++++++++ 6 files changed, 115 insertions(+) create mode 100644 src/sha1.cc create mode 100644 src/sha1.hh create mode 100644 src/sha1_md.cc create mode 100644 src/sha1_openssl.cc create mode 100644 test/sha1.cc diff --git a/meson.build b/meson.build index b17ed18..7b751db 100644 --- a/meson.build +++ b/meson.build @@ -36,6 +36,8 @@ configure_file(input: 'src/config.h.in', configuration : conf_data) dbus_dep = dependency('sdbus-c++', version: '>= 2.0.0') +md_dep = dependency('libmd', version: '>= 1.0.0', required: false) +openssl_dep = dependency('openssl', version: '>= 1.0.0', required: false) inc = include_directories('src') @@ -203,6 +205,31 @@ base64_dep = declare_dependency( link_with: base64_lib, ) +if md_dep.found() + sha1_inner_source = 'src/sha1_md.cc' + sha1_inner_dep = md_dep +elif openssl_dep.found() + sha1_inner_source = 'src/sha1_openssl.cc' + sha1_inner_dep = openssl_dep +else + error('Need a library with SHA-1, either openssl or libmd') +endif + +sha1_lib = library( + 'sha1', + sources: [ + 'src/sha1.cc', + 'src/sha1.hh', + sha1_inner_source, + ], + include_directories: inc, + dependencies: [sha1_inner_dep], +) +sha1_dep = declare_dependency( + link_with: sha1_lib, + dependencies: [sha1_inner_dep], +) + bluetooth_jukebox = executable( 'bluetooth-jukebox', sources: [ @@ -355,6 +382,17 @@ test('base64', executable( ], )) +test('sha1', executable( + 'test_sha1', + sources: ['test/sha1.cc'], + include_directories: inc, + dependencies : [ + sha1_dep, + base64_dep, + test_dependencies, + ], +)) + run_clang_tidy = find_program('run-clang-tidy', required: false) if run_clang_tidy.found() diff --git a/src/sha1.cc b/src/sha1.cc new file mode 100644 index 0000000..5d20ca9 --- /dev/null +++ b/src/sha1.cc @@ -0,0 +1,16 @@ +#include "sha1.hh" + +namespace sha1 { + +std::array hash(std::span input) { + // std::string and std::string_view -> std::span includes null terminating + // byte. + if (!input.empty() && input.back() == '\0') { + return hash(std::span{reinterpret_cast(input.data()), + input.size() - 1}); + } + return hash( + std::span{reinterpret_cast(input.data()), input.size()}); +} + +} // namespace sha1 diff --git a/src/sha1.hh b/src/sha1.hh new file mode 100644 index 0000000..a885a09 --- /dev/null +++ b/src/sha1.hh @@ -0,0 +1,15 @@ +#ifndef SHA1_HH +#define SHA1_HH + +#include // IWYU pragma: export +#include // IWYU pragma: export +#include // IWYU pragma: export + +namespace sha1 { + +std::array hash(std::span input); +std::array hash(std::span input); + +} // namespace sha1 + +#endif // SHA1_HH diff --git a/src/sha1_md.cc b/src/sha1_md.cc new file mode 100644 index 0000000..274eb60 --- /dev/null +++ b/src/sha1_md.cc @@ -0,0 +1,16 @@ +#include "sha1.hh" + +#include + +namespace sha1 { + +std::array hash(std::span input) { + std::array ret; + SHA1_CTX ctx; + SHA1Init(&ctx); + SHA1Update(&ctx, input.data(), input.size()); + SHA1Final(ret.data(), &ctx); + return ret; +} + +} // namespace sha1 diff --git a/src/sha1_openssl.cc b/src/sha1_openssl.cc new file mode 100644 index 0000000..9e6d77e --- /dev/null +++ b/src/sha1_openssl.cc @@ -0,0 +1,13 @@ +#include "sha1.hh" + +#include + +namespace sha1 { + +std::array hash(std::span input) { + std::array ret; + SHA1(input.data(), input.size(), ret.data()); + return ret; +} + +} // namespace sha1 diff --git a/test/sha1.cc b/test/sha1.cc new file mode 100644 index 0000000..7441f01 --- /dev/null +++ b/test/sha1.cc @@ -0,0 +1,17 @@ +#include "sha1.hh" + +#include "base64.hh" + +#include + +TEST(Sha1, sanity) { + EXPECT_EQ("L9ThxnotKPzthJ7hu3bnORuT6xI=", + base64::encode( + sha1::hash("The quick brown fox jumps over the lazy dog"))); + + EXPECT_EQ("3p8sf9JeGzr60+haC9F9mxANtLM=", + base64::encode( + sha1::hash("The quick brown fox jumps over the lazy cog"))); + + EXPECT_EQ("2jmj7l5rSw0yVb/vlWAYkK/YBwk=", base64::encode(sha1::hash(""))); +} -- cgit v1.2.3-70-g09d2