mirror of
git://f0xx.org/android_cast
synced 2026-07-29 06:58:51 +03:00
123 lines
2.9 KiB
C
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;
|
|
}
|