EveryDay.DevUp

[Unity] 프레임워크 개발 - 5. 암호화 ( 대칭형 암호화 AES ) 본문

FrameWork

[Unity] 프레임워크 개발 - 5. 암호화 ( 대칭형 암호화 AES )

EveryDay.DevUp 2020. 5. 4. 10:04

게임에서 사용하는 암호화를 실제 코드로 구현하여 프레임워크에 추가

자세한 이론은 하단의 링크를 참고

https://everyday-devup.tistory.com/24

 

[Unity] 게임 암호화

게임의 암호화는 유저의 데이터를 지키고, 게임을 서비스 하면서 안정적인 운영을 할 수 있도록 도와주는 것 ▶ 메모리 핵, 앱 변조, 스피드 핵, 데미지 핵과 같은 많은 핵들이 존재하고 방어하��

everyday-devup.tistory.com

Crypto Class를 생성 Static 으로 암복호화 함수 추가 

▶ 양방향 암호화 중 대칭형 암호화는 AES 를 사용

: 게임에서 사용할 AES의 키 값과 IV 값을 Base64로 저장할 변수를 생성

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CryptoComponent : MonoBehaviour
{
	[HideInInspector]
	public string aesBase64Key = string.Empty;
	[HideInInspector]
	public string aesBase64IV = string.Empty;
}

: 인스펙터 창에서 Key와 IV 값을 설정할 수 있도록 커스텀 에디터를 추가

using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
using System.Security.Cryptography;
using System;
using System.Text;

[CustomEditor( typeof( CryptoComponent ) )]
public class CryptoEditor : Editor
{
	CryptoComponent _cryptoComponent;
	int _aesKeySize;
	string _aesKey;

	int _aesIVSize;
	string _aesIV;

	private void OnEnable()
	{
		_cryptoComponent = (CryptoComponent)target;
	}

	public override void OnInspectorGUI()
	{
		base.OnInspectorGUI();

		if( string.IsNullOrEmpty( _aesKey ))
		{
			if( string.IsNullOrEmpty( _cryptoComponent.aesBase64Key ) == false )
			{
				_aesKey = Crypto.DecodingBase64( _cryptoComponent.aesBase64Key );
			}
			else
			{
				_aesKey = string.Empty;
			}
		}

		_aesKeySize = Encoding.UTF8.GetByteCount( _aesKey ) * 8;
		EditorGUILayout.IntField( "AES Key Size", _aesKeySize );
		_aesKey = EditorGUILayout.TextField( "AES Key", _aesKey );
		EditorGUILayout.TextField( "AES Base64 Key", _cryptoComponent.aesBase64Key );

		if( GUILayout.Button( "Convert" ) )
		{
			bool isValid = false;
			string validKeySizeText = string.Empty;

			int validKeySize = 0;
			for( int i = 0, icount = CryptoAES.aesKeySize.Length; i < icount; i++ )
			{
				validKeySize = CryptoAES.aesKeySize[i];
				validKeySizeText += validKeySize.ToString() + " ";
				if( _aesKeySize.Equals( validKeySize ) )
				{
					isValid = true;
					break;
				}
			}

			if( isValid )
			{
				_cryptoComponent.aesBase64Key = Crypto.EncodingBase64( _aesKey );
				EditorUtility.SetDirty( _cryptoComponent );
			}
			else
			{

				EditorUtility.DisplayDialog( "key size error", string.Format( "key size {0}", validKeySizeText ), "ok" );
			}
		}

		if( string.IsNullOrEmpty( _aesIV ) )
		{
			if( string.IsNullOrEmpty( _cryptoComponent.aesBase64IV ) == false )
			{
				_aesIV = Crypto.DecodingBase64( _cryptoComponent.aesBase64IV );
			}
			else
			{
				_aesIV = string.Empty;
			}
		}

		_aesIVSize = Encoding.UTF8.GetByteCount( _aesIV ) * 8; 
		EditorGUILayout.IntField( "AES IV Size", _aesIVSize );

		_aesIV = EditorGUILayout.TextField( "AES IV", _aesIV );
		EditorGUILayout.TextField( "AES Base64 Key", _cryptoComponent.aesBase64IV );

		if( GUILayout.Button( "Convert" ) )
		{
			if( _aesIVSize == CryptoAES.aesIVSize )
			{
				_cryptoComponent.aesBase64IV = Crypto.EncodingBase64( _aesIV );
				EditorUtility.SetDirty( _cryptoComponent );
			}
			else
			{
				EditorUtility.DisplayDialog( "iv size error", string.Format( "IV Size {0}", CryptoAES.aesIVSize ), "ok" );
			}
		}
	}
}

