반응형
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 |