-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwallet.py
123 lines (106 loc) · 6.08 KB
/
wallet.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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
"""
Elliptic Curve Cryptography (ECC) with Hazmat EC Key Generation primitives within the crytogrpahy library
Digital Signature Algorithm (DSA and ECDSA) A variant of the ElGamal signature, specified in FIPS PUB 186-4.
It is based on the discrete logarithm problem in a prime finite field (DSA) or in an elliptic curve field (ECDSA).
[15] https://asecuritysite.com/encryption/hashnew9 RSA has been around for over 40 years, and it is struggling in places.
In terms of key sizes, we are now at 2,048-bit keys and above.
For a lightweight device, we will struggle to perform these sizes of operations.
And so Elliptic Curve Cryptography (ECC) has come to our rescue, and where we use typical key sizes of just 256 bits.
In fact, Bitcoin and Ethereum, and most blockchain methods use ECC for their keys.
"""
from Crypto.Hash import SHA256
from Crypto.Hash import SHA3_256
import binascii # Converts binary to ascii and the other way around
from Crypto.PublicKey import ECC
from Crypto.Signature import DSS
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import utils
from cryptography import exceptions
import binascii
import sys
class Wallet:
def __init__(self, node_id):
self.private_key = None
self.public_key = None
self.node_id = node_id
def create_keys(self):
private_key, public_key = self.generate_keys()
self.private_key = private_key
self.public_key = public_key
def save_keys(self):
if self.public_key is not None and self.private_key is not None:
try:
with open('wallet-{}.txt'.format(self.node_id), mode='w') as f:
f.write(self.public_key)
f.write('\n')
f.write(self.private_key)
return True
except (IOError, IndexError):
print('ERROR: save_keys Saving wallet file failed.')
return False
def load_keys(self):
try:
with open('wallet-{}.txt'.format(self.node_id), mode='r') as f:
keys = f.readlines()
public_key = keys[0][:-1] # -1 because the character \n when we write the file wallet.txt above
private_key = keys[1]
self.public_key = public_key
self.private_key = private_key
return True
except (IOError, IndexError):
print('ERROR: load_keys Loading wallet file failed.')
return False
def generate_keys(self):
private_key = ec.generate_private_key(ec.SECP256R1())
vals = private_key.private_numbers()
no_bits=vals.private_value.bit_length()
print (f"Private key value: {vals.private_value}. Number of bits {no_bits}")
public_key = private_key.public_key()
vals=public_key.public_numbers()
enc_point=binascii.b2a_hex(vals.encode_point()).decode()
print (f"\nPublic key encoded point: {enc_point} \nx={enc_point[2:(len(enc_point)-2)//2+2]} \ny={enc_point[(len(enc_point)-2)//2+2:]}")
pem = private_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.PKCS8,encryption_algorithm=serialization.NoEncryption())
der = private_key.private_bytes(encoding=serialization.Encoding.DER,format=serialization.PrivateFormat.PKCS8,encryption_algorithm=serialization.NoEncryption())
print ("\nPrivate key (PEM):\n",pem.decode())
print ("Private key (DER):\n",binascii.b2a_hex(der))
pem1 = public_key.public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo)
der1 = public_key.public_bytes(encoding=serialization.Encoding.DER,format=serialization.PublicFormat.SubjectPublicKeyInfo)
print ("\nPublic key (PEM):\n",pem1.decode())
print ("Public key (DER):\n",binascii.b2a_hex(der1))
#private_key = ECC.generate(curve='P-256')
#private_key = ec.generate_private_key(ec.SECP256K1())
#return (binascii.hexlify(private_key.export_key(format='DER')).decode('ascii'), binascii.hexlify(public_key.export_key(format='DER')).decode('ascii'))
private_key = pem
public_key = pem1
return ((private_key).decode(), (public_key).decode())
#return (binascii.b2a_hex(private_key.export_key(format='DER')).decode('ascii'), binascii.b2a_hex(public_key.export_key(format='DER')).decode('ascii'))
def sign_transaction(self, sender, recipient, amount):
h = SHA3_256.new((str(sender) + str(recipient) + str(amount)).encode('utf8'))
signature = DSS.new(ECC.import_key(self.private_key), 'fips-186-3').sign(h)
#return binascii.hexlify(signature).decode('ascii')
print('\nsignature: {}\n'.format(signature.hex()))
#return signature.hex()
#print(binascii.hexlify(signature).decode())
return binascii.hexlify(signature).decode()
'''
Raises: ValueError – if the signature is not authentic
and it always return False if it is successful.
So rather than checking the return value, you need to check if the method raises an exception.
'''
@staticmethod
def verify_transaction(transaction):
# If is MINING sender, we don't have to validate, because MINING does't have a valid signature.
public_key = ECC.import_key(transaction.sender)
#verifier = DSS.new(public_key, 'fips-186-3')
h = SHA3_256.new((str(transaction.sender) + str(transaction.recipient) + str(transaction.amount)).encode('utf8'))
verifier = DSS.new(public_key, 'fips-186-3')
try:
verifier.verify(h, binascii.unhexlify(transaction.signature))
print ("The message is authentic.")
except ValueError:
print ("The message is not authentic.")
#return (verifier.verify(h, binascii.unhexlify(transaction.signature)))
return (binascii.unhexlify(transaction.signature))