c#/기타

[c# / 암복호화] DES와 AES

루다대디 2024. 2. 14. 15:23

DES

Data Encryption Standard

 

미국 국립표준기술연구소(NIST)에서 국가 표준으로 정한 암호.

(1977년에 표준으로 채택)

DES는 대칭키 암호이며, 56비트의 키를 사용.

 

미국 국립표준기술연구소(NIST)에서는

DES에 대해 5년마다 재평가를 실시하였고,

1993년에 실시된 재평가에서 DES는 안정성에 문제가 있다고 판단함

(1998년까지만 표준으로 사용)


AES

Advanced Encryption Standard

 

DES의 안정성 문제로

AES가  2001년에 NIST에 의하여

차세대의 블록 암호화 알고리즘의 표준으로 발표됨

 

AES의 암호기술을 사용한 암호문을 해독하려면
양자 컴퓨터로도 30년이상이 걸린다고 AES의 관계자가 주장한 바 있음.

(DES는 1999년에 22시간 15분 안에 해독하는 하드웨어가 만들어짐)

 

AESDES와 마찬가지로 대칭키 암호이며,

56비트의 키를 사용하는 DES와 달리

128, 192, 256비트의 다양한 길이의 키를 사용

키값이 길면 길수록 보안 공격에 대해 더 유리하게 방어할 수 있다고 함.

아래코드는 AES256-CBC 코드.

 

더보기
더보기
   public class AES
   {
       private static string _key = "";
	   private static string _iv = "";
       
       /// <summary>
       /// 암호화
       /// </summary>
       /// <param name="str"></param>
       /// <returns></returns>
       public string Encrypt(string str)
       {
           return Encrypt(str, _key, _iv);
       }
       private string Encrypt(string inputText, string key, string iv)
       {
           try
           {
               RijndaelManaged aes = new RijndaelManaged(); //AES 알고리즘
               aes.KeySize = 256;   // 키 크기는 128, 192, 256중에 256
               aes.BlockSize = 128; // 블록 크기는 128고정
               aes.Mode = CipherMode.CBC;
               aes.Padding = PaddingMode.PKCS7;
               aes.Key = CreateKey(key).GetBytes(32); //AES-256을 사용하므로 키값의길이는 32여야 함
               aes.IV = CreateIv(iv).GetBytes(16);    //초기화 벡터는 언제나 길이가 16이어야 함

               // 키값과 초기화 벡터를 기반으로 암호화 작업을 하는 클래스 변수 생성
               var encrypt = aes.CreateEncryptor(aes.Key, aes.IV);

               byte[] xBuff = null;
               using (var ms = new MemoryStream())
               {
                   // encrypt 변수에서 암호화된 데이터를 결과에 쓰는 스트림
                   using (var cs = new CryptoStream(ms, encrypt, CryptoStreamMode.Write))
                   {
                       byte[] xXml = Encoding.UTF8.GetBytes(inputText);
                       cs.Write(xXml, 0, xXml.Length);
                   }

                   xBuff = ms.ToArray();
               }

               String Output = Convert.ToBase64String(xBuff);
               return Output;
           }
           catch (Exception ex)
           {
               return "";
           }
       }

       /// <summary>
       /// 복호화
       /// </summary>
       /// <param name="str"></param>
       /// <returns></returns>
       public string Decrypt(string str)
       {
           return Decrypt(str, _key, _iv);
       }
       private string Decrypt(string inputText, string key, string iv)
       {
           try
           {
               RijndaelManaged aes = new RijndaelManaged();
               aes.KeySize = 256;
               aes.BlockSize = 128;
               aes.Mode = CipherMode.CBC;
               aes.Padding = PaddingMode.PKCS7;
               aes.Key = CreateKey(key).GetBytes(32);
               aes.IV = CreateIv(iv).GetBytes(16);

               var decrypt = aes.CreateDecryptor();
               byte[] xBuff = null;
               using (var ms = new MemoryStream())
               {
                   using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write))
                   {
                       byte[] xXml = Convert.FromBase64String(inputText);
                       cs.Write(xXml, 0, xXml.Length);
                   }

                   xBuff = ms.ToArray();
               }

               string Output = Encoding.UTF8.GetString(xBuff);
               return Output;
           }
           catch (Exception ex)
           {
               return "";
           }
       }

       private static Rfc2898DeriveBytes CreateKey(string key)
       {
       	   //키값 생성
           byte[] keyBytes = Encoding.UTF8.GetBytes(key);
           //솔트값(원본 키값을 알기 어렵게 하는 값)
           byte[] saltBytes = SHA512.Create().ComputeHash(keyBytes);

		   //키값에 솔트값을 사용해 새로운 키 생성, 마지막에 들어가는 수는 해시 생성의 반복 횟수이다.
           Rfc2898DeriveBytes result = new Rfc2898DeriveBytes(keyBytes, saltBytes, 100000);    

		   //키값 반환
           return result; 
       }

       private static Rfc2898DeriveBytes CreateIv(string iv)
       {
           //벡터 생성
           byte[] vectorBytes = Encoding.UTF8.GetBytes(iv);
           //솔트값(원본 벡터를 알기 어렵게 하는 값)
           byte[] saltBytes = SHA512.Create().ComputeHash(vectorBytes);

		   //벡터에 솔트값을 사용해 새로운 키 생성, 마지막에 들어가는 수는 해시 생성의 반복 횟수이다.
           Rfc2898DeriveBytes result = new Rfc2898DeriveBytes(vectorBytes, saltBytes, 100000);
			
           //벡터 반환
           return result;
       }
   }