Quick answer: Decide what you actually need: use an HMAC for tamper detection, and only add authenticated encryption (AES-GCM) if the contents must stay secret, with a key the client cannot trivially read.

Your save looks scrambled, so it feels protected. But base64 is just an encoding and a constant XOR key is recovered in seconds, so a player still reads and edits the data. Be honest about the goal: hiding contents versus detecting edits are different problems with different fixes.

How to fix it

1. Pick the real requirement

If you only need to stop edits, an HMAC is enough and simpler. If you must hide the contents (for example, a stored answer key), you need encryption, not obfuscation.

2. Use authenticated encryption

If you encrypt, use AES-GCM or similar so the same operation gives confidentiality and integrity. Never roll a custom cipher or reuse a nonce, and never ship a single global key in clear in the binary.

3. Accept client-side limits

A fully offline client must hold the key somewhere, so a determined attacker on their own device can extract it. Server-side validation is the only true protection for competitive values; client crypto just raises the bar.

Catching the ones you can't reproduce

The hardest version of this to fix is the one you can't reproduce — it only happens on a player's hardware, OS, driver, or save state, under conditions that simply aren't present on your machine. A report that says “it crashed” or “it froze” gives you nothing to act on, so the bug survives release after release while quietly costing you players.

Automatic error capture closes that gap. Each failure arrives with its full stack trace, the device and OS, the build number, and a breadcrumb trail of what the player did right before it broke, so even a failure you have never seen becomes a specific, reproducible issue. Fold identical failures into one signature ranked by how many players each hits, and your worklist sorts itself worst-first instead of arriving as a stream of vague complaints.

This is where a tool like Bugnet earns its place. Its SDK captures every error automatically with the full stack trace plus device, OS, memory, build, and game-state context, folds duplicates into one grouped issue with an occurrence count, and ties each to the build it first appeared on — so you fix the problem that hurts the most players first and confirm it is gone when its signature disappears from the next release.

A crash you can name from its stack trace is a crash you can usually fix in minutes.