재우니의 블로그

 

 

 

미션

더보기

개인정보를 전달하기 전에 암호화 해야 합니다. 암호화에는 비대칭 암호화 알고리즘은 2048 bit RSA key - OAEP Padding - SHA256 Digest를 사용 합니다. 가이드와 같이 전달 드린 public key(PEM 형식)를 사용하여 encrypt 한 후 base64로 인코딩 된 text로 API에 전달하시면 됩니다

 

 

 

.NET Framework 4.6.2 환경에서 ASP.NET MVC 5 애플리케이션을 구현하고, 주어진 공개키(publicKey.pem 파일, PEM 형식)를 사용하여 데이터를 RSA 알고리즘으로 암호화하는 과정은 다음과 같습니다. 

 

.NET Framework 4.6.2에서는 RSACryptoServiceProvider 클래스를 사용하여 RSA 암호화를 수행할 수 있지만, 직접 PEM 파일을 읽어들이고 OAEP Padding을 사용하는 것은 직관적이지 않습니다. 따라서, 추가적인 작업이 필요합니다. 하지만, PEM 파일 파싱: .NET Framework 4.6.2는 기본적으로 PEM 형식의 파일을 직접 읽어들이는 기능을 제공하지 않습니다.

 

따라서, BouncyCastle 라이브러리 같은 외부 라이브러리를 사용하여 PEM 파일을 파싱하거나, PEM 파일에서 필요한 공개키 정보를 추출하는 로직을 직접 구현해야 합니다. 데이터 암호화: 추출한 공개키 정보를 사용하여 데이터를 암호화합니다.

 

RSA OAEP Padding과 SHA256을 사용해야 합니다. 하지만, RSACryptoServiceProvider는 .NET Framework 4.6.2에서 OAEP Padding을 SHA256과 함께 사용하는 것을 직접 지원하지 않습니다. 이를 위해 RSACng 클래스를 사용할 수 있지만, 이는 .NET Framework 4.6.2에서 기본적으로 사용할 수 없으므로, 대안적인 방법을 모색해야 합니다. 이러한 제한 사항을 고려하여, 먼저 BouncyCastle을 사용하여 PEM 파일로부터 공개키를 읽어들이는 방법과 데이터를 암호화하는 방법을 단계별로 설명하겠습니다.

 

 

BouncyCastle.Cryptography.2.2.1  로 nuget 을 통해 설치하면 되겠습니다.

 

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;



/// <summary>
/// .NET 4.6.2 기반으로 ASP.NET MVC 5 환경에서 RSA 비대칭 암호화를 사용하여 데이터를 암호화하고 복호화하는 예제입니다.
/// 공개키는 데이터를 암호화할 때 사용되며, 개인키는 암호화된 데이터를 복호화할 때 사용됩니다.
/// 본 예제에서는 BouncyCastle 라이브러리를 사용하여 RSA 암호화와 복호화를 구현하고 있습니다.
///
/// ## STEP 1.PEM 파일 파싱
/// .NET Framework 4.6.2는 기본적으로 PEM 형식의 파일을 직접 읽어들이는 기능을 제공하지 않습니다.
/// 따라서, BouncyCastle 라이브러리 같은 외부 라이브러리를 사용하여 PEM 파일을 파싱하거나,
/// PEM 파일에서 필요한 공개키 정보를 추출하는 로직을 직접 구현해야 합니다.
/// 
/// ## STEP 2.데이터 암호화 (RSA OAEP Padding과 SHA256을 사용)
/// 문제 : RSACryptoServiceProvider는 .NET Framework 4.6.2에서 OAEP Padding을 SHA256과 함께 사용하는 것을 직접 지원하지 않음.
/// 방안 : 외부 오픈소스 BouncyCastle을 사용하여 PEM 파일로부터 공개키를 읽어들이는 방법과 데이터를 암호화하는 방법
/// 
/// </summary>
public class RSAEncryptionHelper
{


    /// <summary>
    /// BouncyCastle 라이브러리를 사용하여 PEM 형식의 공개키 파일을 로드
    /// </summary>
    /// <param name="pem">The pem.</param>
    /// <returns></returns>
    public static RsaKeyParameters LoadPublicKey(string pem)
    {
        using (TextReader reader = new StringReader(pem))
        {
            PemReader pemReader = new PemReader(reader);
            return (RsaKeyParameters)pemReader.ReadObject();
        }
    }

