Microsoft MVP성태의 닷넷 이야기
vb.net 3.5버전 RSA복호화에 대해 여쭤봅니다. [링크 복사], [링크+제목 복사],
조회: 165
글쓴 사람
WMCH (oca123454 at gmail.com)
홈페이지
첨부 파일
 

using Microsoft.AspNetCore.Mvc;
using RsaApi.Models;
using RsaApi.Services;

namespace RsaApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class RsaController : ControllerBase
    {
        private readonly RsaService _rsaService;
        private readonly ILogger<RsaService> _logger;

        public RsaController(RsaService rsaService, ILogger<RsaService> logger)
        {
            this._rsaService = rsaService;
            this._logger = logger;
        }

        [HttpPost("generate")]
        public ActionResult<RsaGenerateKeyRequestDto> GenerateKey()
        {
            try {
                var result = _rsaService.generateKey();
                return Ok( new {
                        publicKey = result.getPublicKey(),
                        privateKey = result.getPrivateKey()
                     });
            } catch (Exception ex)
            {
                return StatusCode(500, $"Internal server error: {ex.Message}");
            }
            
        }

        [HttpPost("decryptMessage")]
        public ActionResult<EmrUserDto> getDecryptMessage([FromBody] DecryptMessageRequestDto request)
        {
            try {
                _logger.LogInformation(request.ciphertextBase64);
                return Ok(_rsaService.Decrypt(request.ciphertextBase64));
            } catch (Exception ex)
            {
                return StatusCode(500, $"Internal server error: {ex.Message}");
            }
            
        }
    }
}
using System.Security.Cryptography;
using System.Text.Json;
using RsaApi.Models;

namespace RsaApi.Services
{
    public class RsaService : IRsaService
    {
        private readonly ILogger<RsaService> _logger;

        // 생성자에서 ILogger를 주입받습니다.
        public RsaService(ILogger<RsaService> logger)
        {
            _logger = logger;
        }
        public RsaGenerateKeyRequestDto generateKey()
        {
            _logger.LogInformation("Key generation started.");
            // RSA 객체를 플랫폼에 맞게 생성
            using (var rsa = RSA.Create())
            {
                // 키 길이를 2048 비트로 설정
                rsa.KeySize = 2048;

                // 공개키와 개인키 추출
                var publicKey = rsa.ExportRSAPublicKey();
                var privateKey = rsa.ExportRSAPrivateKey();

                // Base64로 인코딩
                var publicKeyBase64 = Convert.ToBase64String(publicKey);
                var privateKeyBase64 = Convert.ToBase64String(privateKey);

                _logger.LogInformation(publicKeyBase64);
                _logger.LogInformation(privateKeyBase64);
                // DTO 리턴
                return new RsaGenerateKeyRequestDto(publicKeyBase64, privateKeyBase64);
            }
        }

        public string Encrypt(string plaintext, string publicKeyBase64)
        {
            using (var rsa = RSA.Create())
            {
                // 공개키 로드
                rsa.ImportRSAPublicKey(Convert.FromBase64String(publicKeyBase64), out _);

                // OAEP 패딩 방식 적용
                var encryptedBytes = rsa.Encrypt(System.Text.Encoding.UTF8.GetBytes(plaintext), RSAEncryptionPadding.OaepSHA1);

                return Convert.ToBase64String(encryptedBytes);
            }
        }

