전자서명 작동 원리와 실전 구현 방법 - Python & Java 예제
전자서명은 온라인 세상에서 종이 도장이나 사인을 대신하는 디지털 기술입니다. 암호화 기술로 문서의 진짜 주인이 누구인지, 문서가 위조되지 않았는지 확인할 수 있어 인터넷 뱅킹, 전자계약, 암호화폐 거래 등에서 필수적으로 사용됩니다.
이 글에서는 전자서명이 어떻게 작동하는지 쉽게 설명하고, RSA와 ECDSA 같은 대표 알고리즘을 비교합니다. 또한 Python과 Java로 실제 전자서명을 구현하는 방법을 단계별로 안내하여 개발자가 바로 활용할 수 있도록 합니다.
전자서명은 디지털 문서에 붙이는 '암호화된 도장'입니다. 종이에 하는 서명이나 도장과 달리, 수학적 암호 기술로 만들어져서 복사하거나 위조하는 것이 거의 불가능합니다.
전자서명은 세 가지 중요한 역할을 합니다.
전자서명을 보면 이 문서에 누가 서명했는지 정확히 알 수 있습니다. 마치 지문처럼 각 사람마다 고유한 서명이 만들어지기 때문입니다.
문서 내용이 단 한 글자라도 바뀌면 전자서명이 무효가 됩니다. 이를 통해 계약서나 중요 문서가 위조되는 것을 막을 수 있습니다.
전자서명을 하면 나중에 "나는 서명한 적 없다"고 부인할 수 없습니다. 암호학적으로 서명자가 증명되기 때문입니다.
| 구분 | 종이 서명/도장 | 전자서명 |
|---|---|---|
| 형태 | 손으로 쓴 사인, 도장 찍기 | 암호화된 디지털 코드 |
| 확인 방법 | 눈으로 비교, 필적 감정 | 컴퓨터가 자동 검증 |
| 위조 가능성 | 연습하면 흉내낼 수 있음 | 수학적으로 거의 불가능 |
| 변경 감지 | 어려움 (잘 모름) | 즉시 감지 가능 |
| 복사 가능성 | 스캔하면 쉽게 복사됨 | 비밀키 없이는 불가능 |
| 법적 효력 | 인정됨 | 동등하게 인정됨 |
전자서명은 우리 일상과 비즈니스 곳곳에서 사용됩니다.

전자서명은 복잡한 수학을 사용하지만, 기본 원리는 의외로 간단합니다. 두 개의 열쇠(키)를 사용하는 방식으로 생각하면 쉽습니다.
전자서명은 수학적으로 연결된 두 개의 열쇠를 사용합니다.
절대로 남에게 보여주면 안 되는 비밀 열쇠입니다. 이 열쇠로 전자서명을 만듭니다. 마치 은행 계좌 비밀번호처럼 본인만 알고 있어야 합니다.
모든 사람에게 공개하는 열쇠입니다. 이 열쇠로 내가 만든 서명이 진짜인지 확인합니다. 은행 계좌번호처럼 다른 사람이 알아도 괜찮습니다.

전자서명을 만드는 과정을 요리에 비유하면 쉽게 이해할 수 있습니다.
먼저 문서 전체를 해시 함수라는 특별한 기계에 넣으면 짧은 '디지털 지문'이 나옵니다. 아무리 긴 문서라도 항상 같은 길이의 지문이 만들어집니다.
원본 문서: "홍길동은 2024년 12월 17일에 계약에 동의합니다."
↓ (SHA-256 해시 함수 적용)
해시값(지문): a3f5d8c2e9b1f7a4c6d2e8f3b9c1d5a7e2f8c4b6d9a1e3f7c5b2d8a4
문서가 조금이라도 바뀌면 완전히 다른 지문이 나옵니다.
만들어진 디지털 지문을 나만 가진 개인키로 암호화합니다. 이렇게 암호화된 지문이 바로 전자서명입니다.
만든 전자서명을 원본 문서에 붙여서 완성합니다. 이제 이 문서를 다른 사람에게 보낼 수 있습니다.


