- Home /
How to encrypt a variable before storing it in the device via PlayerPrefs?
Hi,
I store player's coins in PlayerPrefs for Android version of the game but it can easily be opened and hacked away.
Is there any way to encrypt the integer and then store it via PlayerPrefs and then read it and decrypt and use it?
I have an MD5 hash function for my leaderboard, so can I store it as MD5 hash and read it via MD5 hash or something like that? Like contacting it with a secret key and then computing MD5 hash over it.
Thanks.
Answer by queequeg · Mar 17, 2014 at 03:30 PM
The following code allows you to store an integer number in the playerpref variable string _RegString using RSA encryption. I used this to check how many times a program had been run since it was installed. This value cannot be altered without knowing the encryption key. However the value could still be deleted from the registry causing the counter to reset.
using UnityEngine;
using System.Collections;
using System.Security.Cryptography;
using System.Text;
using System;
using System.IO;
using System.Globalization;
public class EncryptedPlayerPref : MonoBehaviour {
void Awake() {
// For encrypting number in player pref.
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = "ThisIsAKey"; // This is the key used to encrypt and decrypt can be anything.
var provider = new RSACryptoServiceProvider(cspParams);
// Check if _RegString exsists, if not create it with an encrypted value of -1
if (PlayerPrefs.GetString ("_RegString") == "") {
byte[] tempencryptedBytes = provider.Encrypt (
System.Text.Encoding.UTF8.GetBytes ("-1"), true);
string tempencryptionString = Convert.ToBase64String (tempencryptedBytes); // convert to base64string for storage
PlayerPrefs.SetString ("_RegString", tempencryptionString);// store in player pref
}
// Get the value stored in RegString and decrypt it using the key.
string decrypted = System.Text.Encoding.UTF7.GetString(
provider.Decrypt (Convert.FromBase64String(PlayerPrefs.GetString("RegString")) , true));
int counter = 0; // initalise a counter integer variable
int.TryParse (decrypted, out counter); // parse the decrypted string into an int. Potential errors not dealt with here.
// check if program has been ran more than 5 times
if(counter> 4)
{
print("Program ran more than 5 times");
}
else{
// if not increment the counter and store it encrypted into player pref.
counter += 1;
byte[] encryptedBytes = provider.Encrypt(
System.Text.Encoding.UTF8.GetBytes(counter.ToString()), true);
// convert to base64string first for storage as a string in the registry.
string encryptionString = Convert.ToBase64String(encryptedBytes);
PlayerPrefs.SetString ("_RegString", encryptionString);
}
print("This is the counter : " + counter.ToString());
}
}
Answer by Benproductions1 · Mar 17, 2014 at 10:30 AM
A Hash function is one way, ie. You can hash something but you can never unhash it, which is the whole point why hashes exist, for comparative information, such as passwords.
A per "cheater" security there is not a lot you can do. Even if you set up some form of encryption of your data, the users are still able to modify the variables at runtime through a memory editor. The only way you can be entirely secure is through a bullet-proof online system that runs the game itself. Even then it can't prevent people from writing bots to play for them.
This is an excellent discussion about the topic. In the end there is really nothing you can do without hurting your users considerably. As long as hackers aren't hurting other users, why not just let them hack away.
I know it's not an easy task but I was after something $$anonymous$$imum that prevents everyone from opening the local PlayerPrefs data and change their highscore and coins, especially coins.
For example, write the encrypted value ins$$anonymous$$d of plain integer.
You could use a XOR "encryption" on your data before writing them. It's no way a strong encryption but it's better than nothing and easy to implement. Info here: http://www.tech-faq.com/xor-encryption.html. You could also store a kind of checksum of the integer values you write to see if someone modified it.
If security isn't a real concern, then store the data as a float. They are not easily modifiable (at least harder than ints and strings) because they're not stored in the decimal form.
The only thing you need to do is a cast or two when reading and writing.
@Jamora: I casted my int to float and stored it via SetFloat but it's still plain number in the .plist when I open it in OS X.
"The only way you can be entirely secure is through a bullet-proof online system that runs the game itself."
That is wrong on many levels, but I would write that it does require to think outside the box.
Secured data handling can be done by simply doing double checks now and and by using multiple sources to store values.
Double checks are super easy. Just do a quick check with basic values whenever an action is done. For example, in a RPG, put checkers at key points where stats are compared to the character's level. When the value total in stats exceed the possible max from the level gained, just force-drop the stats within acceptable level. If you want to trick the cheater even more, make it so that cheaters only see their cheated stats while the game is using "real" stats after a drop adjustment. You would be surprised by how many would end up retrying stuff again and again or complain that the game is broken.
The positive thing about the double-check method is that it allow "realistic" changes never the less. Like having a change of heart and wanting to change the stats, class or whatever without going through hours of gameplay. (That is if you don't put, in the game, a way to directly do it.)
The multiple-source to store method is a bit more complex. To put it simple, keep data in 2 or 3 different places and keep them stored differently. For example, use 3 different switch-based converter that changes different kind of values into numbers. In one of my games, I'm using a String, a Vector3 and the regular pure int value. When formatted into binaries, those 3 values have little in common and 2 of them requires them to be converted when saving and loading. The Vector3 conversion is done by a simple algorithm mixing x, y and z values and the string is using a switch statement that convert chars into numbers.
This method makes it difficult to use data injection because the one key point about data injection is that it's handled by a 3rd party software that doesn't run exactly in frame-by-frame with the game engine. If you check the values of those 3 types of data within a closed function, they are run within a single frame in Unity and having a variation between the 3 values means there's an attempt to cheat and you're free to do whatever you want against the cheater at this point.
Is it possible to bypass those 2 methods? Yes it's possible, but it requires a lot of computing power and the gain as astronomically small, hence those who makes tools usually makes the tools for themselves as, otherwise, those usually don't work because of user-based cases. So, no money to be made out of it makes it a target for hobby hacker (which is far fewer than commercial hackers).
Answer by haim96 · Mar 17, 2014 at 02:58 PM
watch this live session video about saving and loading data in unity.
in this video you will learn how to save data with serialization (instead of playpref) this way the data is much less readable outside the game. on top of this you can add any encryption layer you want, if you think it needed.
As an extra, take care of file write exception on some platforms while following this system
Answer by sherjeel-sak · Jun 21, 2020 at 09:45 AM
Use this tool for encryption. it also provides to save data in encryption file and SQLite database. It is complete solution for Encryption and SQLite Database. It is easy to use. Check its YouTube video for further understanding https://assetstore.unity.com/packages/slug/149417
Your answer
Follow this Question
Related Questions
RTS Multiplayer Synchronization Check 0 Answers
How can I generate Hash128 from assetfile? 1 Answer
Best way to save to playerprefs scriptableObjects 0 Answers
Using Objective C scripts with Unity 0 Answers
PlayerPrefs Question 0 Answers