PYTHON/네트워크보안과 블록체인
[PYTHON] 전자서명
G허니
2024. 8. 11. 20:19
전자서명은 디지털 데이터의 무결성과 인증을 보장하기 위해 사용되는 기술입니다. 주로 비대칭 암호화 방식에 기반하여 작동하며, 두 개의 키(개인키와 공개키)를 사용하여 서명과 검증 과정을 수행합니다.
- 무결성: 전자서명을 통해 서명된 데이터가 전송 중에 변경되지 않았음을 보장합니다.
- 인증: 서명자는 개인키를 사용하여 서명을 생성하므로, 서명된 데이터는 해당 서명자의 소유임을 증명합니다.
- 부인 방지: 서명자는 서명된 메시지를 부인할 수 없으며, 이는 법적 효력을 가질 수 있습니다.
타원 곡선 암호화(ECC)를 사용하여 전자서명을 구현
import os
import random
import time
import hashlib
# 타원 곡선의 파라미터
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
G = [0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,
0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8]
a = 0
b = 7
def get_private_key():
"""개인키 생성 함수"""
while True:
random_str = os.urandom(256 // 8) + str(random.random()).encode() + str(time.time()).encode()
random_num = hashlib.sha256(random_str).digest()
private_key = int.from_bytes(random_num, 'big')
if private_key < p:
break
return private_key
def euclidian(b, n):
"""유클리드 알고리즘을 사용하여 역원을 찾는 함수"""
r1 = n
r2 = b if b > 0 else b + n
t1 = 0
t2 = 1
while r2 > 0:
q = r1 // r2
r = r1 - q * r2
r1 = r2
r2 = r
t = t1 - q * t2
t1 = t2
t2 = t
if r1 == 1:
return t1 if t1 > 0 else t1 + n
else:
return None
def euclidean_algorithm(a, b):
"""두 수의 최대공약수를 구하는 유클리드 알고리즘"""
if b == 0:
return (a, 1, 0)
else:
gcd, x, y = euclidean_algorithm(b, a % b)
return (gcd, y, x - (a // b) * y)
def find_inverse(a, p):
"""모듈로 역원을 찾는 함수"""
gcd, x, y = euclidean_algorithm(a, p)
if gcd == 1:
return x % p
else:
return None
def add(point1: list, point2: list):
"""타원 곡선 위의 두 점을 더하는 함수"""
if point1 == point2:
w = (3 * point1[0] ** 2 + a) * euclidian((2 * point1[1]), p) % p
else:
w = (point2[1] - point1[1]) * euclidian(point2[0] - point1[0], p) % p
if w < 0:
w += p
x3 = (w ** 2 - point1[0] - point2[0]) % p
y3 = (w * (point1[0] - x3) - point1[1]) % p
if x3 < 0:
x3 += p
if y3 < 0:
y3 += p
point3 = [x3, y3]
return point3
def double_and_add(x, G: list):
"""스칼라 곱셈을 수행하는 함수"""
binary = bin(x)
K = G
for i in range(3, len(binary)):
if binary[i] == '1':
K = add(add(K, K), G)
else:
K = add(K, K)
return tuple(K)
# 서명 생성 및 검증 함수
def sign(M, d):
"""메시지를 서명하는 함수"""
while True:
r = random.randint(1, q-1)
x1, y1 = double_and_add(r, e1)
S1 = x1 % q
if S1 == 0:
continue
h = int.from_bytes(hashlib.sha256(M.encode()).digest()) % q
S2 = ((h + d * S1) * find_inverse(r, q)) % q
if S2 == 0:
continue
return S1, S2
def verify(M, S1, S2, e2):
"""서명을 검증하는 함수"""
h = hashlib.sha256(M.encode()).hexdigest()
S2_inverse = find_inverse(S2, q)
A = (int(h, 16) * S2_inverse) % q
B = (S1 * S2_inverse) % q
x, y = add(double_and_add(A, e1), double_and_add(B, e2))
return x % q == S1 % q
if __name__ == "__main__":
d = get_private_key() # 개인키
e2 = double_and_add(d, G) # 공개키
M = input("메시지? ")
S1, S2 = sign(M, d) # 서명 생성
print("1. Sign:")
print("\tS1 =", hex(S1))
print("\tS2 =", hex(S2))
print("2. 정확한 서명을 입력할 경우:")
if verify(M, S1, S2, e2):
print("검증 성공")
else:
print("검증 실패")
print("3. 잘못된 서명을 입력할 경우:")
if verify(M, S1-1, S2-1, e2):
print("검증 성공")
else:
print("검증 실패")
- 모듈 임포트: 필요한 모듈을 가져옵니다. os, random, time, hashlib는 난수 생성 및 해싱에 사용됩니다.
- 타원 곡선 파라미터: p, G, a, b는 타원 곡선의 파라미터입니다. 이들은 ECC의 특정 곡선을 정의합니다.
- 개인키 생성: get_private_key() 함수는 안전한 개인키를 생성합니다. 랜덤한 문자열을 해싱하여 개인키를 생성하고, 조건에 맞는지 확인합니다.
- 유클리드 알고리즘: euclidian 및 euclidean_algorithm 함수는 모듈로 역원을 찾기 위한 최대공약수(GCD)를 계산합니다.
- 점 덧셈: add() 함수는 타원 곡선 위에서 두 점을 더하는 기능을 수행합니다.
- 서명 생성: sign() 함수는 주어진 메시지 M과 개인키 d를 사용하여 서명 (S1, S2)를 생성합니다.
- 서명 검증: verify() 함수는 주어진 메시지와 서명을 검증하여 서명이 올바른지 확인합니다.
깃허브