본문 바로가기
C#

C#] System.Security.Cryptography

by Fastlane 2023. 1. 16.
728x90
반응형

출처 : https://code-maze.com/dotnet-cryptography-implementations/

Hash Functions in Cryptography

Hash 함수는 단방향 수학알고리즘이다. Hashing data는 되돌릴 수 없다. input에 대한 결과값이 항상 같다. 

input 사이즈에 상관없이 언제나 고정된 사이트의 output을 만든다. 따라서 충돌이 발생할 수 있다. 

 

Hash Functions 활용

비밀번호를 plain text로 저장하지 않고, hash값을 저장한다. file의 무결성을 확인하기 위해서도 사용한다. 

MD5

Message-digest algorithm 또는 MD5는 널리 사용되는 hashing 알고리즘이다. 

var strStreamOne = new MemoryStream(Encoding.UTF8.GetBytes("This is my password! Dont read me!"));

byte[] hashOne;
using (var hasher = MD5.Create())
{
    hashOne = await hasher.ComputeHashAsync(strStreamOne);
}

var hashAsString = Convert.ToHexString(hashOne);

Console.WriteLine("Hash Value:\n" + hashAsString)

hash는 bytes 배열이지만, Convert.ToHexString()함수를 호출하여 hex string으로 변환하면, 읽을 수 있는 string format으로 변경이 가능하다. 

 

SHA Family

Secure Hashing Algorithm 또는 SHA. 

National Institute of Standards and Technology (NIST)에서 개발한 해쉬 알고리즘이다. 

현재는 SHA-1, SHA-2 다음으로 SHA-3을 사용한다. 

2015년에 SHA-3이 릴리즈되었다. SHA-1, 2가 MD-5 알고리즘 기반인 것에 반해, SHA-3은 Keccak 알고리즘 기반이다. 

SHA-3은 .NET에서 제공하지 않는다. 

var strStreamOne = new MemoryStream(Encoding.UTF8.GetBytes("This is my password! Dont read me!"));
byte[] hashOne;
using (var sha256 = SHA256.Create())
{
    hashOne = await sha256.ComputeHashAsync(strStreamOne);
}
var hashAsString = Convert.ToHexString(hashOne);
Console.WriteLine("Hash Value:\n" + hashAsString);

 

HMAC

secret key가 필요한 hasing function이다. HMAC이 secret key가 필요하기 때문에, hash를 하기위한 권한이 있는 사람을 확인할 수 있다. 

var strStreamOne = new MemoryStream(Encoding.UTF8.GetBytes("This is my password! Dont read me!"));
byte[] hashOne;
byte[] key = Encoding.UTF8.GetBytes("superSecretH4shKey1!");
using (var hmac = new HMACSHA256(key))
{
    hashOne = await hmac.ComputeHashAsync(strStreamOne);
}
var hashAsString = Convert.ToHexString(hashOne);
Console.WriteLine("Hash Value:\n" + hashAsString);

Symmetric Encryption 대칭 키 암호화

하나의 private key로 데이터의 암호화 복호화를 할 수 있는 알고리즘을 말한다. 

AES

가장 유명한 대칭 키 암호화 알고리즘이다. 빠르고 사이즈에 상관없이 데이터를 암호화할 수 있다. 

AES는 128 bit block size와 128, 192, 256 bit key size를 갖는다. key size가 길어, 안전하고 깨기 어렵다. 

var dataStr = "This is corporate research! Dont read me!";
var data = Encoding.UTF8.GetBytes(dataStr);
var key = GenerateAESKey();
var encryptedData = Encrypt(data, key, out var iv);
var encryptedDataAsString = Convert.ToHexString(encryptedData);
Console.WriteLine("Encrypted Value:\n" + encryptedDataAsString);
public static byte[] Encrypt(byte[] data, byte[] key, out byte[] iv)
{
    using (var aes = Aes.Create())
    {
        aes.Mode = CipherMode.CBC; // better security
        aes.Key = key;
        aes.GenerateIV(); // IV = Initialization Vector
        using (var encryptor = aes.CreateEncryptor())
        {
            iv = aes.IV;
            return encryptor.TransformFinalBlock(data, 0, data.Length);
        }
    }
}
public static byte[] Decrypt(byte[] data, byte[] key, byte[] iv)
{
    using (var aes = Aes.Create())
    {
        aes.Key = key;
        aes.IV = iv;
        aes.Mode = CipherMode.CBC; // same as for encryption
        using (var decryptor = aes.CreateDecryptor())
        {
            return decryptor.TransformFinalBlock(data, 0, data.Length);
        }
    }
}
public static byte[] GenerateAESKey()
{
    var rnd = new RNGCryptoServiceProvider();
    var b = new byte[16];
    rnd.GetNonZeroBytes(b);
    return b;
}

잘못된 사이즈의 키를 제공하면 오류가 발생한다. 이 예에서 16-byte key, CBC cipher mode, IV(initialization vector)를 생성하기 위해 GenerateIV()를 사용했다. 

Cryptography Cipher Modes

aes.Mode 값 설정을 통해서 원하는 cipher mode를 사용할 수 있다. 

The Cipher Block Chaining

현재 블록을 암호화할때 이전 블록의 feedback을 사용한다. 

The Electronic Codebook

각 블록을 개별적으로 암호화한다. 동일한 key를 사용할때 평문의 identical 블록은 같은 암호값을 갖는다. 

보안에 취약하여 추천하지 않는다. 

The Cipher Feedback

The Cipher Text Stealing 

어떤 길이의 평문도 암호화하며, 평문의 길이와 동일한 cipher text를 만든다. 