    /// <summary>
    /// PEM 파일에서 개인키를 로드하여 RsaPrivateCrtKeyParameters 타입으로 반환
    /// </summary>
    /// <param name="pem">The pem.</param>
    /// <returns></returns>
    /// <exception cref="System.InvalidCastException">개인키를 로드하는데 실패하였습니다. 올바른 형식의 개인키인지 확인해주세요.</exception>
    public static RsaPrivateCrtKeyParameters LoadPrivateKey(string pem)
    {
        using (TextReader reader = new StringReader(pem))
        {
            PemReader pemReader = new PemReader(reader);
            object readObject = pemReader.ReadObject();
            if (readObject is AsymmetricCipherKeyPair keyPair)
            {
                return (RsaPrivateCrtKeyParameters)keyPair.Private;
            }
            else if (readObject is RsaPrivateCrtKeyParameters keyParameters)
            {
                return keyParameters;
            }
            else
            {
                throw new InvalidCastException("개인키를 로드하는데 실패하였습니다. 올바른 형식의 개인키인지 확인해주세요.");
            }
        }
    }

    /// <summary>
    /// 문자열 데이터를 받아 RSA OAEP SHA-256 알고리즘을 사용하여 암호화하고, 그 결과를 Base64 문자열로 변환하여 반환한다.
    /// </summary>
    /// <param name="data">The data.</param>
    /// <param name="publicKey">The public key.</param>
    /// <returns></returns>
    public static string EncryptData(string data, RsaKeyParameters publicKey)
    {
        byte[] dataToEncryptBytes = Encoding.UTF8.GetBytes(data);
        IAsymmetricBlockCipher cipher = new OaepEncoding(new RsaEngine(), new Sha256Digest());
        cipher.Init(true, publicKey);

        byte[] encryptedBytes = cipher.ProcessBlock(dataToEncryptBytes, 0, dataToEncryptBytes.Length);
        return Convert.ToBase64String(encryptedBytes);
    }

    /// <summary>
    /// 데이터를 RSA OAEP SHA-256 알고리즘을 사용하여 복호화
    /// </summary>
    /// <param name="data">The data.</param>
    /// <param name="privateKey">The private key.</param>
    /// <returns></returns>
    public static string DecryptData(string data, RsaKeyParameters privateKey)
    {
        byte[] dataToDecryptBytes = Convert.FromBase64String(data);
        IAsymmetricBlockCipher cipher = new OaepEncoding(new RsaEngine(), new Sha256Digest());
        cipher.Init(false, privateKey);

        byte[] decryptedBytes = cipher.ProcessBlock(dataToDecryptBytes, 0, dataToDecryptBytes.Length);
        return Encoding.UTF8.GetString(decryptedBytes);
    }
}

 

 

위의 클래스를 통해 호출하여 실행하는 코드입니다.  publickey 와 private 키는 물리적인 경로를 지정해서 사용해야 합니다.

string publicKeyPath = @"D:\UNIV Developer Center\Development\Internal\StepUp\UnivDefault.Web\Html\publicKey.pem";
string privateKeyPath = @"D:\UNIV Developer Center\Development\Internal\StepUp\UnivDefault.Web\Html\privateKey.pem";



try
{
    // 공개키 로드
    string publicKeyPem = System.IO.File.ReadAllText(publicKeyPath);

    RsaKeyParameters publicKey = RSAEncryptionHelper.LoadPublicKey(publicKeyPem);

    // 개인키 로드 (복호화 예시를 위해 필요함)
    string privateKeyPem = System.IO.File.ReadAllText(privateKeyPath);
    RsaPrivateCrtKeyParameters privateKey = RSAEncryptionHelper.LoadPrivateKey(privateKeyPem);

    // 데이터 암호화
    string dataToEncrypt = "안녕하세요. 대학내일입니다. !@#$%^&*()_+ abceEF";
    string encryptedData = RSAEncryptionHelper.EncryptData(dataToEncrypt, publicKey);

    // 데이터 복호화 (실제 사용 시에는 서버 측에서 수행)
    string decryptedData = RSAEncryptionHelper.DecryptData(encryptedData, privateKey);

    ViewBag.Ori = dataToEncrypt;
    ViewBag.Enc = encryptedData;
    ViewBag.Dec = decryptedData;
}
catch (Exception ex)
{
    Console.WriteLine($"An error occurred: {ex.Message}");
}

 

 

 

pem 파일을 만드는데 있어서, 먼저 시스템에 OpenSSL이 설치되어 있지 않다면, OpenSSL 공식 페이지에서 다운로드하여 설치합니다.

 

https://www.openssl.org/source/

 

[ Downloads ] - /source/index.html

Downloads The master sources are maintained in our git repository, which is accessible over the network and cloned on GitHub, at https://github.com/openssl/openssl. Bugs and pull patches (issues and pull requests) should be filed on the GitHub repo. Please

www.openssl.org

 

 

아래 명령어는 2048비트 RSA 키 쌍을 생성하고, 개인키를 privateKey.pem 파일에, 공개키를 publicKey.pem 파일에 저장합니다. (아래 한줄씩 실행하세요.)

 

openssl genpkey -algorithm RSA -out privateKey.pem -pkeyopt rsa_keygen_bits:2048
openssl rsa -pubout -in privateKey.pem -out publicKey.pem