첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
728x90
반응형
728x170

■ AesCryptoServiceProvider 클래스를 사용해 암호화/복호화하는 방법을 보여준다.

TestProject.zip
0.01MB

▶ SecurityHelper.cs

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

namespace TestProject
{
    /// <summary>
    /// 보안 헬퍼
    /// </summary>
    public static class SecurityHelper
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// RNG 암호 서비스 공급자
        /// </summary>
        private static RNGCryptoServiceProvider _provider = new RNGCryptoServiceProvider();

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Public

        #region 문자열로 암호화하기 - EncryptToString(source, password, salt)

        /// <summary>
        /// 문자열로 암호화하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="password">패스워드</param>
        /// <param name="salt">솔트</param>
        /// <returns>암호화 문자열</returns>
        public static string EncryptToString(string source, string password, string salt)
        {
            return GetHexadecimalString(Encrypt(source, password, salt));
        }

        #endregion
        #region 문자열에서 복호화하기 - DecryptFromString(source, password, salt)

        /// <summary>
        /// 문자열에서 복호화하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="password">패스워드</param>
        /// <param name="salt">솔트</param>
        /// <returns>복호화 문자열</returns>
        public static string DecryptFromString(string source, string password, string salt)
        {
            return Decrypt(GetByteArrayFromHexadecimalString(source), password, salt);
        }

        #endregion
        #region 임의 정수 값 구하기 - GetRandomIntegerValue(minimumValue, maximumValue)

        /// <summary>
        /// 임의 정수 값 구하기
        /// </summary>
        /// <param name="minimumValue">최소 값</param>
        /// <param name="maximumValue">최대 값</param>
        /// <returns>임의 정수 값</returns>
        public static int GetRandomIntegerValue(int minimumValue, int maximumValue)
        {
            uint scale = uint.MaxValue;

            while(scale == uint.MaxValue)
            {
                byte[] byteArray = new byte[4];

                _provider.GetBytes(byteArray);

                scale = BitConverter.ToUInt32(byteArray, 0);
            }

            return (int)(minimumValue + (maximumValue - minimumValue) * (scale / (double)uint.MaxValue));
        }

        #endregion
        #region 임의 솔트 구하기 - GetRandomSalt()

        /// <summary>
        /// 임의 솔트 구하기
        /// </summary>
        /// <returns>임의 솔트</returns>
        public static string GetRandomSalt()
        {
            int byteArrayLength = GetRandomIntegerValue(10, 20);

            byte[] saltByteArray = new byte[byteArrayLength];

            _provider.GetBytes(saltByteArray);

            return GetHexadecimalString(saltByteArray);
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Private

        #region 16진수 문자열에서 바이트 배열 구하기 - GetByteArrayFromHexadecimalString(source)

        /// <summary>
        /// 16진수 문자열에서 바이트 배열 구하기
        /// </summary>
        /// <param name="source">소스 문자여</param>
        /// <returns>바이트 배열</returns>
        private static byte[] GetByteArrayFromHexadecimalString(string source)
        {
            source = source.Replace(" ", string.Empty);

            int    byteCount       = source.Length / 2;
            byte[] targetByteArray = new byte[byteCount];

            for(int i = 0; i < byteCount; i++)
            {
                targetByteArray[i] = Convert.ToByte(source.Substring(2 * i, 2), 16);
            }

            return targetByteArray;
        }

        #endregion
        #region 16진수 문자열 구하기 - GetHexadecimalString(sourceByteArray)

        /// <summary>
        /// 16진수 문자열 구하기
        /// </summary>
        /// <param name="sourceByteArray">소스 바이트 배열</param>
        /// <returns>16진수 문자열</returns>
        private static string GetHexadecimalString(byte[] sourceByteArray)
        {
            string target = string.Empty;

            foreach(byte sourceByte in sourceByteArray)
            {
                target += " " + sourceByte.ToString("X2");
            }

            if(target.Length > 0)
            {
                target = target.Substring(1);
            }

            return target;
        }

        #endregion
        #region 키/초기 값 만들기 - MakeKeyAndInitialValue(password, saltByteArray, keySizeBitCount, blockSizeBitCount, keyByteArray, initialValueByteArray)

        /// <summary>
        /// 키/초기 값 만들기
        /// </summary>
        /// <param name="password">패스워드</param>
        /// <param name="saltByteArray">솔트 바이트 배열</param>
        /// <param name="keySizeBitCount">키 크기 비트 카운트</param>
        /// <param name="blockSizeBitCount">블럭 크기 비트 카운트</param>
        /// <param name="keyByteArray">키 바이트 배열</param>
        /// <param name="initialValueByteArray">초기 값 바이트 배열</param>
        private static void MakeKeyAndInitialValue
        (
            string     password,
            byte[]     saltByteArray,
            int        keySizeBitCount,
            int        blockSizeBitCount,
            ref byte[] keyByteArray,
            ref byte[] initialValueByteArray
        )
        {
            Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, saltByteArray, 513);

            keyByteArray          = rfc2898DeriveBytes.GetBytes(keySizeBitCount   / 8);
            initialValueByteArray = rfc2898DeriveBytes.GetBytes(blockSizeBitCount / 8);
        }