        public EmrUserDto Decrypt(string ciphertextBase64)
        {
            using (var rsa = RSA.Create())
            {
                _logger.LogInformation(ciphertextBase64);
                // 루트 경로에 있는 개인키 파일 경로 지정
                string privateKeyFilePath = Path.Combine(Directory.GetCurrentDirectory(), "private_key.pem");

                // 개인키를 파일에서 읽어서 Base64로 변환
                string privateKeyBase64 = ReadPrivateKeyFromFile(privateKeyFilePath);

                // Base64를 디코딩하여 RSA 개인키 로드
                rsa.ImportRSAPrivateKey(Convert.FromBase64String(privateKeyBase64), out _);

                // OAEP 패딩 방식 적용
                byte[] decryptedBytes = rsa.Decrypt(Convert.FromBase64String(ciphertextBase64), RSAEncryptionPadding.OaepSHA1);

                string result = System.Text.Encoding.UTF8.GetString(decryptedBytes);
                _logger.LogInformation(result);
                var options = new JsonSerializerOptions
                {
                    PropertyNameCaseInsensitive = true // 대소문자 구분을 하지 않도록 설정
                };

                try
                {
                    // JSON 문자열을 EmrUserDto 객체로 역직렬화
                    return JsonSerializer.Deserialize<EmrUserDto>(result) ?? new EmrUserDto("", "", "", "", "");
                }
                catch (JsonException)
                {
                    // 역직렬화 실패 시 기본값을 반환
                    Console.WriteLine("Error during deserialization. Returning default EmrUserDto.");
                    return new EmrUserDto("", "", "", "", "");
                }
            }
        }

        private string ReadPrivateKeyFromFile(string filePath)
        {
            // 개인키 파일을 읽음
            string privateKey = File.ReadAllText(filePath);
            
            // PEM 형식에서 불필요한 부분 제거 (예: "-----BEGIN PRIVATE KEY-----"와 "-----END PRIVATE KEY-----" 부분)
            privateKey = privateKey.Replace("-----BEGIN RSA PRIVATE KEY-----", "")
                                .Replace("-----END RSA PRIVATE KEY-----", "")
                                .Replace("\n", "")
                                .Replace("\r", "");
            return privateKey;
        }
    }
}
using System.Text.Json.Serialization;

namespace RsaApi.Models
{
    public class RsaGenerateKeyRequestDto
    {
        private string publicKey;
        private string privateKey;

        public string getPublicKey(){
            return this.publicKey;
        }

        public string getPrivateKey(){
            return this.privateKey;
        }

        public RsaGenerateKeyRequestDto(string publicKey, string privateKey)
        {
            this.publicKey = publicKey;
            this.privateKey = privateKey;
        }
    }

    public class RsaDecryptMessageDto
    {
        public string decryptMessage;

        public string getDecryptMessage(){
            return this.decryptMessage;
        }

        public RsaDecryptMessageDto(string decryptMessage)
        {
            this.decryptMessage = decryptMessage;
        }
    }

    public class DecryptMessageRequestDto
    {
        public string ciphertextBase64 { get; set; }
    }
    public class EmrUserDto
    {
        [JsonPropertyName("name")]
        public string Name { get; set; }

        [JsonPropertyName("birthday")]
        public string Birthday { get; set; }

        [JsonPropertyName("gender")]
        public string Gender { get; set; }

        [JsonPropertyName("phone")]
        public string Phone { get; set; }

        [JsonPropertyName("emrUserIdx")]
        public string EmrUserIdx { get; set; }

        public EmrUserDto(string name, string birthday, string gender, string phone, string emrUserIdx)
        {
            this.Name = name;
            this.Birthday = birthday;
            this.Gender = gender;
            this.Phone = phone;
            this.EmrUserIdx = emrUserIdx;
        }
    }
}

C#에서는 이런식으로 RSA암복호화를 진행하라고 예시를 줬는데
저는 VB.net 3.5에서 RSA복호화를 진행하려고 합니다.
private_key.pem은 제가 가지고 있고 서버에서 암호화된 문자열을 넘겨주면 RSA복호화를 통해 JSon형태의 데이터를 받아오도록 하길 원합니다.








[최초 등록일: ]
[최종 수정일: 7/17/2025]


비밀번호

댓글 작성자
 



2025-07-17 03시38분
VB.net 3.5라는 것은 아마도 .NET Framework 3.5 환경에서 VB.NET으로 코딩하시려는 의도같은데... 딱히 C#과 다른 점이 없습니다. 위의 예제에서 Decrypt 메서드에서 사용한 RSA 관련 타입들이 .NET Framework 3.5에서도 지원하기 때문에 그대로 VB.NET으로 마이그레이션하면 됩니다. 혹시... 뭔가 막히는 다른 부분이 있는 건가요?

