10-1. RSA

박은서's avatar
Feb 06, 2026
10-1. RSA

1. RSA 암호

0️⃣ 필기

notion image
notion image
💡
상민이가 a공개키라고 하고 자신의 공개키를 공개하면 이게 누구의 공개키인지 알 수 없음! 그래서 RSA로 대칭키를 전달해서 대칭키 전달의 문제 해결하고 정말 보내고자 하는 내용은 대칭키로 잠궈서 보냄!

1️⃣ 보안의 3요소 (CIA)

  • 기밀성 (Confidentiality)
    • → 허가된 사람만 메시지를 볼 수 있어야 함
  • 무결성 (Integrity)
    • → 메시지가 중간에 위·변조되지 않았음을 보장
  • 가용성 (Availability)
    • → 필요할 때 정상적으로 사용 가능

2️⃣ 기존 통신 환경의 문제

1) 상황

  • 송신자 홍군 A (50명) ↔ 수신자 홍군 B (50명)
  • 중간 공격자(청군) 약 70명
  • 공격 방식
    • 도청: 평문(Plaintext) 그대로 탈취
    • 위조: 메시지를 바꿔치기 (무결성 깨짐)

2) 문제점

  • 암호화를 안 하면 → 기밀성 X
  • 암호화를 해도:
    • “누가 보냈는지” 확인 불가 → 무결성 X
    • 열쇠를 안전하게 전달할 방법이 없음

3️⃣ 대칭키 암호의 한계

  • 암호화(C)와 복호화에 같은 키 사용
  • 장점: 빠름
  • 치명적 단점:
    • 🔑 키를 안전하게 전달할 방법이 없음
    • 키가 탈취되면 모든 보안 붕괴

4️⃣ 디피-헬만(Diffie-Hellman) 키 교환

1) 목적

  • 기밀성 확보
  • 공개된 채널에서도 공통 비밀키 생성

2) 개념 흐름

  1. 공개 정보
      • 공통 소수 ggg
      • 공통 모듈러 ppp
  1. 개인 비밀
      • A의 비밀값 aaa
      • B의 비밀값 bbb
  1. 계산
      • A → gamod  pg^a \mod pgamodp
      • B → gbmod  pg^b \mod pgbmodp
  1. 최종 공유 비밀
      • (gb)a=(ga)b(g^b)^a = (g^a)^b(gb)a=(ga)b

3) 핵심

  • 공개키 값은 커질수록 경우의 수 폭증
  • 역으로 비밀값을 구하는 것이 매우 어려움

4) ⚠️ 한계

  • 누가 보냈는지 증명 불가 → 무결성 해결 안 됨

5️⃣ RSA의 등장 배경

  • Diffie-Hellman: 기밀성 O / 무결성 X
  • RSA 목표:
    • 기밀성
    • 무결성
    • 공개키 환경에서 안전한 통신

6️⃣ RSA 기본 개념

1) 키 구조 (2개)

  • 공개키 (Public Key) → open
  • 개인키 (Private Key) → close

2) 특징

  • 공개키로 암호화한 메시지는
    • 오직 대응되는 개인키로만 복호화 가능
  • 개인키는 절대 공개 ❌

7️⃣ RSA 통신 시나리오 (예시)

상황

  • 길동 → 꺽정에게 메시지 전송
  • 중간에 상민(공격자) 존재

① A의 개인키만 사용 (서명 X)

  • A 개인키로 암호화 → 누구나 공개키로 열 수 있음
  • ❌ 기밀성 없음
  • ✔️ 무결성은 어느 정도 확보

② B의 공개키만 사용

  • 기밀성 O
  • ❌ 누가 보냈는지 알 수 없음
  • 상민이 메시지 위조 가능

RSA 핵심 방식 (정답)

  1. B의 공개키로 암호화
    1. → 기밀성 확보
  1. A의 개인키로 서명
    1. → 무결성 확보
수신자 B는:
  1. A의 공개키로 서명 검증 (누가 보냈는지 확인)
  1. B의 개인키로 메시지 복호화
