
공개키 vs 개인키: 비대칭 암호화
자물쇠(Public)는 뿌리고, 열쇠(Private)는 나만 갖는다. HTTPS와 블록체인의 원리.

자물쇠(Public)는 뿌리고, 열쇠(Private)는 나만 갖는다. HTTPS와 블록체인의 원리.
내 서버는 왜 걸핏하면 뻗을까? OS가 한정된 메모리를 쪼개 쓰는 처절한 사투. 단편화(Fragmentation)와의 전쟁.

미로를 탈출하는 두 가지 방법. 넓게 퍼져나갈 것인가(BFS), 한 우물만 팔 것인가(DFS). 최단 경로는 누가 찾을까?

프론트엔드 개발자가 알아야 할 4가지 저장소의 차이점과 보안 이슈(XSS, CSRF), 그리고 언제 무엇을 써야 하는지에 대한 명확한 기준.

이름부터 빠릅니다. 피벗(Pivot)을 기준으로 나누고 또 나누는 분할 정복 알고리즘. 왜 최악엔 느린데도 가장 많이 쓰일까요?

처음 GitHub에 코드를 push하려다 막혔던 기억이 있다. 매번 비밀번호를 쳐야 했는데, 어느 날 갑자기 "Password authentication is removed"라는 에러를 만났다. 검색해보니 SSH 키를 등록하라고 했다.
ssh-keygen 명령어를 쳤더니 id_rsa와 id_rsa.pub 두 파일이 생겼다. 공개키는 GitHub에 올리고, 개인키는 내 컴퓨터에 둔다고 했다. "이게 도대체 왜 안전한 거지?"라는 의문이 들었다. 비밀번호처럼 탈취당하면 어떡하나? 근데 공개키는 이름 그대로 공개해도 된다니, 너무 이상했다.
이 질문을 해결하려다 공개키 암호화(비대칭 암호화)라는 개념을 만났다. 처음엔 "수학 마법"처럼 느껴졌지만, 하나씩 풀어보니 결국 간단한 원리였다. 나를 위한 정리 노트를 남겨본다.
처음 암호화를 배울 때 접하는 건 대칭키(Symmetric Key) 방식이다. 암호화할 때 쓰는 키랑 복호화할 때 쓰는 키가 똑같다. 비밀번호 1234로 잠그면, 1234로 풀어야 한다.
# 대칭키 예시 (AES)
from cryptography.fernet import Fernet
# 키 생성 (암호화/복호화 동일)
key = Fernet.generate_key()
cipher = Fernet(key)
# 암호화
message = b"This is secret"
encrypted = cipher.encrypt(message)
# 복호화 (같은 키 사용)
decrypted = cipher.decrypt(encrypted)
print(decrypted) # b"This is secret"
문제는 이 key를 상대방에게 어떻게 전달하느냐다. 인터넷으로 키를 보내면, 중간에 누군가 가로챌 수 있다. 키를 안전하게 전달할 방법이 있다면, 그 방법으로 메시지 자체를 보내면 되는 거 아닌가? 이게 키 배달 문제(Key Distribution Problem)다.
이 문제를 해결하려고 나온 게 비대칭 암호화다.
비대칭 암호화는 키가 두 개다. 하나는 공개키(Public Key), 하나는 개인키(Private Key). 나는 이걸 자물쇠와 열쇠로 이해했다.
예를 들어, 내가 친구에게 안전한 메시지를 받고 싶다면:
이 방식의 핵심은 공개키로 잠근 건 개인키로만 풀 수 있고, 개인키로 잠근 건 공개키로만 풀 수 있다는 수학적 특성이다. RSA 같은 알고리즘이 이걸 가능하게 한다.
RSA는 "큰 소수 두 개를 곱하기는 쉬운데, 그 결과를 다시 소인수분해하기는 엄청 어렵다"는 사실에 기반한다.
예를 들어, 61 × 53 = 3233은 계산기로 1초면 된다. 하지만 3233을 보고 "이게 61과 53을 곱한 거다"라고 찾는 건 시간이 오래 걸린다(숫자가 수백 자리면 슈퍼컴퓨터로도 수십 년).
RSA 키 생성 과정을 단순화하면:
p, q)를 고른다.n = p × q를 계산한다. (이게 공개된다)e와 개인키 d를 만든다.(n, e)로 암호화하면, 개인키 (n, d)로만 복호화할 수 있다.나는 이걸 일방향 문(Trapdoor Function)이라는 비유로 받아들였다. 문은 한쪽으로만 열리고, 반대로 열려면 특별한 비밀 정보(개인키)가 필요하다.
처음 HTTPS를 배울 때, "모든 통신이 비대칭 암호화로 되는 건가?"라고 생각했다. 근데 아니었다. 비대칭 암호화는 대칭키보다 100~1000배 느리다. 그래서 실제론 하이브리드 방식을 쓴다.
HTTPS의 TLS Handshake 과정:
결국 비대칭 암호화는 "대칭키를 안전하게 교환하는 용도"로만 쓰인다. 이해하고 나니 왜 TLS Handshake가 필요한지 와닿았다.
비대칭 암호화는 반대로도 쓸 수 있다. 개인키로 암호화하고 공개키로 복호화하면, 이건 암호화가 아니라 서명(Signature)이 된다.
"왜 개인키로 잠그면 다들 공개키로 열 수 있는데 그게 무슨 의미야?"라고 생각했다. 근데 이게 핵심이었다. 공개키로 열렸다는 건, 그 메시지가 개인키 소유자가 작성했다는 증거다.
예를 들어:
이게 바로 Git 커밋 서명, 소프트웨어 배포 서명, 블록체인 트랜잭션 서명의 원리다.
내가 처음 SSH 키를 생성했던 그 순간으로 돌아가보자. SSH 인증은 비대칭 암호화의 가장 실용적인 사례다.
# SSH 키 생성
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
# 생성 결과
# ~/.ssh/id_rsa (개인키 - 절대 공유 금지)
# ~/.ssh/id_rsa.pub (공개키 - GitHub 등에 등록)
SSH 인증 과정:
비밀번호는 탈취당하면 끝이지만, SSH 키는 개인키를 절대 네트워크로 보내지 않는다. 서명만 보내니까 훨씬 안전하다.
이론만 보면 와닿지 않아서, Node.js로 직접 구현해봤다.
const crypto = require('crypto');
// 1. 키 쌍 생성 (RSA)
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: { type: 'spki', format: 'pem' },
privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
});
console.log('공개키:\n', publicKey);
console.log('개인키:\n', privateKey);
// 2. 암호화 (공개키로 잠금)
const message = '비밀 메시지입니다';
const encrypted = crypto.publicEncrypt(
publicKey,
Buffer.from(message)
);
console.log('암호문:', encrypted.toString('base64'));
// 3. 복호화 (개인키로 해독)
const decrypted = crypto.privateDecrypt(
privateKey,
encrypted
);
console.log('복호화:', decrypted.toString()); // "비밀 메시지입니다"
// 4. 서명 (개인키로 서명)
const sign = crypto.createSign('SHA256');
sign.update(message);
const signature = sign.sign(privateKey, 'base64');
console.log('서명:', signature);
// 5. 서명 검증 (공개키로 확인)
const verify = crypto.createVerify('SHA256');
verify.update(message);
const isValid = verify.verify(publicKey, signature, 'base64');
console.log('서명 유효성:', isValid); // true
코드를 직접 실행해보니, "공개키로 암호화하면 개인키로만 복호화된다"는 게 실제로 작동하는 걸 확인할 수 있었다. 서명도 마찬가지로, 개인키로 서명한 건 공개키로만 검증된다.
비트코인이나 이더리움 지갑을 만들면 "개인키 절대 잃어버리지 말라"고 경고한다. 블록체인에서는 공개키가 계좌 주소고, 개인키가 인출 권한이다.
트랜잭션을 만들 때:
은행은 중앙 서버가 "이 사람이 맞나?"를 확인하지만, 블록체인은 수학적 증명(서명)으로 대체한다. 개인키를 잃어버리면 복구 불가능한 이유가 여기 있다.
HTTPS를 쓸 때, 서버가 보낸 공개키를 그냥 믿으면 안 된다. 중간자 공격(MITM)으로 가짜 공개키를 보낼 수 있다. 그래서 인증서(Certificate)와 인증 기관(CA)이 필요하다.
CA는 "이 공개키는 진짜 google.com 것이 맞다"라고 서명해주는 제3자다. 브라우저는 미리 신뢰하는 CA 목록을 갖고 있어서, CA의 서명을 검증한다.
이 구조를 이해하고 나니, Let's Encrypt 같은 무료 인증서가 왜 혁명적인지 와닿았다. 예전엔 CA 인증서 받으려면 돈을 내야 했는데, 자동화로 무료화한 거다.
공개키 암호화는 "비밀을 공유하지 않고도 비밀을 주고받는" 마법처럼 느껴진다. 하지만 결국 이건 수학이다. 소인수분해의 어려움, 일방향 함수의 특성, 이런 수학적 사실들이 현대 인터넷의 보안을 떠받치고 있다.
SSH 키를 처음 만들었을 때 느꼈던 의문, "왜 공개키는 공개해도 되는 거지?"에 대한 답을 정리해본다. 공개키는 자물쇠다. 아무리 많이 복사해서 뿌려도, 열쇠(개인키)가 없으면 아무도 못 연다. 그리고 그 열쇠는 오직 나만 갖고 있다.
이 간단한 원리가 HTTPS, SSH, 블록체인, 전자 서명을 가능하게 한다. 앞으로 "이 서비스는 어떻게 보안을 유지하지?"라는 질문을 만나면, 십중팔구 답은 "공개키 암호화"일 거다.