1
0
mirror of git://f0xx.org/ac/ac-mobile-android synced 2026-07-29 07:57:41 +03:00
Files
ac-mobile-android/ndk/obfuscate/obfuscate.c
Anton Afanasyeu 8675c2df3a initial
2026-06-23 12:30:10 +02:00

123 lines
2.9 KiB
C

#include "obfuscate.h"
#include <stddef.h>
static uint16_t rotl16(uint16_t x, unsigned int n)
{
n &= 15u;
return (uint16_t)((x << n) | (x >> (16u - n)));
}
static uint64_t rotl40(uint64_t x, unsigned int n)
{
n %= OBF_PAYLOAD_BITS;
x &= OBF_PAYLOAD_MASK;
if (n == 0u)
return x;
return ((x << n) | (x >> (OBF_PAYLOAD_BITS - n))) & OBF_PAYLOAD_MASK;
}
static uint64_t rotr40(uint64_t x, unsigned int n)
{
n %= OBF_PAYLOAD_BITS;
x &= OBF_PAYLOAD_MASK;
if (n == 0u)
return x;
return ((x >> n) | (x << (OBF_PAYLOAD_BITS - n))) & OBF_PAYLOAD_MASK;
}
/* Lightweight seed mixer — same output for same seed on any platform. */
static uint64_t derive_key(uint64_t seed)
{
uint64_t x = seed ^ 0xA5A5A5A5A5A5A5A5ULL;
x ^= x >> 33;
x *= 0xFF51AFD7ED558CCDULL;
x ^= x >> 33;
x *= 0xC4CEB9FE1A85EC53ULL;
x ^= x >> 33;
return x & OBF_PAYLOAD_MASK;
}
static unsigned int derive_rotation(uint64_t seed)
{
uint64_t mix = seed * 0x9E3779B97F4A7C15ULL;
return (unsigned int)((mix >> 59) + 1u); /* 1..8 */
}
/*
* 24-bit FEC-style tag: four 16-bit shards XOR-mixed with key and seed.
* Detects single-bit flips and wrong seed with high probability.
*/
static uint32_t compute_tag(uint64_t val, uint64_t seed)
{
uint64_t k = derive_key(seed);
uint64_t a = (val & 0xFFFFULL) ^ (k & 0xFFFFULL);
uint64_t b = ((val >> 16) & 0xFFFFULL) ^ ((k >> 16) & 0xFFFFULL);
uint64_t c = ((val >> 32) & 0xFFFFULL) ^ ((k >> 32) & 0xFFFFULL);
uint64_t d = ((val >> 48) & 0xFFFFULL) ^ ((k >> 48) & 0xFFFFULL);
uint64_t p1 = a ^ rotl16((uint16_t)b, 3) ^ c;
uint64_t p2 = b ^ rotl16((uint16_t)c, 7) ^ d;
uint64_t p3 = c ^ rotl16((uint16_t)d, 11) ^ a;
uint64_t mix = (p1 * 0x01000193ULL) ^ (p2 << 16) ^ (p3 << 8);
mix ^= seed;
mix *= 0x85EBCA77C2B2AE63ULL;
mix ^= mix >> 33;
return (uint32_t)(mix & 0xFFFFFFULL);
}
static uint64_t obfuscate(uint64_t val, uint64_t seed)
{
uint64_t key = derive_key(seed);
unsigned int rot = derive_rotation(seed);
return rotl40(val & OBF_PAYLOAD_MASK, rot) ^ key;
}
static uint64_t deobfuscate(uint64_t obscured, uint64_t seed)
{
uint64_t key = derive_key(seed);
unsigned int rot = derive_rotation(seed);
return rotr40(obscured ^ key, rot);
}
int32_t encode(uint64_t val, uint64_t seed, uint64_t *out)
{
uint64_t packed;
uint32_t tag;
if (out == NULL)
return OBF_ERR_NULL;
if (val > OBF_PAYLOAD_MASK)
return OBF_ERR_RANGE;
tag = compute_tag(val, seed);
packed = ((uint64_t)tag << OBF_PAYLOAD_BITS) | obfuscate(val, seed);
*out = packed;
return OBF_OK;
}
int32_t decode(uint64_t encoded_val, uint64_t seed, uint64_t *out)
{
uint32_t stored_tag;
uint32_t expected_tag;
uint64_t obscured;
uint64_t val;
if (out == NULL)
return OBF_ERR_NULL;
stored_tag = (uint32_t)(encoded_val >> OBF_PAYLOAD_BITS);
obscured = encoded_val & OBF_PAYLOAD_MASK;
val = deobfuscate(obscured, seed);
expected_tag = compute_tag(val, seed);
if (stored_tag != expected_tag)
return OBF_ERR_VERIFY;
*out = val;
return OBF_OK;
}