➡️ 기밀성 + 무결성 모두 충족

8️⃣ RSA 핵심 요약

  • 🔐 공개키 암호 방식
  • 🔑 키 전달 문제 해결
  • ✍️ 전자서명으로 무결성 확보
  • 📌 Diffie-Hellman의 단점을 보완

9️⃣ 한 줄 요약

RSA는 “공개키 암호 + 전자서명”을 통해 기밀성과 무결성을 동시에 만족시키는 암호 방식이다.

🔟 실습

implementation "com.nimbusds:nimbus-jose-jwt:9.37.3"
import com.nimbusds.jose.*; import com.nimbusds.jose.crypto.RSADecrypter; import com.nimbusds.jose.crypto.RSAEncrypter; import com.nimbusds.jose.crypto.RSASSASigner; import com.nimbusds.jose.crypto.RSASSAVerifier; import com.nimbusds.jose.jwk.RSAKey; import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; import java.nio.charset.StandardCharsets; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; public class RSAUtil { // RSA 키 생성 (개인키, 공개키) public static RSAKey generateRSAKey(String keyId) throws JOSEException { return new RSAKeyGenerator(2048).keyID(keyId).generate(); } // 공개키로 암호화 public static String encrypt(String message, RSAPublicKey publicKey) throws JOSEException { JWEObject encryptObject = new JWEObject( new JWEHeader(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A256GCM), new Payload(message.getBytes(StandardCharsets.UTF_8)) ); encryptObject.encrypt(new RSAEncrypter(publicKey)); return encryptObject.serialize(); } // 개인키로 서명 public static String sign(String payload, RSAPrivateKey privateKey) throws JOSEException { JWSObject signObject = new JWSObject( new JWSHeader(JWSAlgorithm.RS256), new Payload(payload) ); signObject.sign(new RSASSASigner(privateKey)); return signObject.serialize(); } // 공개키로 서명검증 public static String verifySignature(String signedToken, RSAPublicKey publicKey) throws Exception { JWSObject signObject = JWSObject.parse(signedToken); if (signObject.verify(new RSASSAVerifier(publicKey))) { return signObject.getPayload().toString(); }else{ throw new RuntimeException("공개키 서명 검증 실패"); } } // 개인키로 복호화 public static String decrypt(String encryptedToken, RSAPrivateKey privateKey) throws Exception { JWEObject encryptObject = JWEObject.parse(encryptedToken); encryptObject.decrypt(new RSADecrypter(privateKey)); return encryptObject.getPayload().toString(); } }
import com.nimbusds.jose.*; import com.nimbusds.jose.crypto.*; import com.nimbusds.jose.jwk.RSAKey; public class RSADemo { public static void main(String[] args) throws Exception { String msg = "나는 오늘 백운포에 송원 왕갈비를 먹으러 간다 비밀이다!!"; // 0. A(송신자), B(수신자) RSA 키 생성 RSAKey aKey = RSAUtil.generateRSAKey("A"); RSAKey bKey = RSAUtil.generateRSAKey("B"); RSAKey cKey = RSAUtil.generateRSAKey("C"); // ===== 송신 과정 ===== // 1. 수신자(B)의 공개키로 암호화 String encrypted = RSAUtil.encrypt(msg, bKey.toRSAPublicKey()); System.out.println("1. 암호화: " + encrypted.substring(0, 50) + "..."); // 2. 송신자(A)의 개인키로 서명 String signed = RSAUtil.sign(encrypted, aKey.toRSAPrivateKey()); System.out.println("2. 서명: " + signed.substring(0, 50) + "..."); System.out.println(); // ===== 수신 과정 ===== // 3. 송신자(A)의 공개키로 서명 검증 String verify = RSAUtil.verifySignature(signed, aKey.toRSAPublicKey()); System.out.println("3. 서명 검증: " + verify); // 4. 수신자(B)의 개인키로 복호화 String decrypted = RSAUtil.decrypt(verify, bKey.toRSAPrivateKey()); System.out.println("4. 복호화: " + decrypted); } }
Share article