/
signature.py
96 lines (74 loc) · 2.63 KB
/
signature.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import Cryptodome.PublicKey.ECC as ECC
import Cryptodome.Signature.DSS as DSS
from Cryptodome.Hash import SHA256
from base64 import urlsafe_b64encode
CURVE = "P-256"
"""
La curva utilizada para las firmas.
.. warning:: Esta curva no se considera segura pero es la única que
implementa la librería utilizada.
"""
MODE = "fips-186-3"
FORMAT = "DER"
def generate_signature():
"""
Genera una clave ECDSA.
:return: Una clave ECDSA.
"""
return ECC.generate(curve=CURVE)
def sign(key, msg):
"""
Firma un mensaje digitalmente con una clave privada.
:param key: Una clave privada.
:param msg: Un mensaje a firmar.
:return: La firma digital del mensaje.
:raise ValueError: Si la clave no tiene componente privada.
"""
if not key.has_private():
raise ValueError("La firma digital no tiene componente privada")
msg_hash = SHA256.new(msg)
dss = DSS.new(key=key, mode=MODE)
return dss.sign(msg_hash)
def verify(key, signature, msg):
"""
Verifica la validez de la firma sobre un mensaje.
:param key: Una clave del par público-privado que pueda verificar
la firma.
:param signature: La firma digital.
:param msg: El mensaje firmado.
:return: `True` si la firma es válida, `False` en cualquier otro caso.
"""
try:
dss = DSS.new(key=key, mode=MODE)
dss.verify(signature=signature, msg_hash=SHA256.new(msg))
return True
except ValueError:
return False
def address(key):
"""
Devuelve una firma digital apropiada para ser usada en una papeleta.
Es el resultado de firmar el hash de la clave pública de la clave
privada correspondiente.
El nombre *address* viene de la similitud de este mecanismo con el
utilizado por Bitcoin para generar direcciones para las
transacciones.
:param key: La clave con componente privada.
:returns: La firma digital del hash de la clave pública
correspondiente (la dirección, *address*).
"""
return sign(key, key.public_key().export_key(format="DER"))
def is_valid_signature(signature, signature_list):
"""
Dada una firma digital presente en una papeleta, permite
contrastarla con la lista de votantes para saber si la
firma es válida.
:param signature: La firma digital.
:param signature_list: La lista de claves públicas de los votantes
:returns: `True` si la firma es válida, `False` en cualquier otro
caso.
"""
hashes = [sig.export_key(format="DER") for sig in signature_list]
for pk, h in zip(signature_list, hashes):
if verify(pk, signature, h):
return True
return False