반응형
    
    
    
  C# - 문자열 양방향 암호화 ( RijndaelManaged )
환경 ; visual studio community 2017
참고 : https://docs.microsoft.com/ko-kr/dotnet/api/system.security.cryptography.rijndaelmanaged?view=netframework-4.6.1
** 참고에 나온 예제 함수를 그대로 사용함.
** 문자열을 RijndaelManaged 로 암호화 한후, 복호화 하기 **
** 문자열을 암호화 하면, byte[ ] 형태의 결과 값 나옴
--> db 나 파일에 저장하기 편하게 하기위해, 16진수 string 으로 변환하여 저장함.
--> 이후, 저장된 16진수 문자열을 읽어들여, byte[ ] 로 바꾸고,
--> 이를 다시 문자열로 복호화 함.
** 암호화 하기 위해, 먼저 key 와 IV(initialization vector) 를 구하여, 저장해둔다.
--> 이후, 암호화 , 복호화 시에 똑같은 key 와 iv 를 사용해야함.
            byte[] key = GetKey();  // 실행시마다, 바뀜
            byte[] iv = GetIV();  // 실행시마다, 바뀜
--> 실행시마다, 바뀌므로, key, iv 를 한번만 실행하여, 그 결과를 아래와 같이 하드코딩하여 계속 사용하자.
            key = new byte[] { 66, 178, 206, 246, 134, 160, 101, 78, 20, 159, 118, 25, 49, 225, 145, 114, 177, 174, 206, 238, 186, 158, 153, 51, 89, 182, 243, 214, 187, 200, 156, 210 };
            iv = new byte[] { 151, 15, 177, 176, 64, 117, 139, 150, 239, 53, 33, 111, 54, 77, 219, 76 };
** 암호화 하는 함수 **
            string encStr = GetEncryptedData(strData, key, iv);
** 복호화 하는 함수 **
            string data = GetDecryptedData(encStr, key, iv);  // 복호화
