일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- 오블완
- 티스토리챌린지
- unity게임만들기
- 시샵
- c# c#프로그래머스
- c#기본문법
- unity공부
- c#
- unity3d
- 유니티3dui
- 스파르타코딩클럽
- c#프로그래머스기초문법
- 유니티
- 유니티상호작용
- 유니티공부
- C++문법
- C#문법
- c#코테
- 스파르타
- c# 백준
- unity3dservival
- c#문제
- 유니티서바이벌게임만들기
- Unity
- c#코딩기초트레이닝
- unity게임
- 유니티게임만들기
- 시샵문법
- c#기초문법
- unity3d게임만들기
- Today
- Total
나 개발자 진짜 되냐?
[ 11月 4日 ] 오늘 내가 배운 것 _ 35日次_JSON 암호화 (AES) 본문
오늘 특강에서
직렬화를 배웠다.
예전에 내 친구가
직렬화를 아주 쉽게 설명해주었던 기억이 난다.
김밥을 직렬화 하면
김 밥 햄 계란 당근 등등으로 다 흩어져서 저장되었다가
역직렬화를 하면
김밥이 말아지는 형태가 되는 것이다.
이 직렬화를 하는 종류는 다양한데..
[ C# 기본 문법 24 ] 직렬화 Serialization & 역직렬화 Deserialization
이번에 큰마음 먹고 시작한게임 저장기능.. 저장과 불러오기를 통해알게된 직렬화 자바에 있다던..자바에서는 쉽다던..하지만 여기선..쉽지않은직렬화!!! 그 친구에 대해 탐구해보자.직렬화
qua28.tistory.com
종류는 적어놓았다.
그 중에서 자주쓰이는 JSON
이친구에게는 치명적인 단점이 있다.
암호화에 약하다.
즉
Json 파일로 데이터를 저장하는 것은 간편하지만,
파일이 그대로 노출되면 데이터가 쉽게 읽힐 수 있다.
민감한 데이터는 암호화하여 저장하는 것이 좋기에
Unity에서 Json 파일을 암호화하여 저장하고 불러오는 방법을
정리해보자.
자 먼저,
암호화와 복호화를 위해
난수를 왕 만들어보자!
using System.Security.Cryptography;
이 친구를 써주고 시작하자!
private byte[] key; // 암호화에 사용되는 키
private byte[] iv; // 초기화 벡터
private readonly string keyPath = Path.Combine(Application.persistentDataPath, "aesKey.dat");
private readonly string ivPath = Path.Combine(Application.persistentDataPath, "aesIV.dat");
public AESCrypto()
{
if (File.Exists(keyPath) && File.Exists(ivPath)) // 키와 IV가 존재하는 지 확인
{
// 존재한다면 해당 키와 IV를 읽어옴
key = File.ReadAllBytes(keyPath);
iv = File.ReadAllBytes(ivPath);
}
else
{
// 없다면 다시 생성
key = GenerateRandomBytes(32); // 256-bit key
iv = GenerateRandomBytes(16); // 128-bit IV
File.WriteAllBytes(keyPath, key);
File.WriteAllBytes(ivPath, iv);
}
}
// 지정된 길이의 랜덤 바이트 배열을 생성
private byte[] GenerateRandomBytes(int length)
{
byte[] randomBytes = new byte[length];
// RNGCryptoServiceProvider : 난수 발생기
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(randomBytes);
}
return randomBytes;
}
암호화를 하기위해서는 난수생성은 필수이다.
해주고 나서
밑에서는
위에서 만든 함수를 가지고
Json을 암호화 복호화를 진행한다.
public string EncryptString(string plainText)
{
// AES 객체와 같은 암호화 객체는 네이티브 리소스를 사용하므로 사용후에 반드시 해제해야한다.
// using을 사용하여 작업이 끝난 후에 자동으로 리소스가 해제되게 설계했다.
// 네이티브 리소스는 운영 체제나 하드웨어와 직접적으로 상호작용하는 리소스 (GC에 의해 자동으로 관리되지 않기 떄문에 수동으로 해제해줘야 함)
using (Aes aesAlg = Aes.Create()) // AES 알고리즘 생성
{
// 키, IV 설정
aesAlg.Key = key;
aesAlg.IV = iv;
// 암호화 변환기를 생성
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// 평문 텍스트를 암호화
byte[] encrypted = encryptor.TransformFinalBlock(Encoding.UTF8.GetBytes(plainText), 0, plainText.Length);
// 암호화된 바이트 배열을 Base64 문자열로 변환 후 반환
return System.Convert.ToBase64String(encrypted);
}
}
public string DecryptString(string cipherText) // 복호화 함수
{
// Base64 문자열을 바이트 배열로 변환
byte[] buffer = System.Convert.FromBase64String(cipherText);
using (Aes aesAlg = Aes.Create()) // AES 알고리즘 생성
{
// 키, IV 설정
aesAlg.Key = key;
aesAlg.IV = iv;
// 복호화 변환기를 생성
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// 암호화된 바이트 배열을 복호화
byte[] decrypted = decryptor.TransformFinalBlock(buffer, 0, buffer.Length);
// 복호화된 바이트 배열을 UTF-8 문자열로 변환 후 반환
return Encoding.UTF8.GetString(decrypted);
}
}
사용 할 때!
PlayerDataManager.cs
using UnityEngine;
using System.IO;
public class PlayerDataManager : MonoBehaviour
{
private AESCrypto crypto;
private string path;
private void Awake()
{
crypto = new AESCrypto();
path = Path.Combine(Application.persistentDataPath, "PlayerData.json");
}
public void DataSave(PlayerSaveData playerData)
{
string json = JsonUtility.ToJson(playerData, true); // 데이터 직렬화
string encryptedJson = crypto.EncryptString(json); // 직렬화 된 데이터 암호화
File.WriteAllText(path, encryptedJson);
}
public void DataLoad()
{
if (!File.Exists(path))
{
Debug.Log("데이터가 존재하지 않습니다 !");
return;
}
string encryptedJson = File.ReadAllText(path); // 암호화된 데이터 읽어옴
string json =crypto.DecryptString(encryptedJson); // 복호화 및 역직렬화
PlayerSaveData playerData = JsonUtility.FromJson<PlayerSaveData>(json);
}
}
AESCrypto.cs
using System.IO;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
public class AESCrypto
{
private byte[] key; // 암호화에 사용되는 키
private byte[] iv; // 초기화 벡터
private readonly string keyPath = Path.Combine(Application.persistentDataPath, "aesKey.dat");
private readonly string ivPath = Path.Combine(Application.persistentDataPath, "aesIV.dat");
public AESCrypto()
{
if (File.Exists(keyPath) && File.Exists(ivPath)) // 키와 IV가 존재하는 지 확인
{
// 존재한다면 해당 키와 IV를 읽어옴
key = File.ReadAllBytes(keyPath);
iv = File.ReadAllBytes(ivPath);
}
else
{
// 없다면 다시 생성
key = GenerateRandomBytes(32); // 256-bit key
iv = GenerateRandomBytes(16); // 128-bit IV
File.WriteAllBytes(keyPath, key);
File.WriteAllBytes(ivPath, iv);
}
}
// 지정된 길이의 랜덤 바이트 배열을 생성
private byte[] GenerateRandomBytes(int length)
{
byte[] randomBytes = new byte[length];
// RNGCryptoServiceProvider : 난수 발생기
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(randomBytes);
}
return randomBytes;
}
public string EncryptString(string plainText)
{
// AES 객체와 같은 암호화 객체는 네이티브 리소스를 사용하므로 사용후에 반드시 해제해야한다.
// using을 사용하여 작업이 끝난 후에 자동으로 리소스가 해제되게 설계했다.
// 네이티브 리소스는 운영 체제나 하드웨어와 직접적으로 상호작용하는 리소스 (GC에 의해 자동으로 관리되지 않기 떄문에 수동으로 해제해줘야 함)
using (Aes aesAlg = Aes.Create()) // AES 알고리즘 생성
{
// 키, IV 설정
aesAlg.Key = key;
aesAlg.IV = iv;
// 암호화 변환기를 생성
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// 평문 텍스트를 암호화
byte[] encrypted = encryptor.TransformFinalBlock(Encoding.UTF8.GetBytes(plainText), 0, plainText.Length);
// 암호화된 바이트 배열을 Base64 문자열로 변환 후 반환
return System.Convert.ToBase64String(encrypted);
}
}
public string DecryptString(string cipherText) // 복호화 함수
{
// Base64 문자열을 바이트 배열로 변환
byte[] buffer = System.Convert.FromBase64String(cipherText);
using (Aes aesAlg = Aes.Create()) // AES 알고리즘 생성
{
// 키, IV 설정
aesAlg.Key = key;
aesAlg.IV = iv;
// 복호화 변환기를 생성
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// 암호화된 바이트 배열을 복호화
byte[] decrypted = decryptor.TransformFinalBlock(buffer, 0, buffer.Length);
// 복호화된 바이트 배열을 UTF-8 문자열로 변환 후 반환
return Encoding.UTF8.GetString(decrypted);
}
}
}
[ 참고 블로그 ]
위 내용은 전 기수분께서 작성해주신 블로그를 참고하였습니다.
https://deff-dev.tistory.com/145
'오늘 공부를 정리해봐요!' 카테고리의 다른 글
[ 11月 6日 ] 오늘 내가 배운 것 _ 37日次 (2) | 2024.11.06 |
---|---|
[ 11月 5日 ] 오늘 내가 배운 것 _ 36日次 (2) | 2024.11.05 |
[ 11月 1日 ] 오늘 내가 배운 것 _ 34日次_ 깃 용량 터질때 (0) | 2024.11.01 |
[ 10月 31日 ] 오늘 내가 배운 것 _ 33日次 (0) | 2024.10.31 |
[ 10月 30日 ] 오늘 내가 배운 것 _ 32日次_ 과제 트러블슈팅 (0) | 2024.10.30 |