이름 : sha1Hash.cs using System; using System.IO; using System.Text; using System.Security; using System.Security.Cryptography; namespace CryptoFilter { public class sha1Hash { public static void Main() { sha1Hash app = new sha1Hash(); app.DoTest(); } public void DoTest() { SHA1 sha = new SHA1CryptoServiceProvider(); byte[] data = new byte[3]; byte[] result = {}; data[0] = 97; // ASCII Code 97 = "a" data[1] = 97; data[2] = 97; result = sha.ComputeHash(data); Console.WriteLine("Base64 Encoding : " + Convert.ToBase64String(result)); Console.WriteLine("ASCII Encoding : \n" + Encoding.ASCII.GetString(result)); } } }암호화와 관련된 기능을 이용하려면 System.Security와 System.Security.Cryptography 네임스페이스에 있는 클래스를 이용해야한다. 또한, 암호화는 byte 형태로 되어 있는데 이것을 적절한 문자열(string) 형태로 변환하기 위해 System.Text 네임스페이스를 사용했다. 모든 코드를 입력했으면 다음과 같이 컴파일하여 실행한다.
Csc /out:sha1Hash.exe /target:exe sha1Hash.cs여기서는 미리 데이터를 입력하고 그에 대한 해시를 생성하는 방법을 사용했다. 아스키(ASCII) 코드 97은 영소문자 "a"이며, 실제로 해시를 생성하기 위해 사용한 입력 데이터는 "aaa"가 된다.
Base64 인코딩을 사용하면 화면에 나타낼 수 있는 문자만을 사용하기 때문에 안전하게 표시할 수 있지만, 직접 문자열로 변환하여 출력하는 경우에는 화면 제어문자와 같은 특수 문자로 인해서 화면이 깨져보일 수 있기 때문에 그 다음 라인에 결과를 출력하도록 했다.
이름: md5Hash.cs using System; using System.IO; using System.Text; using System.Security; using System.Security.Cryptography; namespace CryptoFilter { public class md5Hash { public static void Main() { md5Hash app = new md5Hash(); app.DoTest(); } public void DoTest() { MD5 md5 = new MD5CryptoServiceProvider(); byte[] data = new byte[3]; byte[] result = {}; data[0] = 97; // ASCII Code 97 = "a" data[1] = 97; data[2] = 97; result = md5.ComputeHash(data); Console.WriteLine("Base64 Encoding : " + Convert.ToBase64String(result)); Console.WriteLine("ASCII Encoding : \n" + Encoding.ASCII.GetString(result)); } } }SHA1이라는 단어 대신에 MD5를 사용한 것 외에는 큰 차이점이 없을 것이다. 입력 데이터는 같은 데이터를 사용했다. 컴파일은 이전과 같다.
Csc /out:md5Hash.exe /target:exe md5Hash.cs실행한 결과는 다음과 같을 것이다.
사용자 인증을 웹 서비스로 구현하는 경우에 사용자 ID와 비밀번호를 전송하게 되며, 이 모든 데이터는 일반 텍스트로 전달된다. 즉, 누구나 데이터 패킷을 가로챌 수 있다면 사용자 비밀번호를 쉽게 알아낼 수 있을 것이다.
using System; using System.IO; using System.Text; using System.Security; using System.Security.Cryptography;여기서 이용하는데 필요한 각종 네임스페이를 선언하는 부분이다.
namespace CryptoFilter { public class Hash {네임 스페이스와 클래스를 만드는 부분인데, 여기서는 CryptoFilter라는 네임스페이스와 Hash라는 클래스를 작성한다. 코드내에서 이것을 이용하고자 한다면 다음과 같이 사용할 수 있도록 하기 위한 것이다.
CryptoFilter.Hash hash = new CryptoFilter.Hash();앞에 CryptoFilter를 생략하고 싶다면 코드의 시작에 using CryptoFilter; 를 추가하도록 한다.(하지만, 실제로는 이렇게 추가하지 않으면 원하는 클래스를 찾을 수 없다는 에러가 발생한다)
public enum HashType { MD5, SHA1 } private string[] InputData = {}; private string plain = String.Empty; private byte[] hashed; private byte[] result = new byte[100]; private bool bSHA1 = false; private bool bMD5 = false;HashType을 선언하고, MD5, SHA1 알고리즘중에 어떤 것을 사용할지를 지정하도록 한다. 이 값에 따라서 bSHA1 또는 bMD5와 같은 불리언(boolean) 타입을 true로 설정하도록 할 것이다. 할당되지 않는 값들에 대해서는 적절한 초기값을 넣어두도록 한다.
private string plain = String.Empty;문자열 변수에 대해서 값을 할당하지 않는다면 String.Empty과 같은 값을 넣도록 한다.
private string[] InputData = {};배열에 초기값을 할당하지 않는다는 것을 명시하기 위해 다음과 같이 설정하였다.
public Hash(HashType hashType, params string[] sInputData) { if ( hashType == HashType.MD5 ) { bMD5 = true; } else if( hashType == HashType.SHA1 ) { bSHA1 = true; } InputData = sInputData; } // end of Hash클래스 이름이 Hash이므로, 여기서 정의한 것은 생성자 Hash를 지정한 부분이다. 생성자 Hash에서는 HashType에 따라서 불리언 값(bMD5, bSHA1)을 true로 설정하도록 한다. 나머지 변수들은 모두 초기값이 false이므로 단 하나의 변수만 true로 설정된다.
public string Encrypt(bool isBase64) { if(bSHA1) { SHA1 sha1 = new SHA1CryptoServiceProvider(); for(int loopctr = 0; loopctr < InputData.Length; loopctr++) plain += InputData[loopctr]; byte[] bSha1Hash = Encoding.ASCII.GetBytes(plain); result = sha1.ComputeHash(bSha1Hash); hashed = result; } else if(bMD5) { MD5 md5 = new MD5CryptoServiceProvider(); for (int loopctr = 0; loopctr < InputData.Length; loopctr++) plain += InputData[loopctr]; byte[] bMD5Hash = Encoding.ASCII.GetBytes(plain); result = md5.ComputeHash(bMD5Hash); hashed = result; }각각 설정된 불리언 값(bMD5, bSHA1)에 따라서 입력데이터에 대한 해시를 생성한다. 해시는 바이트 단위로 이루어지기 때문에 입력 받은 문자열에 대해서 루프를 돌면서 한 문자(즉, 한 바이트)씩 해시를 생성하고 이것을 바이트 배열 result에 저장한다. (일반적으로 암호화를 하게되면 그 결과는 원본보다 크기가 커진다)
if(isBase64) { return Convert.ToBase64String(hashed); } else { return Encoding.ASCII.GetString(hashed); } } } }이 부분은 전달된 값에 따라서 결과를 Base64 인코딩으로 변환할 것인지, ASCII 형식으로 저장할 것인지를 지정하는 것이다. ASCII 인코딩을 하게되면 특수문자등이 들어가기 때문에 처리하기가 어려워진다. 특히, 웹 서비스의 내용을 암호화하는 경우, XML 컨텐트를 암호화하는 경우, 데이터베이스에 암호화한 내용을 저장하는 경우라면 Base64 인코딩을 사용하기를 권한다.(Base64 인코딩이라는 것은 영문 대소문자와 몇몇 기호들을 합쳐서 64개의 문자로 인코딩한다는 의미다)
이름: CryptoFilter.cs using System; using System.IO; using System.Text; using System.Security; using System.Security.Cryptography; namespace CryptoFilter { public class Hash { public enum HashType { MD5, SHA1 } // end of enum HashType private string[] InputData = {}; private string plain = String.Empty; private byte[] hashed; private byte[] result = new byte[100]; private bool bSHA1 = false; private bool bMD5 = false; public Hash(HashType hashType, params string[] sInputData) { if ( hashType == HashType.MD5 ) { bMD5 = true; } else if( hashType == HashType.SHA1 ) { bSHA1 = true; } InputData = sInputData; } // end of Hash Constructor public string Encrypt(bool isBase64) { // SHA1 Hash if(bSHA1) { SHA1 sha1 = new SHA1CryptoServiceProvider(); for(int loopctr = 0; loopctr < InputData.Length; loopctr++) { plain += InputData[loopctr]; } byte[] bSha1Hash = Encoding.ASCII.GetBytes(plain); result = sha1.ComputeHash(bSha1Hash); hashed = result; } // MD5 Hash else if(bMD5) { MD5 md5 = new MD5CryptoServiceProvider(); for (int loopctr = 0; loopctr < InputData.Length; loopctr++) { plain += InputData[loopctr]; } byte[] bMD5Hash = Encoding.ASCII.GetBytes(plain); result = md5.ComputeHash(bMD5Hash); hashed = result; } // end of if if(isBase64) { return Convert.ToBase64String(hashed); } else { return Encoding.ASCII.GetString(hashed); } // end of if } // end of function Encrypt } // end of class Hash } // end of namespace CryptoFilter코드를 모두 입력했다면 다음과 같은 과정을 거친다.
Csc /out:CryptoFilter.dll /target:library CryptoFilter.cs컴파일이 끝나면 이제 CryptoFilter.DLL 어셈블리가 생성되었을 것이다. 이제 이 어셈블리를 이용하여 해시를 생성하는 프로그램을 작성해보자.
이름: CryptApp.cs using System; using CryptoFilter; public class CryptApp { public static void Main() { string result = String.Empty; Hash hash = new Hash(hash.HashType.MD5, "password"); result = hash.Encrypt(true); Console.WriteLine(result); } }입력을 모두 했으면 다음과 같이 컴파일한다.
Csc /out:CryptApp.exe /target:exe CryptApp.cs /reference:CryptoFilter.dll성공적으로 컴파일이 끝나면 CryptApp.exe가 생성된다. 실행한 결과는 다음과 같다.
입력을 모두 했으면 볼 수 있는 것처럼, MD5 알고리즘(hash.HashType.MD5)을 사용하고, 해시를 생성할 입력데이터는 "password"로 하였다. Hash.Encrypt(true)로 하였으므로 결과는 Base64 인코딩될 것이다.
이전 글 : C# 메시지 처리
다음 글 : 유닉스에서 find 기능 이용하기
최신 콘텐츠