RSA 키 쌍 이해하기: 키 길이, PEM 형식, 그리고 언제 RSA를 쓰는가
RSA는 서로 다른 두 키를 쓰는 공개키 암호 방식입니다. 한쪽으로 잠근 것은 다른 쪽으로만 열립니다. 이 성질에서 두 가지 용도가 나옵니다. 공개키로 암호화하고 개인키로 복호화하면 기밀성이 되고, 개인키로 서명하고 공개키로 검증하면 진위 확인이 됩니다. 이 도구는 브라우저의 Web Crypto API로 키 쌍을 생성합니다.
키 길이를 어떻게 고를까
2048비트가 실무의 기본값입니다. 4096비트가 더 안전하지만 대가가 있습니다. 키 생성이 눈에 띄게 오래 걸리고, 서명·검증 연산 비용이 커지며, 서명 값 자체가 커집니다. 초당 수천 건의 토큰을 검증하는 서비스라면 이 비용이 실제 지연으로 나타납니다. 반대로 몇 년에 한 번 쓰는 루트 키라면 4096비트를 쓰는 것이 합리적입니다.
| 키 길이 | 대칭키 환산 강도 | 상태 | 용도 |
|---|---|---|---|
| 1024비트 | 약 80비트 | 부적합 | 새로 쓰면 안 됨 |
| 2048비트 | 약 112비트 | 현재 표준 | 대부분의 TLS 인증서, JWT 서명 |
| 3072비트 | 약 128비트 | 여유 있는 선택 | 장기 보관이 필요한 서명 |
| 4096비트 | 약 152비트 | 보수적 | 루트 CA, 수명이 매우 긴 키 |
사용 방법
- 키 길이를 선택합니다. 특별한 이유가 없다면 2048비트를 고르세요.
- 생성 버튼을 누르면 키 쌍이 만들어집니다. 4096비트는 브라우저에서 수 초가 걸릴 수 있습니다.
- 공개키는 검증하거나 암호화할 쪽에 배포합니다. 공개되어도 무방합니다.
- 개인키는 절대 공유하지 않고 안전한 곳에 보관합니다. 유출되면 즉시 키를 폐기하고 새로 발급해야 합니다.
PEM 헤더로 형식 구분하기
PEM 파일은 Base64로 인코딩된 키를 사람이 읽을 수 있는 헤더로 감싼 텍스트 형식입니다. 헤더 줄만 봐도 어떤 형식인지 알 수 있고, 라이브러리가 특정 형식만 받아들이는 경우가 많아 구분이 중요합니다.
# 개인키에서 공개키 추출 openssl rsa -in private.pem -pubout -out public.pem # PKCS#1 → PKCS#8 변환 openssl pkcs8 -topk8 -nocrypt -in pkcs1.pem -out pkcs8.pem # 키 정보 확인 (길이, 지수 등) openssl rsa -in private.pem -text -noout
| 헤더 | 형식 | 설명 |
|---|---|---|
| BEGIN PUBLIC KEY | SPKI (X.509) | 알고리즘 정보를 포함한 범용 공개키 형식 |
| BEGIN RSA PUBLIC KEY | PKCS#1 | RSA 전용 공개키 형식 |
| BEGIN PRIVATE KEY | PKCS#8 | 알고리즘 정보를 포함한 범용 개인키 형식 (현재 권장) |
| BEGIN RSA PRIVATE KEY | PKCS#1 | RSA 전용 개인키. 레거시 도구에서 흔함 |
| BEGIN ENCRYPTED PRIVATE KEY | PKCS#8 암호화 | 암호로 보호된 개인키 |
| BEGIN OPENSSH PRIVATE KEY | OpenSSH | SSH 전용. ssh-keygen이 생성하는 형식 |
RSA가 아니라 다른 것을 써야 할 때
RSA로 큰 데이터를 직접 암호화하려는 시도는 잘못된 접근입니다. RSA는 키 길이보다 짧은 데이터만 처리할 수 있어서, 2048비트 키에 OAEP 패딩을 쓰면 실제로 암호화 가능한 평문은 190바이트 정도에 불과합니다. 파일을 암호화해야 한다면 AES 같은 대칭키로 데이터를 암호화하고, 그 AES 키만 RSA로 감싸는 하이브리드 방식을 씁니다. TLS가 정확히 이 구조입니다.
새 시스템에서 서명이 목적이라면 타원곡선 방식(Ed25519, ECDSA P-256)이 대체로 더 나은 선택입니다. 같은 보안 강도에서 키와 서명이 훨씬 짧고 연산이 빠릅니다. Ed25519 공개키는 32바이트인데 2048비트 RSA 공개키는 256바이트입니다. RSA를 쓰는 주된 이유는 여전히 호환성, 즉 상대 시스템이 그것만 받아들이는 경우입니다.
이런 곳에 씁니다
- JWT를 RS256으로 서명하고 여러 서비스가 공개키로 검증하는 구조
- SSH 공개키 인증 (다만 ssh-keygen -t ed25519 가 요즘 권장)
- TLS 인증서 발급을 위한 CSR 생성
- 패키지나 릴리스 아티팩트에 서명해 배포 무결성 보장
- 서로 다른 조직 간에 주고받는 데이터의 서명 검증
개인키 보관
개인키는 유출되면 그 키로 보호되던 모든 것이 무너지는 값입니다. 소스 저장소에 커밋하지 않는 것은 기본이고, .gitignore에 넣는 것만으로는 이미 커밋된 이력이 남을 수 있으니 주의해야 합니다. 운영 환경에서는 클라우드 KMS나 HashiCorp Vault처럼 키를 밖으로 내보내지 않고 서명 연산만 대행하는 서비스를 쓰는 것이 가장 안전합니다. 최소한 파일 권한을 600으로 제한하고, 암호로 보호된 PKCS#8 형식으로 저장하세요.
자주 묻는 질문
- 생성된 키가 서버로 전송되나요?
- 전송되지 않습니다. 브라우저의 Web Crypto API가 로컬에서 키를 생성합니다. 그렇더라도 브라우저에서 만든 키를 장기 운영용 개인키로 쓰는 것은 권장하지 않습니다. 브라우저 확장 프로그램이나 클립보드 접근 등 통제하기 어려운 변수가 많기 때문입니다. 학습·테스트 용도로 쓰고, 운영 키는 서버나 KMS에서 생성하세요.
- 공개키만 있으면 개인키를 알아낼 수 있나요?
- 현실적인 시간 안에는 불가능합니다. RSA의 안전성은 큰 수의 소인수분해가 어렵다는 데 기반하며, 2048비트 키를 분해하는 것은 현존 컴퓨팅 자원으로 실현 불가능합니다. 다만 양자컴퓨터가 충분히 발전하면 Shor 알고리즘으로 이 가정이 무너지므로, 장기적으로는 내양자 암호로의 전환이 논의되고 있습니다.
- 키 쌍을 잃어버리면 복구할 수 있나요?
- 개인키를 잃으면 복구할 방법이 없습니다. 개인키로 암호화된 데이터는 영구히 열 수 없고, 그 키로 인증하던 시스템에는 새 키를 등록해야 합니다. 공개키는 개인키에서 언제든 다시 추출할 수 있으므로 공개키만 잃는 것은 문제가 되지 않습니다.
- SSH에 바로 쓸 수 있나요?
- 형식 변환이 필요합니다. SSH의 authorized_keys는 PEM이 아니라 'ssh-rsa AAAAB3Nza...' 형태의 한 줄 형식을 씁니다. ssh-keygen -i -m PKCS8 -f public.pem 으로 변환할 수 있지만, SSH 키를 새로 만드는 것이 목적이라면 ssh-keygen -t ed25519 를 쓰는 편이 간단하고 권장되는 방식입니다.
- 공개 지수 65537은 무슨 의미인가요?
- RSA 공개키는 모듈러스와 공개 지수 두 값으로 이루어지고, 공개 지수는 거의 항상 65537입니다. 이 값은 2^16+1로 이진수에서 1이 두 개뿐이어서 암호화·검증 연산이 빠르고, 동시에 3처럼 너무 작은 값에서 발생하는 몇몇 공격을 피할 수 있을 만큼은 큽니다. 특별한 이유가 없다면 바꿀 필요가 없습니다.
- PEM 파일의 줄바꿈이 사라졌는데 괜찮나요?
- 문제가 됩니다. 많은 파서가 헤더·본문·푸터가 줄 단위로 나뉜 것을 전제합니다. 환경변수에 PEM을 넣을 때 줄바꿈이 \n 문자열로 들어가 파싱에 실패하는 일이 흔합니다. 이 경우 값을 읽은 뒤 replace(/\\n/g, "\n") 로 복원하거나, PEM 전체를 Base64로 한 번 더 감싸 한 줄로 저장하는 방식을 씁니다.
💡 참고: 개인키를 실수로 저장소에 커밋했다면 히스토리에서 지우는 것만으로 끝내지 마세요. 이미 노출된 키는 즉시 폐기하고 새로 발급하는 것이 유일하게 확실한 대응입니다.