아무런 처리 없이 PlayerPrefs를 사용할 경우 값이 그대로 노출되면서 접근이 가능하고, 프로그램 밖에서 값을 수정할 경우 수정된 값 그대로 프로그램에 적용되는 문제점이 있음.
using UnityEngine;
using System.Collections;
using System.Security.Cryptography;
using System.Text;
public class EncryptedPlayerPrefs {
// Encrypted PlayerPrefs
// Written by Sven Magnus
// MD5 code by Matthew Wegner (from [url]http://www.unifycommunity.com/wiki/index.php?title=MD5[/url])
// Modify this key in this file :
private static string privateKey="9ETrEsWaFRach3gexaDr";
// Add some values to this array before using EncryptedPlayerPrefs
public static string[] keys;
public static string Md5(string strToEncrypt) {
UTF8Encoding ue = new UTF8Encoding();
byte[] bytes = ue.GetBytes(strToEncrypt);
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
byte[] hashBytes = md5.ComputeHash(bytes);
string hashString = "";
for (int i = 0; i < hashBytes.Length; i++) {
hashString += System.Convert.ToString(hashBytes[i], 16).PadLeft(2, '0');
}
return hashString.PadLeft(32, '0');
}
public static void SaveEncryption(string key, string type, string value) {
int keyIndex = (int)Mathf.Floor(Random.value * keys.Length);
string secretKey = keys[keyIndex];
string check = Md5(type + "_" + privateKey + "_" + secretKey + "_" + value);
PlayerPrefs.SetString(key + "_encryption_check", check);
PlayerPrefs.SetInt(key + "_used_key", keyIndex);
}
public static bool CheckEncryption(string key, string type, string value) {
int keyIndex = PlayerPrefs.GetInt(key + "_used_key");
string secretKey = keys[keyIndex];
string check = Md5(type + "_" + privateKey + "_" + secretKey + "_" + value);
if(!PlayerPrefs.HasKey(key + "_encryption_check")) return false;
string storedCheck = PlayerPrefs.GetString(key + "_encryption_check");
return storedCheck == check;
}
public static void SetInt(string key, int value) {
PlayerPrefs.SetInt(key, value);
SaveEncryption(key, "int", value.ToString());
}
public static void SetFloat(string key, float value) {
PlayerPrefs.SetFloat(key, value);
SaveEncryption(key, "float", Mathf.Floor(value*1000).ToString());
}
public static void SetString(string key, string value) {
PlayerPrefs.SetString(key, value);
SaveEncryption(key, "string", value);
}
public static int GetInt(string key) {
return GetInt(key, 0);
}
public static float GetFloat(string key) {
return GetFloat(key, 0f);
}
public static string GetString(string key) {
return GetString(key, "");
}
public static int GetInt(string key,int defaultValue) {
int value = PlayerPrefs.GetInt(key);
if(!CheckEncryption(key, "int", value.ToString())) return defaultValue;
return value;
}
public static float GetFloat(string key, float defaultValue) {
float value = PlayerPrefs.GetFloat(key);
if(!CheckEncryption(key, "float", Mathf.Floor(value*1000).ToString())) return defaultValue;
return value;
}
public static string GetString(string key, string defaultValue) {
string value = PlayerPrefs.GetString(key);
if(!CheckEncryption(key, "string", value)) return defaultValue;
return value;
}
public static bool HasKey(string key) {
return PlayerPrefs.HasKey(key);
}
public static void DeleteKey(string key) {
PlayerPrefs.DeleteKey(key);
PlayerPrefs.DeleteKey(key + "_encryption_check");
PlayerPrefs.DeleteKey(key + "_used_key");
}
}
사용법은 PlayerPrefs의 사용법과 동일하다. (아래의 암호화를 위한 키를 추가한 후 사용하면 된다.)
EncryptedPlayerPrefs.keys=new string[5];
EncryptedPlayerPrefs.keys[0]="23Wrudre";
EncryptedPlayerPrefs.keys[1]="SP9DupHa";
EncryptedPlayerPrefs.keys[2]="frA5rAS3";
EncryptedPlayerPrefs.keys[3]="tHat2epr";
EncryptedPlayerPrefs.keys[4]="jaw3eDAs";
사용시 PlayerPrefs 클래스 대신 EncryptedPlayerPrefs을 사용하면 된다. 키값 전부 지워주는 것은 기존대로 PlayerPrefs꺼 가져다가 쓰면 됨. 추후 빌드시 난독화 과정을 거치면 어느정도 보안처리를 했다고 볼수 있겠지.
---- 10월 27일 추가.
위의 클래스를 사용하면 값이 그대로 보이기때문에, 이러한 문제를 해결하기위해서는 PlayerPrefs를 약간 가공해서 쓰는것도 한가지 방법이다.
이와 관련하여 암/복호화를 특정키를 사용하여 쉽게 할 수 있도록 하는 클래스는 검색하면 어느정도 나오니 그것을 이용해 구현하는 것이 적합.