Asymmetric Encryption 공개 키 암호화

공개키로 암호화되고 비밀키로 복호화한다. Asymmetric encryption은 symmetric encryption보다 훨씬 느리다. 대용량 데이터에 대해 asymmetric encryption은 실용적이지 않다.

RSA

공개 키 암호화 방식 중 인기있는 알고리즘이며, 암호화 알고리즘 보안에 대해 오래되어 충분히 긴 키를 사용했다면, RSA를 깰 수 있는 방법은 없다. RSA는 암호화에서 사용된 key 사이즈의 데이터 암호블록만 다룰 수 있다. Data set이 key size보다 커지면 여러개의 블록으로 나누어진다. 

 

key 변환, digital signing에서 RSA를 사용한다. 

 

var dataStr = "This is corporate research! Dont read me!";
var data = Encoding.UTF8.GetBytes(dataStr);
var keyLength = 2048; // size in bits

GenerateKeys(keyLength , out var publicKey, out var privateKey);

var encryptedData = Encrypt(data, publicKey);

var encryptedDataAsString = Convert.ToHexString(encryptedData);

Console.WriteLine("Encrypted Value:\n" + encryptedDataAsString);

public void GenerateKeys(int keyLength, out RSAParameters publicKey, out RSAParameters privateKey)
{
    using (var rsa = RSA.Create())
    {
        rsa.KeySize = keyLength;
        publicKey = rsa.ExportParameters(includePrivateParameters: false);
        privateKey = rsa.ExportParameters(includePrivateParameters: true);
    }
}

public byte[] Encrypt(byte[] data, RSAParameters publicKey)
{
    using (var rsa = RSA.Create())
    {
        rsa.ImportParameters(publicKey);

        var result = rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA256);
        return result;
    }
}

public byte[] Decrypt(byte[] data, RSAParameters privateKey)
{
    using (var rsa = RSA.Create())
    {
        rsa.ImportParameters(privateKey);
        return rsa.Decrypt(data, RSAEncryptionPadding.OaepSHA256);
    }
}

rsa.KeySize와 공개키/암호키를 만들기 위한 ExportParameters()를 설정했다. key size가 너무 작으면 암호화를 하기위한 key를 만들 수 없다. 안전한 key size 표준은 2048bits이다. 

 

DSA

Digital Signing Algorithm. key generation, digital signing에서 DSA를 사용한다. RSA에 비해서 DAS가 key generation, digital signing, 복호에서 빠르다. 반면에, 암호와 digital signature verification에서는 RSA가 더 빠르다. 

var dsa = DSA.Create();
var dataStr = "This is corporate research! Dont read me!";
var data = Encoding.UTF8.GetBytes(dataStr);

var signedData = Sign(dsa, data);

dsa.Dispose();

public byte[] Sign(DSA dsa, byte[] data)
{
    if(dsa is null)
        throw new NullReferenceException(nameof(dsa));

    var result = dsa.SignData(data, HashAlgorithmName.SHA256);

    return result;
}

public bool VerifySignature(DSA dsa, byte[] data, byte[] signedData)
{
    if (dsa is null)
        throw new NullReferenceException(nameof(dsa));

    return dsa.VerifyData(data, signedData, HashAlgorithmName.SHA256);
}

digitally sign data를 하기 위해 DSA를 사용하였다. 데이터는 text file, email도 될 수 있다. SignData()를 호출해서 data를 sign하고 VerifyData()를 호출해서 signed data를 검증할 수 있다. 

 

적합한 암호화 알고리즘 선택

Asymmetric Encryption

데이터 셋이 크지 않다면, private key를 안전하게 공유할 수 있다면 공개 키 암호화 방식이 가장 안전하다. 데이터인증의 목적이 비밀유지보다 진본여부라면 hashing 알고리즘이 나은 선택이다. 

Symmetric Encryption

데이터 셋이 클때 적합하다. 보안보다 고성능 암호가 중요한 경우에 알맞다. 물론 안전하지만 공개키 암호화보다는 덜 안전하다. 

Hash Function

데이터의 보안보다, 데이터 전송의 정확성이 중요할 수 있다. 전송값과 수신값 사이에 차이가 없다는 것을 인증해야 한다. 이런경우에 hashing 알고리즘을 사용할 수 있다. 가장 빠른 암호화 알고리즘이다. 데이터의 숨김보다 유효성이 중요할때 사용한다. 

Hybrid Encryption

Symmetric/Asymmetric Encryption의 장점을 모두 사용할 수 있다. 우선, symmetric 알고리즘으로 데이터를 암호화한다. 그 다음 asymmetric 알고리즘으로 private key를 암호화한다. 

Cryptographic Random Numbers

random 값을 만들기 위해 가장 쉬운 방법은 System.Random을 사용하는 것이다. 하지만 보안에 취약하다. RandomNumverGenerator가 더 안전하다. 

var randomNumGenerator = RandomNumberGenerator.Create();
var data = new byte[length];
randomNumGenerator.GetBytes(data);
    
return data ;

bytes를 int, char, string과 같은 다른 type을 변경할 수 있다. 

 

728x90
반응형

'C#' 카테고리의 다른 글

C#] 특수문자 (주석, $, @)  (0) 2023.03.21
.NET] DTO vs POCO 차이점  (0) 2023.02.09
C#] ConcurrentBag  (0) 2023.01.11
C#] IEnumerable vs Enumerable 차이점  (0) 2023.01.09
구성관리자] 조건부 컴파일 기호, connectionStrings 관리  (0) 2022.12.14

댓글