From 2278df1493e064c197913e49b5d1935942d83448 Mon Sep 17 00:00:00 2001 From: daniel Date: Tue, 6 May 2025 16:57:32 -0700 Subject: initial import --- src/hash_ledger.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 src/hash_ledger.c (limited to 'src/hash_ledger.c') diff --git a/src/hash_ledger.c b/src/hash_ledger.c new file mode 100644 index 0000000..5ae1939 --- /dev/null +++ b/src/hash_ledger.c @@ -0,0 +1,184 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "djb2.h" +#include "entropy.h" +#include "md5.h" +#include "md5/global.h" +#include "md5/md5.h" +#include "sha256.h" +#include "hash_ledger.h" + + +static void hexify(const unsigned char *in, size_t len, char *out) { + for (size_t i = 0; i < len; i++) { + sprintf(out + (i * 2), "%02x", in[i]); + } + + out[len * 2] = '\0'; +} + +size_t hash_ledger_bucket(struct hash_ledger *ledger, const char *path) { + return djb2(path) % ledger->num_buckets; +} + +struct hash_ledger *hash_ledger_init(size_t num_buckets) { + struct hash_ledger *ledger = calloc(1, sizeof(struct hash_ledger)); + if (!ledger) { + return NULL; + } + + ledger->num_buckets = num_buckets; + ledger->buckets = calloc(num_buckets, sizeof(struct hash_entry *)); + if (!ledger->buckets) { + free(ledger); + return NULL; + } + + return ledger; +} + +void hash_ledger_destroy(struct hash_ledger *ledger) { + if (!ledger) { + return; + } + + for (size_t i = 0; i < ledger->num_buckets; i++) { + struct hash_entry *entry = ledger->buckets[i]; + while (entry) { + struct hash_entry *next = entry->next; + free(entry); + entry = next; + } + } + + free(ledger->buckets); + free(ledger); +} + +struct hash_entry *hash_ledger_find(struct hash_ledger *ledger, const char *path) { + if (!ledger || !path) { + return NULL; + } + + size_t idx = hash_ledger_bucket(ledger, path); + struct hash_entry *entry = ledger->buckets[idx]; + + while (entry) { + if (strcmp(entry->path, path) == 0) { + return entry; + } + + entry = entry->next; + } + + return NULL; +} + +struct hash_entry *hash_ledger_add_or_update(struct hash_ledger *ledger, + const char *path, + struct stat *sb) { + if (!ledger || !path || !sb) { + return NULL; + } + + struct hash_entry *entry = hash_ledger_find(ledger, path); + + if (entry) { + if (entry->sb.st_ino != sb->st_ino || + entry->sb.st_mtime != sb->st_mtime || + entry->sb.st_size != sb->st_size) { + // file changed. must rehash + struct multihash hashes; + if (multihash_file(path, &hashes)) { + entry->entropy = hashes.entropy; + memcpy(entry->md5, hashes.md5, sizeof(entry->md5)); + memcpy(entry->sha256, hashes.sha256, sizeof(entry->sha256)); + } + memcpy(&entry->sb, sb, sizeof(struct stat)); + entry->last_scanned = 0; // force rescan + entry->scan_count = 0; + entry->verdict = VERDICT_UNKNOWN; + //entry->last_scanned = time(NULL); + } + + // hash found. increment scan count + //entry->scan_count++; + return entry; + } + + // not found. create new entry + entry = calloc(1, sizeof(struct hash_entry)); + if (!entry) { + return NULL; + } + + strncpy(entry->path, path, sizeof(entry->path) - 1); + memcpy(&entry->sb, sb, sizeof(struct stat)); + //entry->last_scanned = time(NULL); + //entry->scan_count = 1; + entry->last_scanned = 0; + entry->scan_count = 0; + entry->verdict = VERDICT_UNKNOWN; + memset(entry->matched_rules, 0, sizeof(entry->matched_rules)); + + struct multihash hashes; + if (multihash_file(path, &hashes)) { + entry->entropy = hashes.entropy; + memcpy(entry->md5, hashes.md5, sizeof(entry->md5)); + memcpy(entry->sha256, hashes.sha256, sizeof(entry->sha256)); + } + + size_t idx = hash_ledger_bucket(ledger, path); + entry->next = ledger->buckets[idx]; + ledger->buckets[idx] = entry; + + return entry; +} + +bool multihash_file(const char *path, struct multihash *out) { + if (!path || !out) { + return false; + } + + FILE *fp = fopen(path, "rb"); + if (!fp) { + return false; + } + + unsigned char buf[8192]; + size_t n; + MD5_CTX md5_ctx; + SHA256_CTX sha256_ctx; + entropy_ctx ent_ctx; + + MD5Init(&md5_ctx); + sha256_init(&sha256_ctx); + entropy_init(&ent_ctx); + + while((n = fread(buf, 1, sizeof(buf), fp)) > 0) { + MD5Update(&md5_ctx, buf, n); + sha256_update(&sha256_ctx, buf, n); + entropy_update(&ent_ctx, buf, n); + } + + fclose(fp); + + out->entropy = entropy_final(&ent_ctx); + + unsigned char md5_result[MD5_DIGEST_LENGTH]; + MD5Final(md5_result, &md5_ctx); + hexify(md5_result, sizeof(md5_result), out->md5); + + unsigned char sha256_result[SHA256_DIGEST_LENGTH]; + sha256_final(&sha256_ctx, sha256_result); + hexify(sha256_result, sizeof(sha256_result), out->sha256); + + return true; +} -- cgit v1.2.3