#include "obfuscate_file.h" #include #include #include static uint32_t dummy_u32(uint64_t seed, uint32_t salt) { uint64_t x = seed ^ ((uint64_t)salt * 0x9E3779B97F4A7C15ULL); x ^= x >> 33; x *= 0xFF51AFD7ED558CCDULL; x ^= x >> 33; return (uint32_t)(x ^ (x >> 32)); } static void put_u32_le(uint8_t *dst, uint32_t v) { dst[0] = (uint8_t)(v); dst[1] = (uint8_t)(v >> 8); dst[2] = (uint8_t)(v >> 16); dst[3] = (uint8_t)(v >> 24); } static void put_u64_le(uint8_t *dst, uint64_t v) { unsigned int i; for (i = 0; i < 8u; i++) dst[i] = (uint8_t)(v >> (8u * i)); } static uint32_t get_u32_le(const uint8_t *src) { return (uint32_t)src[0] | ((uint32_t)src[1] << 8) | ((uint32_t)src[2] << 16) | ((uint32_t)src[3] << 24); } static uint64_t get_u64_le(const uint8_t *src) { uint64_t v = 0; unsigned int i; for (i = 0; i < 8u; i++) v |= (uint64_t)src[i] << (8u * i); return v; } int32_t obf_file_payload_count(long file_size, size_t *count_out) { long payload_bytes; if (file_size < 0) return OBF_ERR_IO; if ((unsigned long)file_size < OBF_FILE_OVERHEAD + sizeof(uint64_t)) return OBF_ERR_FORMAT; payload_bytes = file_size - (long)OBF_FILE_OVERHEAD; if (payload_bytes % (long)sizeof(uint64_t) != 0) return OBF_ERR_FORMAT; *count_out = (size_t)payload_bytes / sizeof(uint64_t); return OBF_OK; } static int32_t write_encoded_file(const char *path, const uint64_t *encoded, size_t count, uint64_t seed) { FILE *fp; uint8_t hdr[OBF_FILE_HDR_SIZE]; uint8_t tail[OBF_FILE_TAIL_SIZE]; uint8_t block[sizeof(uint64_t)]; size_t i; if (path == NULL || encoded == NULL || count == 0) return OBF_ERR_NULL; fp = fopen(path, "wb"); if (fp == NULL) return OBF_ERR_IO; put_u32_le(hdr, dummy_u32(seed, 0xA11CEu)); if (fwrite(hdr, 1, sizeof(hdr), fp) != sizeof(hdr)) { fclose(fp); return OBF_ERR_IO; } for (i = 0; i < count; i++) { put_u64_le(block, encoded[i]); if (fwrite(block, 1, sizeof(block), fp) != sizeof(block)) { fclose(fp); return OBF_ERR_IO; } } put_u32_le(tail, dummy_u32(seed, 0x7A1Lu)); if (fwrite(tail, 1, sizeof(tail), fp) != sizeof(tail)) { fclose(fp); return OBF_ERR_IO; } if (fclose(fp) != 0) return OBF_ERR_IO; return OBF_OK; } int32_t write_many_to(const char *path, const uint64_t *vals, size_t count, uint64_t seed) { uint64_t *encoded; size_t i; int32_t rv; if (path == NULL || vals == NULL || count == 0) return OBF_ERR_NULL; encoded = (uint64_t *)malloc(count * sizeof(uint64_t)); if (encoded == NULL) return OBF_ERR_IO; for (i = 0; i < count; i++) { rv = encode(vals[i], seed, &encoded[i]); if (rv != OBF_OK) { free(encoded); return rv; } } rv = write_encoded_file(path, encoded, count, seed); free(encoded); return rv; } int32_t write_to(const char *path, uint64_t val, uint64_t seed) { return write_many_to(path, &val, 1, seed); } int32_t read_many_from(const char *path, uint64_t seed, uint64_t *out_vals, size_t out_cap, size_t *out_count) { FILE *fp; long file_size; size_t count; size_t i; uint8_t hdr[OBF_FILE_HDR_SIZE]; uint8_t tail[OBF_FILE_TAIL_SIZE]; uint8_t block[sizeof(uint64_t)]; uint64_t encoded; uint64_t decoded; int32_t rv; if (path == NULL || out_vals == NULL || out_count == NULL) return OBF_ERR_NULL; fp = fopen(path, "rb"); if (fp == NULL) return OBF_ERR_IO; if (fseek(fp, 0, SEEK_END) != 0) { fclose(fp); return OBF_ERR_IO; } file_size = ftell(fp); if (file_size < 0 || fseek(fp, 0, SEEK_SET) != 0) { fclose(fp); return OBF_ERR_IO; } rv = obf_file_payload_count(file_size, &count); if (rv != OBF_OK) { fclose(fp); return rv; } if (count > out_cap) { fclose(fp); return OBF_ERR_OVERFLOW; } if (fread(hdr, 1, sizeof(hdr), fp) != sizeof(hdr)) { fclose(fp); return OBF_ERR_IO; } (void)get_u32_le(hdr); for (i = 0; i < count; i++) { if (fread(block, 1, sizeof(block), fp) != sizeof(block)) { fclose(fp); return OBF_ERR_IO; } encoded = get_u64_le(block); rv = decode(encoded, seed, &decoded); if (rv != OBF_OK) { fclose(fp); return rv; } out_vals[i] = decoded; } if (fread(tail, 1, sizeof(tail), fp) != sizeof(tail)) { fclose(fp); return OBF_ERR_IO; } (void)get_u32_le(tail); fclose(fp); *out_count = count; return OBF_OK; } int32_t read_from(const char *path, uint64_t seed, uint64_t *out) { size_t count = 0; return read_many_from(path, seed, out, 1, &count); }