받는 사람이 서명을 확인하는 방법도 간단합니다.
받은 문서를 똑같은 해시 함수에 넣어서 지문을 계산합니다.
문서에 붙어있는 전자서명을 보낸 사람의 공개키로 풀면 원래의 지문이 나옵니다.
내가 계산한 지문과 서명에서 나온 지문을 비교합니다.
전자서명이 안전한 이유는 세 가지입니다.
전자서명을 만드는 방법(알고리즘)은 여러 가지가 있습니다. 가장 많이 사용되는 RSA와 ECDSA 두 가지를 비교해보겠습니다.
RSA는 1977년에 만들어진 가장 유명한 암호 알고리즘입니다. 은행, 정부 웹사이트 등에서 널리 사용됩니다.
ECDSA는 타원곡선 암호를 사용하는 알고리즘으로, 비트코인과 이더리움 같은 암호화폐에서 사용됩니다.
| 비교 항목 | RSA | ECDSA |
|---|---|---|
| 키 크기 | 2048~4096비트 | 256~384비트 |
| 서명 만들기 속도 | 보통 | 빠름 ⚡ |
| 서명 확인 속도 | 매우 빠름 ⚡⚡ | 보통 |
| 보안 수준 | 높음 (2048비트 기준) | 높음 (256비트 기준) |
| 개발 역사 | 1977년 (47년) | 2008년 (16년) |
| 모바일 적합성 | 보통 | 매우 좋음 📱 |
| 배우기 쉬운 정도 | 쉬움 | 어려움 |
| 주요 사용처 | 웹사이트(HTTPS), 이메일 | 비트코인, 스마트폰 앱 |
이제 실제로 전자서명을 만들고 확인하는 코드를 작성해보겠습니다. Python과 Java 두 가지 언어로 RSA 전자서명을 구현하는 방법을 단계별로 설명합니다.
Python에서는 cryptography 라이브러리를 사용하면 쉽게 전자서명을 구현할 수 있습니다.
pip install cryptography
from cryptography.hazmat.primitives import hashes
import base64
# 1단계: 키 쌍(개인키, 공개키) 생성
print("1단계: 키 쌍 생성 중...")
private_key = rsa.generate_private_key(
public_exponent=65537, # 표준 값
key_size=2048 # 2048비트 키 생성
)
public_key = private_key.public_key()
print("✅ 키 쌍 생성 완료!")
# 2단계: 서명할 문서 준비
document = "홍길동은 2024년 12월 17일에 계약에 동의합니다."
data = document.encode('utf-8') # 문자열을 바이트로 변환
print(f"\n2단계: 서명할 문서 = {document}")
# 3단계: 전자서명 생성 (개인키로 서명)
print("\n3단계: 전자서명 생성 중...")
signature = private_key.sign(
data,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256() # SHA-256 해시 사용
)
# 서명을 Base64로 인코딩하여 읽기 쉽게 만들기
signature_b64 = base64.b64encode(signature).decode('utf-8')
print(f"✅ 전자서명 생성 완료!")
print(f"서명(Base64): {signature_b64[:50]}...") # 앞부분만 출력
# 4단계: 전자서명 검증 (공개키로 확인)
print("\n4단계: 전자서명 검증 중...")
try:
public_key.verify(
signature,
data,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
print("✅ 서명 검증 성공! 문서가 진짜이고 변조되지 않았습니다.")
except Exception as e:
print(f"❌ 서명 검증 실패! 문서가 위조되었거나 변조되었습니다.")
# 5단계: 문서 변조 테스트
print("\n5단계: 문서 변조 테스트...")
tampered_data = "홍길동은 2024년 12월 18일에 계약에 동의합니다.".encode('utf-8')
try:
public_key.verify(
signature,
tampered_data, # 변조된 문서
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
print("❌ 예상치 못한 결과: 변조된 문서가 통과됨")
except:
print("✅ 정상 작동: 변조된 문서는 검증 실패!")
✅ 키 쌍 생성 완료!
2단계: 서명할 문서 = 홍길동은 2024년 12월 17일에 계약에 동의합니다.
3단계: 전자서명 생성 중...
✅ 전자서명 생성 완료!
서명(Base64): gX7Kp2Lm9vNQ8rTaWc3dFh5Jk6lP0nMq1sRt4uVx7wYz...
4단계: 전자서명 검증 중...
✅ 서명 검증 성공! 문서가 진짜이고 변조되지 않았습니다.
5단계: 문서 변조 테스트...
✅ 정상 작동: 변조된 문서는 검증 실패!
Java에서는 기본 제공되는 java.security 패키지를 사용하여 전자서명을 구현할 수 있습니다. 별도 라이브러리 설치 없이 바로 사용 가능합니다.
import java.util.Base64;
public class DigitalSignatureExample {
public static void main(String[] args) {
try {
// 1단계: 키 쌍(개인키, 공개키) 생성
System.out.println("1단계: 키 쌍 생성 중...");
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048); // 2048비트 키 생성
KeyPair keyPair = keyGen.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
System.out.println("✅ 키 쌍 생성 완료!\n");
// 2단계: 서명할 문서 준비
String document = "홍길동은 2024년 12월 17일에 계약에 동의합니다.";
byte[] data = document.getBytes("UTF-8");
System.out.println("2단계: 서명할 문서 = " + document + "\n");
// 3단계: 전자서명 생성 (개인키로 서명)
System.out.println("3단계: 전자서명 생성 중...");
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey); // 개인키로 초기화
signature.update(data); // 문서 데이터 입력
byte[] signatureBytes = signature.sign(); // 서명 생성
// 서명을 Base64로 인코딩하여 읽기 쉽게 만들기
String signatureB64 = Base64.getEncoder().encodeToString(signatureBytes);
System.out.println("✅ 전자서명 생성 완료!");
System.out.println("서명(Base64): " +
signatureB64.substring(0, 50) + "...\n");
// 4단계: 전자서명 검증 (공개키로 확인)
System.out.println("4단계: 전자서명 검증 중...");
Signature verifier = Signature.getInstance("SHA256withRSA");
verifier.initVerify(publicKey); // 공개키로 초기화
verifier.update(data); // 원본 문서 입력
boolean isValid = verifier.verify(signatureBytes);
if (isValid) {
System.out.println("✅ 서명 검증 성공! " +
"문서가 진짜이고 변조되지 않았습니다.\n");
} else {
System.out.println("❌ 서명 검증 실패! " +
"문서가 위조되었거나 변조되었습니다.\n");
}
// 5단계: 문서 변조 테스트
System.out.println("5단계: 문서 변조 테스트...");
String tamperedDoc = "홍길동은 2024년 12월 18일에 계약에 동의합니다.";
byte[] tamperedData = tamperedDoc.getBytes("UTF-8");
Signature verifier2 = Signature.getInstance("SHA256withRSA");
verifier2.initVerify(publicKey);
verifier2.update(tamperedData); // 변조된 문서
boolean isValid2 = verifier2.verify(signatureBytes);
if (!isValid2) {
System.out.println("✅ 정상 작동: 변조된 문서는 검증 실패!");
} else {
System.out.println("❌ 예상치 못한 결과: 변조된 문서가 통과됨");
}
} catch (Exception e) {
System.err.println("에러 발생: " + e.getMessage());
e.printStackTrace();
}
}
}
✅ 키 쌍 생성 완료!
2단계: 서명할 문서 = 홍길동은 2024년 12월 17일에 계약에 동의합니다.
3단계: 전자서명 생성 중...
✅ 전자서명 생성 완료!
서명(Base64): dR6Mn8Tp4xQw2vLk9fHj3cBm5nGp7sRq1tUx0wYz6aKc...
4단계: 전자서명 검증 중...
✅ 서명 검증 성공! 문서가 진짜이고 변조되지 않았습니다.
5단계: 문서 변조 테스트...
✅ 정상 작동: 변조된 문서는 검증 실패!
ECDSA는 더 작은 키로 같은 보안을 제공합니다. Python에서 ECDSA를 구현하는 방법을 살펴보겠습니다.
from cryptography.hazmat.primitives import hashes
import base64
# 1단계: ECDSA 키 쌍 생성 (256비트)
print("1단계: ECDSA 키 쌍 생성 중...")
private_key = ec.generate_private_key(ec.SECP256R1())
public_key = private_key.public_key()
print("✅ 키 쌍 생성 완료! (256비트 ECDSA)\n")
# 2단계: 서명할 문서
document = "비트코인 거래: 0.5 BTC를 전송합니다."
data = document.encode('utf-8')
print(f"2단계: 서명할 문서 = {document}\n")
# 3단계: ECDSA 서명 생성
print("3단계: ECDSA 서명 생성 중...")
signature = private_key.sign(
data,
ec.ECDSA(hashes.SHA256())
)
signature_b64 = base64.b64encode(signature).decode('utf-8')
print(f"✅ 서명 생성 완료! (크기: {len(signature)} 바이트)")
print(f"서명(Base64): {signature_b64[:50]}...\n")
# 4단계: ECDSA 서명 검증
print("4단계: ECDSA 서명 검증 중...")
try:
public_key.verify(
signature,
data,
ec.ECDSA(hashes.SHA256())
)
print("✅ ECDSA 서명 검증 성공!")
except:
print("❌ ECDSA 서명 검증 실패!")
보안을 위해 RSA는 최소 2048비트, ECDSA는 256비트 이상 사용을 권장합니다. 더 높은 보안이 필요하면 RSA 4096비트, ECDSA 384비트를 사용하세요.
SHA-256이 가장 일반적이고 안전합니다. SHA-1은 보안 취약점이 있어 사용하지 마세요.
개인키는 절대로 외부에 노출되면 안 됩니다. 암호화된 파일로 저장하거나 하드웨어 보안 모듈(HSM)을 사용하세요.
실제 서비스에서는 반드시 try-catch 블록으로 에러를 처리하고, 적절한 로그를 남겨야 합니다.
A: 아니요. 전자서명은 문서에 디지털 도장을 찍는 기술이고, 전자인증서는 "이 공개키가 정말로 홍길동의 것이 맞다"고 증명하는 문서입니다. 인증서는 신뢰할 수 있는 기관(CA)이 발급하며, 전자서명을 할 때 함께 사용됩니다.
A: 개인키를 잃어버리면 새로운 키를 만들어야 합니다. 기존에 서명한 문서는 여전히 확인할 수 있지만, 새로운 서명을 만들 수 없습니다. 따라서 개인키는 암호화하여 안전한 곳에 백업해두는 것이 중요합니다.
A: 현재 기술로는 RSA 2048비트를 해독하려면 수백만 년이 걸립니다. 따라서 수학적으로는 매우 안전합니다. 하지만 개인키를 잘못 관리하거나, 피싱 공격으로 개인키가 유출되면 위험합니다. 보안의 핵심은 개인키를 안전하게 보관하는 것입니다.
A: 같은 보안 수준에서 두 알고리즘 모두 안전합니다. RSA 2048비트 = ECDSA 256비트 = 동일한 보안입니다. 차이점은 키 크기, 속도, 사용 편의성입니다. 모바일 환경이면 ECDSA가, 웹 환경이면 RSA가 더 적합합니다.
A: 아니요. 전자서명을 인쇄하면 디지털 서명이 사라집니다. 인쇄된 문서는 그냥 종이가 되어 서명을 검증할 수 없습니다. 법적 효력을 유지하려면 원본 디지털 파일을 보관해야 합니다.
A: 네, 안전합니다. 공개키는 서명을 확인하는 데만 사용되고, 서명을 만들 수는 없습니다. 공개키로 개인키를 알아내는 것은 수학적으로 거의 불가능합니다. 은행 계좌번호를 알아도 돈을 인출할 수 없는 것과 비슷합니다.
A: 전자서명 자체는 영구적이지만, 인증서에는 유효기간이 있습니다. 인증서가 만료되면 새로운 서명을 만들 수 없지만, 유효기간 내에 만든 서명은 계속 유효합니다. 인증서는 보통 1~3년마다 갱신해야 합니다.
A: 네, 양자컴퓨터는 현재의 RSA와 ECDSA를 위협할 수 있습니다. 하지만 이에 대비한 '양자 내성 암호' 연구가 진행 중입니다. 미국 NIST는 2024년에 새로운 양자 내성 암호 표준을 발표했으며, 앞으로 이러한 알고리즘으로 전환될 예정입니다.
A: 네, 스마트폰에서 많이 사용됩니다. 모바일 뱅킹, 카카오페이, PASS 인증 등이 모두 전자서명 기술을 사용합니다. ECDSA는 작은 키 크기 덕분에 스마트폰에 특히 적합하며, 지문이나 얼굴 인식과 결합하여 더 안전하게 사용됩니다.
A: 블록체인은 전자서명을 핵심 기술로 사용합니다. 비트코인, 이더리움 등 모든 암호화폐 거래는 ECDSA 전자서명으로 승인됩니다. 개인키로 거래에 서명하면 그 암호화폐가 정말로 내 것임을 증명하는 방식입니다. 블록체인 없이는 암호화폐가 존재할 수 없습니다.
전자서명은 암호화 기술로 디지털 문서의 진위를 보장하는 필수 기술입니다. 개인키와 공개키라는 두 개의 열쇠를 사용하여 서명을 만들고 확인하는 원리는 의외로 간단하지만, 수학적으로 매우 강력한 보안을 제공합니다.
RSA는 40년 이상 검증된 신뢰할 수 있는 방식이며, ECDSA는 작은 키로 높은 보안을 제공하는 현대적 방식입니다. 웹사이트나 이메일 보안에는 RSA가, 모바일 앱이나 블록체인에는 ECDSA가 더 적합합니다.
Python과 Java로 실제 전자서명을 구현하는 것은 생각보다 어렵지 않습니다. 제공된 예제 코드를 활용하면 몇 줄의 코드만으로 강력한 전자서명 시스템을 구축할 수 있습니다. 다만 개인키 보관과 에러 처리에 각별히 주의해야 합니다.
전자서명은 온라인 뱅킹, 전자계약, 암호화폐 등 디지털 경제의 신뢰를 떠받치는 기반 기술입니다. 이 기술을 올바르게 이해하고 활용하면 더 안전하고 효율적인 디지털 서비스를 만들 수 있습니다.
양자컴퓨터의 등장으로 새로운 도전이 예상되지만, 양자 내성 암호 연구가 활발히 진행되고 있어 미래에도 안전한 전자서명 기술이 계속 발전할 것입니다.
끝.
'Development > Security' 카테고리의 다른 글
| [Security] 대칭키 암호화 원리와 Java 구현 방법 - AES·DES 비교 분석 (0) | 2019.09.22 |
|---|---|
| [Security] Base64 완벽 가이드 : 개념부터 실전 코드까지 (0) | 2019.09.09 |
| [Security] 공개키 인증서 완벽 가이드 : 일반인도 쉽게 이해할 수 있는 디지털 신분증 개념부터 활용까지 한 방에 이해하기 (0) | 2019.09.04 |
| [Security] X.509 인증서에 대하여 (0) | 2019.09.02 |
| [Security] 대칭키 암호화 Padding 과 Mode (0) | 2019.08.29 |