그건 그렇고, 제시하신 예제 코드가 동작은 잘 하나요? 클라이언트 측에서 GenerateKey로 가져간 키는 RSA.Create로 새롭게 생성한 Key인 반면, getDecryptMessage 메서드에서는 클라이언트에서 "그 새롭게 가져간 키"가 아닌, 별도로 "private_key.pem" 파일에 저장한 Key를 사용해 복호화를 한다면 Key가 맞지 않아 문제가 됩니다.
정성태

... 76  77  78  79  80  81  82  [83]  84  85  86  87  88  89  90  ...
NoWriterDateCnt.TitleFile(s)
407김용국6/21/200612915                답변글 [답변]: 다시한번 문의드립니다!
398김성호6/17/200613500IE프로그래밍 관련하여 질문이
400정성태6/19/200613184    답변글 [답변]: IE프로그래밍 관련하여 질문이 [5]
396guest6/13/200613040CallByName 을 어떻게 처리해야 할지 ....조언 부탁합니다.
397정성태6/15/200612587    답변글 [답변]: CallByName 을 어떻게 처리해야 할지 ....조언 부탁합니다.
399guest6/19/200612180        답변글 [답변]: [답변]: CallByName 을 어떻게 처리해야 할지 ....조언 부탁합니다.
392이상식6/9/200613012스마트클라이언트 실행환경 관련 질문입니다.
394정성태6/12/200612891    답변글 [답변]: 스마트클라이언트 실행 환경 관련 질문입니다.
395이상식6/12/200613192        답변글 [답변]: [답변]: 스마트클라이언트 실행환경 관련 질문입니다.
391심현철6/9/200613149Win32 platform과 .NET platform간의 성능이 어느정도 차이가 날까요?
393정성태6/12/200612878    답변글 [답변]: Win32 platform과 .NET platform간의 성능이 어느정도 차이가 날까요?
390이현행6/6/200613117정말 답답해서 그렇습니다. [1]
389임경훈6/2/200623019sql과 oracle 사용시 파라메타 차이점
387창민 6/1/200614919안녕하세요.문제가 걸렸는데 해결기미가 안보여서 답답해서.. 혹시 아시면 문제 채질이라도...파일 다운로드1
388정성태6/1/200614470    답변글 [답변]: 안녕하세요.문제가 걸렸는데 해결기미가 안보여서 답답해서.. 혹시 아시면 문제 채질이라도...
385오윤섭5/31/200612151SmartClient 동적호출
386정성태6/1/200612561    답변글 [답변]: SmartClient 동적 호출
380윤용한5/29/200612646ATL Event에서 스크립트가 값을 다시 돌려주는 방법은?파일 다운로드1
381윤용한5/29/200612363    답변글 [답변]: ATL Event에서 스크립트가 값을 다시 돌려주는 방법은?
382윤용한5/29/200612940        답변글 [답변]: [답변]: ATL Event에서 스크립트가 값을 다시 돌려주는 방법은?
383정성태5/30/200613275            답변글 [답변]: [답변]: [답변]: ATL Event에서 스크립트가 값을 다시 돌려주는 방법은?
378guest5/26/200612707managed 와 unmanaged 의 차이가 뭐져?
379정성태5/26/200613000    답변글 [답변]: managed 와 unmanaged 의 차이가 뭐져? [1]
384guest5/30/200612529        답변글 감사합니다.
376노기도5/16/200612726vb6의 GetObjectContext 를 2005에서는 어떻게 사용해야 하나요? [3]
375이덕희5/15/200614921SmartClient 강좌를 보고... 엑박이 나옵니다... [2]파일 다운로드1
... 76  77  78  79  80  81  82  [83]  84  85  86  87  88  89  90  ...