        #endregion
        #region 암호화/복호화하기 - EncryptOrDecrypt(password, sourceByteArray, salt, encrypt)

        /// <summary>
        /// 암호화/복호화하기
        /// </summary>
        /// <param name="password">패스워드</param>
        /// <param name="sourceByteArray">소스 바이트 배열</param>
        /// <param name="salt">솔트</param>
        /// <param name="encrypt">암호화 여부</param>
        /// <returns>암호화/복호화 바이트 배열</returns>
        private static byte[] EncryptOrDecrypt(string password, byte[] sourceByteArray, string salt, bool encrypt)
        {
            AesCryptoServiceProvider provider = new AesCryptoServiceProvider();

            int keySizeBitCount = 0;

            for(int i = 1024; i >= 1; i--)
            {
                if(provider.ValidKeySize(i))
                {
                    keySizeBitCount = i;

                    break;
                }
            }

            int    blockSizeBitCount     = provider.BlockSize;
            byte[] saltByteArray         = GetByteArrayFromHexadecimalString(salt);
            byte[] keyByteArray          = null;
            byte[] initialValueByteArray = null;

            MakeKeyAndInitialValue(password, saltByteArray, keySizeBitCount, blockSizeBitCount, ref keyByteArray, ref initialValueByteArray);

            ICryptoTransform cryptoTransform;

            if(encrypt)
            {
                cryptoTransform = provider.CreateEncryptor(keyByteArray, initialValueByteArray);
            }
            else
            {
                cryptoTransform = provider.CreateDecryptor(keyByteArray, initialValueByteArray);
            }

            MemoryStream targetStream = new MemoryStream();

            CryptoStream cryptoStream = new CryptoStream(targetStream, cryptoTransform, CryptoStreamMode.Write);

            cryptoStream.Write(sourceByteArray, 0, sourceByteArray.Length);

            try
            {
                cryptoStream.FlushFinalBlock();
            }
            catch(CryptographicException)
            {
            }
            catch
            {
                throw;
            }

            byte[] targetByteArray = targetStream.ToArray();

            try
            {
                cryptoStream.Close();
            }
            catch(CryptographicException)
            {
            }
            catch
            {
                throw;
            }

            targetStream.Close();

            return targetByteArray;
        }

        #endregion
        #region 암호화하기 - Encrypt(source, password, salt)

        /// <summary>
        /// 암호화하기
        /// </summary>
        /// <param name="source">소스 문자열</param>
        /// <param name="password">패스워드</param>
        /// <param name="salt">솔트</param>
        /// <returns>암호화 바이트 배열</returns>
        private static byte[] Encrypt(string source, string password, string salt)
        {
            UTF8Encoding encoding = new UTF8Encoding();

            byte[] sourceByteArray = encoding.GetBytes(source);

            return EncryptOrDecrypt(password, sourceByteArray, salt, true);
        }

        #endregion
        #region 복호화하기 - Decrypt(sourceByteArray, password, salt)

        /// <summary>
        /// 복호화하기
        /// </summary>
        /// <param name="sourceByteArray">소스 바이트 배열</param>
        /// <param name="password">패스워드</param>
        /// <param name="salt">솔트</param>
        /// <returns>복호화 문자열</returns>
        private static string Decrypt(byte[] sourceByteArray, string password, string salt)
        {
            byte[] targetByteArray = EncryptOrDecrypt(password, sourceByteArray, salt, false);

            UTF8Encoding encoding = new UTF8Encoding();

            return new string(encoding.GetChars(targetByteArray));
        }

        #endregion
    }
}

 

▶ Program.cs

using System;

namespace TestProject
{
    /// <summary>
    /// 프로그램
    /// </summary>
    class Program
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Static
        //////////////////////////////////////////////////////////////////////////////// Private

        #region 프로그램 시작하기 - Main()

        /// <summary>
        /// 프로그램 시작하기
        /// </summary>
        private static void Main()
        {
            string plainText     = "무궁화 꽃이 피었습니다.";
            string password      = "test";
            string salt          = SecurityHelper.GetRandomSalt();
            string textEncrypted = SecurityHelper.EncryptToString(plainText, password, salt);
            string textDecrypted = SecurityHelper.DecryptFromString(textEncrypted, password, salt);

            Console.WriteLine($"평문     : {plainText}");
            Console.WriteLine($"패스워드 : {password}");
            Console.WriteLine($"솔트     : {salt}");
            Console.WriteLine($"암호문   : {textEncrypted}");
            Console.WriteLine($"복호문   : {textDecrypted}");
        }

        #endregion
    }
}
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요