: AES를 관리할 클래스를 추가

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public class CryptoAES
{
	public static int[] aesKeySize = { 128, 192, 256 };
	public static int aesIVSize = 128;

	ICryptoTransform encrypter;
	ICryptoTransform decrypter;

	public void Create(string base64Key, string base64IV)
	{
		byte[] key = Convert.FromBase64String( base64Key );
		byte[] iv = Convert.FromBase64String( base64IV );

		RijndaelManaged rijndaelManaged = new RijndaelManaged();
		rijndaelManaged.KeySize = key.Length * 8;
		rijndaelManaged.BlockSize = aesIVSize;
		rijndaelManaged.Padding = PaddingMode.PKCS7;
		rijndaelManaged.Mode = CipherMode.CBC;

		rijndaelManaged.Key = key;
		rijndaelManaged.IV = iv;

		encrypter = rijndaelManaged.CreateEncryptor();
		decrypter = rijndaelManaged.CreateDecryptor();
	}

	public string Encrypt(string plainText)
	{
		using( MemoryStream memoryStream = new MemoryStream() )
		{
			using( CryptoStream cryptoStream = new CryptoStream( memoryStream, encrypter, CryptoStreamMode.Write ) )
			{
				byte[] byteData = Encoding.UTF8.GetBytes( plainText );
				cryptoStream.Write( byteData, 0, byteData.Length );
			}

			byte[] byteCrypto = memoryStream.ToArray();
			return Convert.ToBase64String( byteCrypto );
		}
	}

	public string Decrypt(string encryptData)
	{
		using( MemoryStream memoryStream = new MemoryStream() )
		{
			using( CryptoStream cryptoStream = new CryptoStream( memoryStream, decrypter, CryptoStreamMode.Write ) )
			{
				byte[] byteEncrpt = Convert.FromBase64String( encryptData );
				cryptoStream.Write( byteEncrpt, 0, byteEncrpt.Length );
			}

			byte[] byteCrypto = memoryStream.ToArray();
			return Encoding.UTF8.GetString( byteCrypto );
		}
	}
}

: Crypto 클래스에서 AES를 키값으로 구분하여 저장, 키 값을 통해 암복호화 기능이 동작하도록 함

using System.Collections.Generic;
using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;

public class Crypto
{
	static Dictionary<string, CryptoAES> aesManages = new Dictionary<string, CryptoAES>();

	static void CreateAESManage(string base64Key, string base64IV)
	{
		CryptoAES aesManage = new CryptoAES();
		aesManage.Create( base64Key, base64IV );
		aesManages.Add( base64Key, aesManage );
	}

	public static string EncryptAESbyBase64Key(string plainText, string base64Key, string base64IV)
	{
		if( aesManages.ContainsKey( base64Key ) == false )
		{
			CreateAESManage( base64Key, base64IV );
		}

		return aesManages[base64Key].Encrypt( plainText );
	}


	public static string DecryptAESByBase64Key(string encryptData, string base64Key, string base64IV)
	{
		if( aesManages.ContainsKey( base64Key ) == false )
		{
			return string.Empty;
		}

		return aesManages[base64Key].Decrypt( encryptData );
	}
}

: 사용 예시

public CryptoComponent crypto;

	private void Start()
	{
		string encryptText = Crypto.EncryptAESbyBase64Key( "testData", crypto.aesBase64Key, crypto.aesBase64IV );
		Debug.Log( "encryptText : " + encryptText );
		string decryptText = Crypto.DecryptAESByBase64Key( encryptText, crypto.aesBase64Key, crypto.aesBase64IV );
		Debug.Log( "decryptText : " + decryptText );
	}