<< 전체 소스 코드 >>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace 암호화
{
    class Program
    {
        public static void Main()
        {
            CryptRijndaelManaged.Test("abdc 암호화 @ 테스트 코드 !!");
            //Console.ReadLine();
        }
    }
    // 문자열 -- 양방향 암호화 
    public class CryptRijndaelManaged
    {
        // ** 참고 ; https://docs.microsoft.com/ko-kr/dotnet/api/system.security.cryptography.rijndaelmanaged?view=netframework-4.6.1
        // sample test 용..
        static public void Test(string strData = "Here is 한글 테스트!")
        {
            byte[] key = GetKey();  // 실행시마다, 바뀜
            byte[] iv = GetIV();  // 실행시마다, 바뀜
            PrintKey(key);  // 출력값을 프로그램 내에 하드코딩 하여 계속 사용하자!!!
            Console.WriteLine("-------------------");
            PrintIV(iv);  // 출력값을 프로그램 내에 하드코딩 하여 계속 사용하자!!!
            Console.WriteLine("============ key, iv 하드코딩후 사용 예 ========================");
            key = new byte[] { 66, 178, 206, 246, 134, 160, 101, 78, 20, 159, 118, 25, 49, 225, 145, 114, 177, 174, 206, 238, 186, 158, 153, 51, 89, 182, 243, 214, 187, 200, 156, 210 };
            iv = new byte[] { 151, 15, 177, 176, 64, 117, 139, 150, 239, 53, 33, 111, 54, 77, 219, 76 };
            Console.WriteLine($"원본 문자열 ; {strData}\n");
            string encStr = GetEncryptedData(strData, key, iv);
            Console.WriteLine($"저장하기 편한 hex string 암호화 data (파일 저장용); \n{encStr}");
            string data = GetDecryptedData(encStr, key, iv);  // 복호화
            Console.WriteLine($"\n복구된 문자열 ; {data}");
            //Debug.WriteLine("-------------------");
            Console.ReadLine();
        }
        // 프로그램 내에 Key 값을 하드코딩 시에 사용!
        static string PrintKey(byte[] key = null)
        {
            string strKey = ToStringFromBytes(key);
            Console.WriteLine($"Key = {{ {strKey} }}");
            return strKey;
        }
        // 프로그램 내에 IV 값을 하드코딩 시에 사용!
        static string PrintIV(byte[] iv = null)
        {
            string strIV = ToStringFromBytes(iv);
            Console.WriteLine($"IV = {{ {strIV} }}");
            return strIV;
        }
        // 반환값 형식 ex) 58, 176, 190, 165, 246, 118, 253, 90, 147, 7, 
        static private string ToStringFromBytes(byte[] data = null)
        {
            if(data == null)
            {
                data = GetKey();
            }
            StringBuilder strb = new StringBuilder();
            for (int i=0; i < data.Length - 1; i++)
            {
                strb.Append($"{data[i]}, ");
            }
            strb.Append(data[data.Length - 1]);  // 마지막 data 에는 ', ' 를 넣지말자.
            return strb.ToString();
        }
        // **** byte[] 을 hex string 으로 변환하여 반환.****
        static private string ToHexStringFromBytes(byte[] data = null)
        {
            // **** 파일 or db 저장용. hex string 만들기 위함. ****
            // 반환값 형식 ex) 8B406FF18EE5AD0CD3AFFFD73F28B380B014D2420A0FC6C5BFCF40911CDB2E21
            if (data == null)
            {
                //data = GetKey();
                return null;
            }
            StringBuilder strb = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                strb.Append($"{data[i]:X2}");  // 2자리 16진수로 변환.
            }
            return strb.ToString();
        }
        static private byte[] HexStringToBytes(string hexData)
        {
            if (hexData == null)
            {
                return null;
            }
            List<byte> tempList = new List<byte>();
            // 2개씩 읽어들여서, 변환함.
            for (int i = 0; i < hexData.Length/2; i++)
            {
                string hexValue = hexData.Substring(i*2, 2);  
                //Console.Write($"{hexValue}, ");
                tempList.Add(Convert.ToByte(hexValue, 16));  // 16진수 문자를, byte 로 변환.
            }
            return tempList.ToArray();
        }
        static public byte[] GetKey()
        {
            using (RijndaelManaged myRijndael = new RijndaelManaged())
            {
                myRijndael.GenerateKey();
                return myRijndael.Key;
            }
        }
        static public byte[] GetIV()
        {
            using (RijndaelManaged myRijndael = new RijndaelManaged())
            {
                myRijndael.GenerateIV();
                return myRijndael.IV;
            }
        }
        // 원본 string --> 암호화된 hex string
        static public string GetEncryptedData(string data, byte[] Key, byte[] IV)
        {
            byte[] encData = EncryptStringToBytes(data, Key, IV); // **** 암호화된 data ****
            //===== encStr 을 파일이나, db 에 저장하여 사욯한다.  ===========
            // --- 저장하기 편하게 하기위해, 암호화된 byte[] 데이터 ==> hex string data로 변환.
            string encStr = ToHexStringFromBytes(encData);  // **** 파일 저장용. hex string ****
            return encStr;
        }
        // 암호화된 hex string --> 복호화된 원본 string
        static public string GetDecryptedData(string encStr, byte[] Key, byte[] IV)
        {
            byte[] encData2 = HexStringToBytes(encStr);  // 저장된 암호화 string data를, byte[] 로 변환함.
            string data = DecryptStringFromBytes(encData2, Key, IV);  // 복호화
            return data;
        }
        static byte[] EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
        {
            // Check arguments.
            if (plainText == null || plainText.Length <= 0)
                throw new ArgumentNullException("plainText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("IV");
            byte[] encrypted;
            // Create an RijndaelManaged object
            // with the specified key and IV.
            using (RijndaelManaged rijAlg = new RijndaelManaged())
            {
                rijAlg.Key = Key;
                rijAlg.IV = IV;
                // Create an encryptor to perform the stream transform.
                ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
                // Create the streams used for encryption.
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {
                            //Write all data to the stream.
                            swEncrypt.Write(plainText);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }
            // Return the encrypted bytes from the memory stream.
            return encrypted;
        }
        static string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
        {
            // Check arguments.
            if (cipherText == null || cipherText.Length <= 0)
                throw new ArgumentNullException("cipherText");
            if (Key == null || Key.Length <= 0)
                throw new ArgumentNullException("Key");
            if (IV == null || IV.Length <= 0)
                throw new ArgumentNullException("IV");
            // Declare the string used to hold
            // the decrypted text.
            string plaintext = null;
            // Create an RijndaelManaged object
            // with the specified key and IV.
            using (RijndaelManaged rijAlg = new RijndaelManaged())
            {
                rijAlg.Key = Key;
                rijAlg.IV = IV;
                // Create a decryptor to perform the stream transform.
                ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
                // Create the streams used for decryption.
                using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {
                            // Read the decrypted bytes from the decrypting stream
                            // and place them in a string.
                            plaintext = srDecrypt.ReadToEnd();
                        }
                    }
                }
            }
            return plaintext;
        }
    }
}
반응형
    
    
    
  'C#' 카테고리의 다른 글
| C# -- Task.Delay 사용법 ; UI 화면 block 관계 (0) | 2021.02.04 | 
|---|---|
| C# -- Enter 키 입력시 삐소리 제거 및 'Tab' 키 입력으로 변환하기 (0) | 2021.01.28 | 
| C# -- HttpClient 기본 사용법 ; http, https (0) | 2021.01.01 | 
| C# -- DataGridView 에 List 바인딩시, attribute 이용한, 컬럼명 변경 or 숨기기 (0) | 2020.10.30 | 
| C# -- popup listbox window 구현하기 (0) | 2020.09.16 | 


