(유니티3D)JSON 과 AES 암호화
Icicle Game의 데이터 관리를 현재 PlayerPrefs를 이용하고 있었는데 장기적으로 봤을 때 PlayerPrefs는 썩 좋지 않은거 같아 계속 바꾸고 싶었습니다.
레지스트리로 저장되어 저장데이터 관리에 다소 불편함이 있고 저장도 제한적 자료형만 사용할 수 있으며 용량도 1M인가가 최대라고 들었거든요.
그래서 무엇으로 바꿀까 고민했습니다.
나중에 랭킹을 대비해서라도 미리 SQL을 활용하는 것도 나쁘진 않겠지만 지금은 아직 싱글 게임의 영역이기에 SQL까지 쓰기엔 과하다고 생각하여 다른 것을 찾아보던 중에 같이 수업 듣는 옆자리 분이 json을 쓰더군요.
그래서 기회라고 생각해서 물어보니 이게 또 유니티 내장 API 중에 하나였습니다.
더구나 사용법도 매우 간단하더군요.
방법은
[System.Serializable]
public class Info
{
public string _string;
public int _int;
public float _float;
}
적당히 직렬화 시킨 클래스를 하나 두던가
public struct _Info
{
public string _string;
public int _int;
public float _float;
}
구조체를 둡니다.
해보니 둘 다 잘 됩니다.
여기선 구조체로 하겠습니다. 가비지가 발생하지 않으니까요.
_Info info;
info._string = "테스트";
info._int = 34;
info._float = 1.234f;
string save = JsonUtility.ToJson(info);
File.WriteAllText(Path.Combine(Application.streamingAssetsPath, "jsonAssets.json"), save);
적당히 값을 설정해주고 JsonUtility.ToJson(info)를 통해 string으로 만들어줍니다.
그리고 이것을 그대로 저장해주면 됩니다. Application.streamingAssetsPath는 StreamingAssets폴더 경로인데 리소스 폴더랑 비슷하다고 보면 됩니다.
빌드를 할 때 해당 폴더 내의 외부파일도 같이 포함시켜줍니다.
이렇게 저장시키면 해당 폴더에 json 파일이 생겨납니다.
이제 이걸 불러와봅시다.
_Info info;
string load = File.ReadAllText(Path.Combine(Application.streamingAssetsPath, "jsonAssets.json"));
info = JsonUtility.FromJson<_Info>(load);
역순으로 불러오면됩니다.
구조체 자리를 마련해두고 File.ReadAllText로 동일 경로의 파일의 글을 전부 가져온 다음 JsonUtility.FromJson으로 형변환 시켜주면서 불러주면 됩니다.
이걸 그대로 로그 찍어보면
저장한 값이 그대로 출력됩니다!
매우 간단하면서 쉽게 파일화가 가능하여 유용한거 같습니다. 꽤 많은 사람들이 xml보다 json을 선호한다는 글도 본거 같네요.
다만 아쉽게도 이 방법만으론 배열이나 리스트를 저장하거나 불러올 수 없습니다.
아예 인식을 못하는지 아무 값도 들어가지 않더군요.
그래서 찾아보니 이미 이걸 위한 클래스를 누군가 만들어 뒀더군요.
http://debuglog.tistory.com/36
여길 참고하시면 좋을거 같습니다.
위 주소에서 JsonHelper 클래스를 가져온 다음 위에서 쓴 방법에서 JsonUtility 자리를 JsonHelper로 치환해 주고 인자에 배열을 넣어주면 저장, 불러오기가 잘 됩니다.
리스트의 경우엔 저장 전에 ToArray()로 배열화 시킨 다음 JsonHelper를 이용하면 됩니다.
불러올 때는 AddRange()로 다시 리스트에 넣으면 되구요.
개인적으론 단일, 배열, 리스트 정도만 저장/불러오기가 가능하면 대부분의 상황에서 충분하다고 생각합니다.
근데 아직 하나 남아있는 문제가 있습니다.
이는 꼭 json 만의 문제는 아니고 아마 이런식의 저장 데이터는 대부분 가질 문제입니다. PlayerPrefs방식도 동일하구요.
바로 저장 데이터를 너무 쉽게 볼 수 있다는 거지요.
그나마 PlayerPrefs의 경우엔 레지스트리에 저장되어 경로라도 다소 복잡한 곳에 위치해있지만 json의 경우엔 위와 같이 내부 폴더 어딘가에 위치할 가능성이 매우 높습니다.
그리고 대부분의 파일은 메모장에 끌어보면 글에 뜹니다.
위에서 저장한 json 파일을 그대로 메모장으로 열어본 화면입니다.
변수명까지 적나라하게 드러나네요.
이대로 수정해서 저장한 다음 불러오면 수정한 값이 그대로 저장됩니다.
이건 절대 개발자가 바라는 상황이 아니군요. 그러니 암호화까지 같이 해야할거 같습니다.
찾아보니 다양한 암호화 방식이 있었는데 그중 많이 쓰면서 아직까지도 높은 효율을 보이는 암호화로 AES 방식이 있더군요.
그리고 이 암호화는 C#자체에서도 지원해주는 기능 중 하나여서 쉽게 사용할 수 있을거 같습니다.
http://intro0517.tistory.com/37
이 블로그에 있는 코드를 사용했습니다.
그리 길지 않은 함수 2개로 암호화와 복호화가 가능합니다.
코드 분석은... 어지간해선 해보려고 하는데 이건 아예 무슨 소린지 모르겠네요. AES 암호화 방식에 대해 따로 검색하면 이론이 나오긴 합니다만 그냥 그정도로만 이해하고 있어야겠습니다.
아무튼 이 함수에 키를 대입하여 암호화를 한 후에 다시 저장과 불러오기를 해봅시다.
save = Encrypt(save, key);
load = Decrypt(load, key);
간단하게 각각 저장/불러오기 코드 사이에 위 코드 한 줄씩을 추가해줍니다.
그러면 유니티 상에서 저장과 불러오기의 결과는 동일하지만...
저장된 파일을 메모장으로 열어보면 이렇게 암호화가 된 것을 볼 수 있습니다.
여기서 키가 중요한데 암호화 시에 걸었던 키가 복호화 시 제시한 키와 다르면 정상적으로 불러와지지 않고 오류를 일으킵니다.
이 키가 노출되면 다른 사람도 AES를 활용하여 똑같이 복호화 할 수 있겠지만 이 키의 관리는 대놓고 파일로 공개되어 드러나는 것보다는 쉬울 것이라고 생각합니다.
'소소한 배움' 카테고리의 다른 글
Soft Body (Bullet Physics) (0) | 2018.02.24 |
---|---|
후처리(post processing) 개념 (0) | 2018.02.22 |
변수, 메서드 작명 (0) | 2018.01.12 |
(유니티3D)이벤트 함수의 실행 순서 (0) | 2017.12.17 |
(유니티3D)new Vector3는 힙? 스택? (0) | 2017.12.17 |