|
|
@@ -0,0 +1,45 @@
|
|
|
+#include <openssl/evp.h>
|
|
|
+#include <openssl/sha.h>
|
|
|
+#include <fstream>
|
|
|
+#include <vector>
|
|
|
+#include <stdexcept>
|
|
|
+#include <iomanip>
|
|
|
+#include <sstream>
|
|
|
+#include <string>
|
|
|
+#include <array>
|
|
|
+
|
|
|
+std::string sha256_file(const std::string& path) {
|
|
|
+ std::ifstream f(path, std::ios::binary);
|
|
|
+ if (!f) throw std::runtime_error("Cannot open file: " + path);
|
|
|
+
|
|
|
+ EVP_MD_CTX* ctx = EVP_MD_CTX_new();
|
|
|
+ if (!ctx) throw std::runtime_error("EVP_MD_CTX_new failed");
|
|
|
+ const EVP_MD* md = EVP_sha256();
|
|
|
+ if (EVP_DigestInit_ex(ctx, md, nullptr) != 1) {
|
|
|
+ EVP_MD_CTX_free(ctx);
|
|
|
+ throw std::runtime_error("EVP_DigestInit_ex failed");
|
|
|
+ }
|
|
|
+
|
|
|
+ std::vector<char> buf(1 << 20); // 1 MiB chunks
|
|
|
+ while (f) {
|
|
|
+ f.read(buf.data(), buf.size());
|
|
|
+ std::streamsize n = f.gcount();
|
|
|
+ if (n > 0 && EVP_DigestUpdate(ctx, buf.data(), static_cast<size_t>(n)) != 1) {
|
|
|
+ EVP_MD_CTX_free(ctx);
|
|
|
+ throw std::runtime_error("EVP_DigestUpdate failed");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ std::array<unsigned char, SHA256_DIGEST_LENGTH> out{};
|
|
|
+ unsigned int outlen = 0;
|
|
|
+ if (EVP_DigestFinal_ex(ctx, out.data(), &outlen) != 1) {
|
|
|
+ EVP_MD_CTX_free(ctx);
|
|
|
+ throw std::runtime_error("EVP_DigestFinal_ex failed");
|
|
|
+ }
|
|
|
+ EVP_MD_CTX_free(ctx);
|
|
|
+
|
|
|
+ std::ostringstream oss;
|
|
|
+ for (size_t i = 0; i < outlen; ++i)
|
|
|
+ oss << std::hex << std::setw(2) << std::setfill('0') << (int)out[i];
|
|
|
+ return oss.str();
|
|
|
+}
|