Skip to content
Snippets Groups Projects
Commit ecd47386 authored by Tortue95's avatar Tortue95 Committed by GitHub
Browse files

Merge pull request #45 from Tortue95/auth_ewif

add Auth Encrypted WIF feature
parents 0ec5fc58 d130dc24
No related branches found
No related tags found
No related merge requests found
......@@ -15,6 +15,7 @@ Silkaj is based on Python dependencies:
- [Commandlines](https://github.com/chrissimpkins/commandlines): to parse command and sub-commands.
- [PyNaCl](https://github.com/pyca/pynacl/): Cryptography (NaCl) library.
- [scrypt](https://bitbucket.org/mhallin/py-scrypt): scrypt key derivation function.
- [pyaes](https://github.com/ricmoo/pyaes): Pure-Python implementation of AES
#### From pip
```bash
......
......@@ -3,3 +3,4 @@ ipaddress
tabulate
pynacl
scrypt
pyaes
from tools import *
import nacl.encoding
import nacl.signing
import nacl.hash
import scrypt
import pyaes
import getpass
import os
......@@ -24,7 +29,8 @@ def generate_auth_file(c):
seed = auth_method(c)
with open(file, "w") as f:
f.write(seed)
print("Authfile generated for the public key: ", get_publickey_from_seed(seed))
print("Authfile generated for the public key: ",
get_publickey_from_seed(seed))
def auth_by_auth_file(c):
......@@ -56,6 +62,7 @@ def auth_by_seed():
def auth_by_scrypt(c):
salt = input("Please enter your Scrypt Salt (Secret identifier): ")
password = getpass.getpass("Please enter your Scrypt password (masked): ")
if c.contains_definitions('n') and c.contains_definitions('r') and c.contains_definitions('p'):
n, r, p = c.get_definition('n'), c.get_definition('r'), c.get_definition('p')
if n.isnumeric() and r.isnumeric() and p.isnumeric():
......@@ -75,6 +82,120 @@ def auth_by_scrypt(c):
def auth_by_wif():
wif = input("Please enter your WIF address: ")
seed = get_seed_from_wif(wif)
return seed
wif = input("Please enter your WIF or Encrypted WIF address: ")
regex = re.compile('^[1-9A-HJ-NP-Za-km-z]*$')
if not re.search(regex, wif):
print("Error: the format of WIF is invalid")
exit(1)
wif_bytes = b58_decode(wif)
fi = wif_bytes[0:1]
if fi == b'\x01':
return get_seed_from_wifv1(wif)
elif fi == b'\x02':
password = getpass.getpass("Please enter the " +
"password of WIF (masked): ")
return get_seed_from_ewifv1(wif, password)
print("Error: the format of WIF is invalid or unknown")
exit(1)
def get_seed_from_scrypt(salt, password, N=4096, r=16, p=1):
seed = scrypt.hash(password, salt, N, r, p, 32)
seedhex = nacl.encoding.HexEncoder.encode(seed).decode("utf-8")
return seedhex
def get_seed_from_wifv1(wif):
regex = re.compile('^[1-9A-HJ-NP-Za-km-z]*$')
if not re.search(regex, wif):
print("Error: the format of WIF is invalid")
exit(1)
wif_bytes = b58_decode(wif)
if len(wif_bytes) != 35:
print("Error: the size of WIF is invalid")
exit(1)
checksum_from_wif = wif_bytes[-2:]
fi = wif_bytes[0:1]
seed = wif_bytes[1:-2]
seed_fi = wif_bytes[0:-2]
if fi != b'\x01':
print("Error: It's not a WIF format")
exit(1)
# checksum control
checksum = nacl.hash.sha256(
nacl.hash.sha256(seed_fi, nacl.encoding.RawEncoder),
nacl.encoding.RawEncoder)[0:2]
if checksum_from_wif != checksum:
print("Error: bad checksum of the WIF")
exit(1)
seedhex = nacl.encoding.HexEncoder.encode(seed).decode("utf-8")
return seedhex
def get_seed_from_ewifv1(ewif, password):
regex = re.compile('^[1-9A-HJ-NP-Za-km-z]*$')
if not re.search(regex, ewif):
print("Error: the format of EWIF is invalid")
exit(1)
wif_bytes = b58_decode(ewif)
if len(wif_bytes) != 39:
print("Error: the size of EWIF is invalid")
exit(1)
wif_no_checksum = wif_bytes[0:-2]
checksum_from_ewif = wif_bytes[-2:]
fi = wif_bytes[0:1]
salt = wif_bytes[1:5]
encryptedhalf1 = wif_bytes[5:21]
encryptedhalf2 = wif_bytes[21:37]
if fi != b'\x02':
print("Error: It's not a EWIF format")
exit(1)
# Checksum Control
checksum = nacl.hash.sha256(
nacl.hash.sha256(wif_no_checksum, nacl.encoding.RawEncoder),
nacl.encoding.RawEncoder)[0:2]
if checksum_from_ewif != checksum:
print("Error: bad checksum of EWIF address")
exit(1)
# SCRYPT
password = password.encode("utf-8")
scrypt_seed = scrypt.hash(password, salt, 16384, 8, 8, 64)
derivedhalf1 = scrypt_seed[0:32]
derivedhalf2 = scrypt_seed[32:64]
# AES
aes = pyaes.AESModeOfOperationECB(derivedhalf2)
decryptedhalf1 = aes.decrypt(encryptedhalf1)
decryptedhalf2 = aes.decrypt(encryptedhalf2)
# XOR
seed1 = xor_bytes(decryptedhalf1, derivedhalf1[0:16])
seed2 = xor_bytes(decryptedhalf2, derivedhalf1[16:32])
seed = seed1+seed2
seedhex = nacl.encoding.HexEncoder.encode(seed).decode("utf-8")
# Password Control
salt_from_seed = nacl.hash.sha256(
nacl.hash.sha256(
b58_decode(get_publickey_from_seed(seedhex)),
nacl.encoding.RawEncoder),
nacl.encoding.RawEncoder)[0:4]
if salt_from_seed != salt:
print("Error: bad Password of EWIF address")
exit(1)
return seedhex
......@@ -2,9 +2,7 @@ import datetime
import nacl.encoding
import nacl.signing
import nacl.hash
import scrypt
import re
import sys
from network_tools import *
from constants import *
......@@ -46,48 +44,12 @@ def get_current_block(ep):
return request(ep, "blockchain/current")
def get_seed_from_scrypt(salt, password, N=4096, r=16, p=1):
seed = scrypt.hash(password, salt, N, r, p, 32)
seedhex = nacl.encoding.HexEncoder.encode(seed).decode("utf-8")
return seedhex
def get_seed_from_wif(wif):
regex = re.compile('^[1-9A-HJ-NP-Za-km-z]*$')
if not re.search(regex, wif):
print("Error: the format of WIF is invalid")
exit(1)
wif_bytes = b58_decode(wif)
if len(wif_bytes) != 35:
print("Error: the size of WIF is invalid")
exit(1)
checksum_from_wif = wif_bytes[-2:]
fi = wif_bytes[0:1]
seed = wif_bytes[1:-2]
seed_fi = wif_bytes[0:-2]
if fi != b'\x01':
print("Error: It's not a WIF format")
exit(1)
#checksum control
checksum = nacl.hash.sha256(nacl.hash.sha256(seed_fi, nacl.encoding.RawEncoder),nacl.encoding.RawEncoder)[0:2]
if checksum_from_wif != checksum:
print("Error: bad checksum of the WIF")
exit(1)
seedhex = nacl.encoding.HexEncoder.encode(seed).decode("utf-8")
return seedhex
def sign_document_from_seed(document, seed):
seed = bytes(seed, 'utf-8')
signing_key = nacl.signing.SigningKey(seed, nacl.encoding.HexEncoder)
signed = signing_key.sign(bytes(document, 'utf-8'))
signed_b64 = nacl.encoding.Base64Encoder.encode(signed.signature).decode("utf-8")
return signed_b64
signed_b64 = nacl.encoding.Base64Encoder.encode(signed.signature)
return signed_b64.decode("utf-8")
def get_publickey_from_seed(seed):
......@@ -99,13 +61,16 @@ def get_publickey_from_seed(seed):
def check_public_key(pubkey):
regex = re.compile('^[1-9A-HJ-NP-Za-km-z]{43,44}$')
regex_checksum = re.compile('^[1-9A-HJ-NP-Za-km-z]{43,44}:[1-9A-HJ-NP-Za-km-z]{3}$')
regex_checksum = re.compile('^[1-9A-HJ-NP-Za-km-z]{43,44}' +
':[1-9A-HJ-NP-Za-km-z]{3}$')
if re.search(regex, pubkey):
return pubkey
if re.search(regex_checksum, pubkey):
pubkey, checksum = pubkey.split(":")
pubkey_byte = b58_decode(pubkey)
checksum_calculed = b58_encode(nacl.hash.sha256(nacl.hash.sha256(pubkey_byte, nacl.encoding.RawEncoder), nacl.encoding.RawEncoder))[:3]
checksum_calculed = b58_encode(nacl.hash.sha256(
nacl.hash.sha256(pubkey_byte, nacl.encoding.RawEncoder),
nacl.encoding.RawEncoder))[:3]
if checksum_calculed == checksum:
return pubkey
else:
......@@ -123,7 +88,11 @@ def get_amount_from_pubkey(ep, pubkey):
amount = 0
for source in sources:
amount += source["amount"] * 10 ** source["base"]
listinput.append(str(source["amount"]) + ":" + str(source["base"]) + ":" + str(source["type"]) + ":" + str(source["identifier"]) + ":" + str(source["noffset"]))
listinput.append(str(source["amount"]) + ":" +
str(source["base"]) + ":" +
str(source["type"]) + ":" +
str(source["identifier"]) + ":" +
str(source["noffset"]))
# pending source
history = request(ep, "tx/history/" + pubkey + "/pending")["history"]
......@@ -144,7 +113,11 @@ def get_amount_from_pubkey(ep, pubkey):
for output in pending["outputs"]:
outputsplited = output.split(":")
if outputsplited[2] == "SIG(" + pubkey + ")":
inputgenerated = str(outputsplited[0]) + ":" + str(outputsplited[1]) + ":T:" + identifier + ":" + str(i)
inputgenerated = (
str(outputsplited[0]) + ":" +
str(outputsplited[1]) + ":T:" +
identifier + ":" + str(i)
)
if inputgenerated not in listinput:
listinput.append(inputgenerated)
i += 1
......@@ -190,10 +163,7 @@ def b58_encode(b):
res = ''.join(res[::-1])
# Encode leading zeros as base58 zeros
czero = b'\x00'
if sys.version > '3':
# In Python3 indexing a bytes returns numbers, not characters.
czero = 0
czero = 0
pad = 0
for c in b:
if c == czero:
......@@ -212,7 +182,8 @@ def b58_decode(s):
for c in s:
n *= 58
if c not in b58_digits:
raise InvalidBase58Error('Character %r is not a valid base58 character' % c)
raise InvalidBase58Error('Character %r is not a ' +
'valid base58 character' % c)
digit = b58_digits.index(c)
n += digit
......@@ -230,3 +201,10 @@ def b58_decode(s):
else:
break
return b'\x00' * pad + res
def xor_bytes(b1, b2):
result = bytearray()
for b1, b2 in zip(b1, b2):
result.append(b1 ^ b2)
return result
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment