progress in removing core
parent
e12781a49d
commit
e1676ef168
|
@ -41,7 +41,6 @@ class PrivateAPI:
|
|||
self.config = config
|
||||
self.debug = debug
|
||||
self.startTime = epoch.get_epoch()
|
||||
self._crypto = onionrInst.onionrCrypto
|
||||
app = flask.Flask(__name__)
|
||||
bindPort = int(config.get('client.client.port', 59496))
|
||||
self.bindPort = bindPort
|
||||
|
|
|
@ -34,7 +34,7 @@ class PublicAPI:
|
|||
self.i2pEnabled = config.get('i2p.host', False)
|
||||
self.hideBlocks = [] # Blocks to be denied sharing
|
||||
self.host = apiutils.setbindip.set_bind_IP(filepaths.public_API_host_file)
|
||||
self.torAdder = gettransports.get_transports[0]
|
||||
self.torAdder = gettransports.transports[0]
|
||||
self.bindPort = config.get('client.public.port')
|
||||
self.lastRequest = 0
|
||||
self.hitCount = 0 # total rec requests to public api since server started
|
||||
|
|
351
onionr/core.py
351
onionr/core.py
|
@ -1,351 +0,0 @@
|
|||
'''
|
||||
Onionr - Private P2P Communication
|
||||
|
||||
Core Onionr library, useful for external programs. Handles peer & data processing
|
||||
'''
|
||||
'''
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
'''
|
||||
import os, sys, json
|
||||
import logger, netcontroller, config
|
||||
from onionrblockapi import Block
|
||||
import coredb
|
||||
import deadsimplekv as simplekv
|
||||
import onionrcrypto, onionrproofs, onionrevents as events, onionrexceptions
|
||||
import onionrblacklist
|
||||
from onionrusers import onionrusers
|
||||
from onionrstorage import removeblock, setdata
|
||||
import dbcreator, onionrstorage, serializeddata, subprocesspow
|
||||
from etc import onionrvalues, powchoice
|
||||
from onionrutils import localcommand, stringvalidators, bytesconverter, epoch
|
||||
from onionrutils import blockmetadata
|
||||
from utils import identifyhome
|
||||
import storagecounter
|
||||
|
||||
class Core:
|
||||
def __init__(self, torPort=0):
|
||||
'''
|
||||
Initialize Core Onionr library
|
||||
'''
|
||||
# set data dir
|
||||
self.dataDir = identifyhome.identify_home()
|
||||
|
||||
self.usageFile = self.dataDir + 'disk-usage.txt'
|
||||
self.config = config
|
||||
self.maxBlockSize = 10000000 # max block size in bytes
|
||||
|
||||
self.onionrInst = None
|
||||
self.hsAddress = ''
|
||||
self.i2pAddress = config.get('i2p.own_addr', None)
|
||||
self.bootstrapFileLocation = 'static-data/bootstrap-nodes.txt'
|
||||
self.bootstrapList = []
|
||||
self.requirements = onionrvalues.OnionrValues()
|
||||
self.torPort = torPort
|
||||
self.dataNonceFile = self.dataDir + 'block-nonces.dat'
|
||||
self.forwardKeysFile = self.dataDir + 'forward-keys.db'
|
||||
self.keyStore = simplekv.DeadSimpleKV(self.dataDir + 'cachedstorage.dat', refresh_seconds=5)
|
||||
self.storage_counter = storagecounter.StorageCounter(self)
|
||||
|
||||
# Socket data, defined here because of multithreading constraints with gevent
|
||||
self.killSockets = False
|
||||
self.startSocket = {}
|
||||
self.socketServerConnData = {}
|
||||
self.socketReasons = {}
|
||||
self.socketServerResponseData = {}
|
||||
|
||||
if os.path.exists(self.dataDir + '/hs/hostname'):
|
||||
with open(self.dataDir + '/hs/hostname', 'r') as hs:
|
||||
self.hsAddress = hs.read().strip()
|
||||
|
||||
# Load bootstrap address list
|
||||
if os.path.exists(self.bootstrapFileLocation):
|
||||
with open(self.bootstrapFileLocation, 'r') as bootstrap:
|
||||
bootstrap = bootstrap.read()
|
||||
for i in bootstrap.split('\n'):
|
||||
self.bootstrapList.append(i)
|
||||
else:
|
||||
logger.warn('Warning: address bootstrap file not found ' + self.bootstrapFileLocation)
|
||||
|
||||
self.use_subprocess = powchoice.use_subprocess(self)
|
||||
# Initialize the crypto object
|
||||
self._crypto = onionrcrypto.OnionrCrypto(self)
|
||||
self._blacklist = onionrblacklist.OnionrBlackList(self)
|
||||
self.serializer = serializeddata.SerializedData(self)
|
||||
|
||||
def addPeer(self, peerID, name=''):
|
||||
'''
|
||||
Adds a public key to the key database (misleading function name)
|
||||
'''
|
||||
return coredb.keydb.addkeys.add_peer(self, peerID, name)
|
||||
|
||||
def addAddress(self, address):
|
||||
'''
|
||||
Add an address to the address database (only tor currently)
|
||||
'''
|
||||
return coredb.keydb.addkeys.add_address(self, address)
|
||||
|
||||
def removeAddress(self, address):
|
||||
'''
|
||||
Remove an address from the address database
|
||||
'''
|
||||
return coredb.keydb.removekeys.remove_address(self, address)
|
||||
|
||||
def removeBlock(self, block):
|
||||
'''
|
||||
remove a block from this node (does not automatically blacklist)
|
||||
|
||||
**You may want blacklist.addToDB(blockHash)
|
||||
'''
|
||||
removeblock.remove_block(self, block)
|
||||
|
||||
def createAddressDB(self):
|
||||
'''
|
||||
Generate the address database
|
||||
'''
|
||||
self.dbCreate.createAddressDB()
|
||||
|
||||
def createPeerDB(self):
|
||||
'''
|
||||
Generate the peer sqlite3 database and populate it with the peers table.
|
||||
'''
|
||||
self.dbCreate.createPeerDB()
|
||||
|
||||
def createBlockDB(self):
|
||||
'''
|
||||
Create a database for blocks
|
||||
'''
|
||||
self.dbCreate.createBlockDB()
|
||||
|
||||
def setData(self, data):
|
||||
'''
|
||||
Set the data assciated with a hash
|
||||
'''
|
||||
return onionrstorage.setdata.set_data(self, data)
|
||||
|
||||
def getData(self, hash):
|
||||
'''
|
||||
Simply return the data associated to a hash
|
||||
'''
|
||||
return onionrstorage.getData(self, hash)
|
||||
|
||||
def listAdders(self, randomOrder=True, i2p=True, recent=0):
|
||||
'''
|
||||
Return a list of addresses
|
||||
'''
|
||||
return coredb.keydb.listkeys.list_adders(self, randomOrder, i2p, recent)
|
||||
|
||||
def listPeers(self, randomOrder=True, getPow=False, trust=0):
|
||||
'''
|
||||
Return a list of public keys (misleading function name)
|
||||
|
||||
randomOrder determines if the list should be in a random order
|
||||
trust sets the minimum trust to list
|
||||
'''
|
||||
return coredb.keydb.listkeys.list_peers(self, randomOrder, getPow, trust)
|
||||
|
||||
def getPeerInfo(self, peer, info):
|
||||
'''
|
||||
Get info about a peer from their database entry
|
||||
|
||||
id text 0
|
||||
name text, 1
|
||||
adders text, 2
|
||||
dateSeen not null, 3
|
||||
trust int 4
|
||||
hashID text 5
|
||||
'''
|
||||
return coredb.keydb.userinfo.get_user_info(self, peer, info)
|
||||
|
||||
def setPeerInfo(self, peer, key, data):
|
||||
'''
|
||||
Update a peer for a key
|
||||
'''
|
||||
return coredb.keydb.userinfo.set_peer_info(self, peer, key, data)
|
||||
|
||||
def getAddressInfo(self, address, info):
|
||||
'''
|
||||
Get info about an address from its database entry
|
||||
|
||||
address text, 0
|
||||
type int, 1
|
||||
knownPeer text, 2
|
||||
speed int, 3
|
||||
success int, 4
|
||||
powValue 5
|
||||
failure int 6
|
||||
lastConnect 7
|
||||
trust 8
|
||||
introduced 9
|
||||
'''
|
||||
return coredb.keydb.transportinfo.get_address_info(self, address, info)
|
||||
|
||||
def setAddressInfo(self, address, key, data):
|
||||
'''
|
||||
Update an address for a key
|
||||
'''
|
||||
return coredb.keydb.transportinfo.set_address_info(self, address, key, data)
|
||||
|
||||
def insertBlock(self, data, header='txt', sign=False, encryptType='', symKey='', asymPeer='', meta = {}, expire=None, disableForward=False):
|
||||
'''
|
||||
Inserts a block into the network
|
||||
encryptType must be specified to encrypt a block
|
||||
'''
|
||||
allocationReachedMessage = 'Cannot insert block, disk allocation reached.'
|
||||
if self.storage_counter.isFull():
|
||||
logger.error(allocationReachedMessage)
|
||||
return False
|
||||
retData = False
|
||||
|
||||
if type(data) is None:
|
||||
raise ValueError('Data cannot be none')
|
||||
|
||||
createTime = epoch.get_epoch()
|
||||
|
||||
dataNonce = bytesconverter.bytes_to_str(self._crypto.sha3Hash(data))
|
||||
try:
|
||||
with open(self.dataNonceFile, 'r') as nonces:
|
||||
if dataNonce in nonces:
|
||||
return retData
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
# record nonce
|
||||
with open(self.dataNonceFile, 'a') as nonceFile:
|
||||
nonceFile.write(dataNonce + '\n')
|
||||
|
||||
if type(data) is bytes:
|
||||
data = data.decode()
|
||||
data = str(data)
|
||||
plaintext = data
|
||||
plaintextMeta = {}
|
||||
plaintextPeer = asymPeer
|
||||
|
||||
retData = ''
|
||||
signature = ''
|
||||
signer = ''
|
||||
metadata = {}
|
||||
# metadata is full block metadata, meta is internal, user specified metadata
|
||||
|
||||
# only use header if not set in provided meta
|
||||
|
||||
meta['type'] = str(header)
|
||||
|
||||
if encryptType in ('asym', 'sym', ''):
|
||||
metadata['encryptType'] = encryptType
|
||||
else:
|
||||
raise onionrexceptions.InvalidMetadata('encryptType must be asym or sym, or blank')
|
||||
|
||||
try:
|
||||
data = data.encode()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if encryptType == 'asym':
|
||||
meta['rply'] = createTime # Duplicate the time in encrypted messages to prevent replays
|
||||
if not disableForward and sign and asymPeer != self._crypto.pubKey:
|
||||
try:
|
||||
forwardEncrypted = onionrusers.OnionrUser(self, asymPeer).forwardEncrypt(data)
|
||||
data = forwardEncrypted[0]
|
||||
meta['forwardEnc'] = True
|
||||
expire = forwardEncrypted[2] # Expire time of key. no sense keeping block after that
|
||||
except onionrexceptions.InvalidPubkey:
|
||||
pass
|
||||
#onionrusers.OnionrUser(self, asymPeer).generateForwardKey()
|
||||
fsKey = onionrusers.OnionrUser(self, asymPeer).generateForwardKey()
|
||||
#fsKey = onionrusers.OnionrUser(self, asymPeer).getGeneratedForwardKeys().reverse()
|
||||
meta['newFSKey'] = fsKey
|
||||
jsonMeta = json.dumps(meta)
|
||||
plaintextMeta = jsonMeta
|
||||
if sign:
|
||||
signature = self._crypto.edSign(jsonMeta.encode() + data, key=self._crypto.privKey, encodeResult=True)
|
||||
signer = self._crypto.pubKey
|
||||
|
||||
if len(jsonMeta) > 1000:
|
||||
raise onionrexceptions.InvalidMetadata('meta in json encoded form must not exceed 1000 bytes')
|
||||
|
||||
user = onionrusers.OnionrUser(self, symKey)
|
||||
|
||||
# encrypt block metadata/sig/content
|
||||
if encryptType == 'sym':
|
||||
|
||||
if len(symKey) < self.requirements.passwordLength:
|
||||
raise onionrexceptions.SecurityError('Weak encryption key')
|
||||
jsonMeta = self._crypto.symmetricEncrypt(jsonMeta, key=symKey, returnEncoded=True).decode()
|
||||
data = self._crypto.symmetricEncrypt(data, key=symKey, returnEncoded=True).decode()
|
||||
signature = self._crypto.symmetricEncrypt(signature, key=symKey, returnEncoded=True).decode()
|
||||
signer = self._crypto.symmetricEncrypt(signer, key=symKey, returnEncoded=True).decode()
|
||||
elif encryptType == 'asym':
|
||||
if stringvalidators.validate_pub_key(asymPeer):
|
||||
# Encrypt block data with forward secrecy key first, but not meta
|
||||
jsonMeta = json.dumps(meta)
|
||||
jsonMeta = self._crypto.pubKeyEncrypt(jsonMeta, asymPeer, encodedData=True).decode()
|
||||
data = self._crypto.pubKeyEncrypt(data, asymPeer, encodedData=True).decode()
|
||||
signature = self._crypto.pubKeyEncrypt(signature, asymPeer, encodedData=True).decode()
|
||||
signer = self._crypto.pubKeyEncrypt(signer, asymPeer, encodedData=True).decode()
|
||||
try:
|
||||
onionrusers.OnionrUser(self, asymPeer, saveUser=True)
|
||||
except ValueError:
|
||||
# if peer is already known
|
||||
pass
|
||||
else:
|
||||
raise onionrexceptions.InvalidPubkey(asymPeer + ' is not a valid base32 encoded ed25519 key')
|
||||
|
||||
# compile metadata
|
||||
metadata['meta'] = jsonMeta
|
||||
metadata['sig'] = signature
|
||||
metadata['signer'] = signer
|
||||
metadata['time'] = createTime
|
||||
|
||||
# ensure expire is integer and of sane length
|
||||
if type(expire) is not type(None):
|
||||
assert len(str(int(expire))) < 14
|
||||
metadata['expire'] = expire
|
||||
|
||||
# send block data (and metadata) to POW module to get tokenized block data
|
||||
if self.use_subprocess:
|
||||
payload = subprocesspow.SubprocessPOW(data, metadata, self).start()
|
||||
else:
|
||||
payload = onionrproofs.POW(metadata, data).waitForResult()
|
||||
if payload != False:
|
||||
try:
|
||||
retData = self.setData(payload)
|
||||
except onionrexceptions.DiskAllocationReached:
|
||||
logger.error(allocationReachedMessage)
|
||||
retData = False
|
||||
else:
|
||||
# Tell the api server through localCommand to wait for the daemon to upload this block to make statistical analysis more difficult
|
||||
if localcommand.local_command(self, '/ping', maxWait=10) == 'pong!':
|
||||
if self.config.get('general.security_level', 1) == 0:
|
||||
localcommand.local_command(self, '/waitforshare/' + retData, post=True, maxWait=5)
|
||||
coredb.daemonqueue.daemon_queue_add('uploadBlock', retData)
|
||||
else:
|
||||
pass
|
||||
coredb.blockmetadb.add_to_block_DB(retData, selfInsert=True, dataSaved=True)
|
||||
coredb.blockmetadata.process_block_metadata(self, retData)
|
||||
|
||||
if retData != False:
|
||||
if plaintextPeer == onionrvalues.DENIABLE_PEER_ADDRESS:
|
||||
events.event('insertdeniable', {'content': plaintext, 'meta': plaintextMeta, 'hash': retData, 'peer': bytesconverter.bytes_to_str(asymPeer)}, onionr = self.onionrInst, threaded = True)
|
||||
else:
|
||||
events.event('insertblock', {'content': plaintext, 'meta': plaintextMeta, 'hash': retData, 'peer': bytesconverter.bytes_to_str(asymPeer)}, onionr = self.onionrInst, threaded = True)
|
||||
return retData
|
||||
|
||||
def introduceNode(self):
|
||||
'''
|
||||
Introduces our node into the network by telling X many nodes our HS address
|
||||
'''
|
||||
if localcommand.local_command(self, '/ping', maxWait=10) == 'pong!':
|
||||
coredb.daemonqueue.daemon_queue_add('announceNode')
|
||||
logger.info('Introduction command will be processed.', terminal=True)
|
||||
else:
|
||||
logger.warn('No running node detected. Cannot introduce.', terminal=True)
|
|
@ -2,8 +2,8 @@ import json
|
|||
import onionrblockapi
|
||||
from onionrutils import bytesconverter, stringvalidators
|
||||
class GetBlockData:
|
||||
def __init__(self, client_api_inst):
|
||||
self.client_api_inst = client_api_inst
|
||||
def __init__(self, client_api_inst=None):
|
||||
return
|
||||
|
||||
def get_block_data(self, bHash, decrypt=False, raw=False, headerOnly=False):
|
||||
assert stringvalidators.validate_hash(bHash)
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
'''
|
||||
from flask import Blueprint, Response, abort
|
||||
import onionrblockapi
|
||||
from httpapi import apiutils
|
||||
from .. import apiutils
|
||||
from onionrutils import stringvalidators
|
||||
from coredb import blockmetadb
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ HiddenServicePort 80 ''' + self.apiServerIP + ''':''' + str(self.hsPort)
|
|||
logger.fatal('Failed to start Tor. Maybe a stray instance of Tor used by Onionr is still running? This can also be a result of file permissions being too open', terminal=True)
|
||||
return False
|
||||
except KeyboardInterrupt:
|
||||
logger.fatal('Got keyboard interrupt. Onionr will exit soon.', timestamp = False, level = logger.LEVEL_IMPORTANT, terminal=True)
|
||||
logger.fatal('Got keyboard interrupt. Onionr will exit soon.', timestamp = False, terminal=True)
|
||||
return False
|
||||
|
||||
logger.info('Finished starting Tor.', terminal=True)
|
||||
|
|
|
@ -19,14 +19,14 @@
|
|||
'''
|
||||
|
||||
import logger, config, onionrexceptions, nacl.exceptions
|
||||
import json, os, sys, datetime, base64, onionrstorage, onionrcrypto
|
||||
import json, os, sys, datetime, base64, onionrstorage
|
||||
from onionrusers import onionrusers
|
||||
from onionrutils import stringvalidators, epoch
|
||||
from coredb import blockmetadb
|
||||
from onionrstorage import removeblock
|
||||
import onionrblocks
|
||||
from onionrcrypto import encryption, cryptoutils as cryptoutils, signing
|
||||
class Block:
|
||||
crypto = onionrcrypto.OnionrCrypto()
|
||||
blockCacheOrder = list() # NEVER write your own code that writes to this!
|
||||
blockCache = dict() # should never be accessed directly, look at Block.getCache()
|
||||
|
||||
|
@ -71,23 +71,23 @@ class Block:
|
|||
# decrypt data
|
||||
if self.getHeader('encryptType') == 'asym':
|
||||
try:
|
||||
self.bcontent = crypto.pubKeyDecrypt(self.bcontent, encodedData=encodedData)
|
||||
bmeta = crypto.pubKeyDecrypt(self.bmetadata, encodedData=encodedData)
|
||||
self.bcontent = encryption.pub_key_decrypt(self.bcontent, encodedData=encodedData)
|
||||
bmeta = encryption.pub_key_decrypt(self.bmetadata, encodedData=encodedData)
|
||||
try:
|
||||
bmeta = bmeta.decode()
|
||||
except AttributeError:
|
||||
# yet another bytes fix
|
||||
pass
|
||||
self.bmetadata = json.loads(bmeta)
|
||||
self.signature = crypto.pubKeyDecrypt(self.signature, encodedData=encodedData)
|
||||
self.signer = crypto.pubKeyDecrypt(self.signer, encodedData=encodedData)
|
||||
self.signature = encryption.pub_key_decrypt(self.signature, encodedData=encodedData)
|
||||
self.signer = encryption.pub_key_decrypt(self.signer, encodedData=encodedData)
|
||||
self.bheader['signer'] = self.signer.decode()
|
||||
self.signedData = json.dumps(self.bmetadata) + self.bcontent.decode()
|
||||
|
||||
# Check for replay attacks
|
||||
try:
|
||||
if epoch.get_epoch() - blockmetadb.get_block_date(self.hash) > 60:
|
||||
assert self.crypto.replayTimestampValidation(self.bmetadata['rply'])
|
||||
assert cryptoutils.replay_validator(self.bmetadata['rply'])
|
||||
except (AssertionError, KeyError, TypeError) as e:
|
||||
if not self.bypassReplayCheck:
|
||||
# Zero out variables to prevent reading of replays
|
||||
|
@ -124,7 +124,7 @@ class Block:
|
|||
Verify if a block's signature is signed by its claimed signer
|
||||
'''
|
||||
|
||||
if crypto.edVerify(data=self.signedData, key=self.signer, sig=self.signature, encodedData=True):
|
||||
if signing.ed_verify(data=self.signedData, key=self.signer, sig=self.signature, encodedData=True):
|
||||
self.validSig = True
|
||||
else:
|
||||
self.validSig = False
|
||||
|
@ -425,7 +425,7 @@ class Block:
|
|||
if (not self.isSigned()) or (not stringvalidators.validate_pub_key(signer)):
|
||||
return False
|
||||
|
||||
return bool(crypto.edVerify(self.getSignedData(), signer, self.getSignature(), encodedData = encodedData))
|
||||
return bool(signing.ed_verify(self.getSignedData(), signer, self.getSignature(), encodedData = encodedData))
|
||||
except:
|
||||
return False
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ from netcontroller import NetController
|
|||
from onionrutils import localcommand
|
||||
import filepaths
|
||||
from coredb import daemonqueue
|
||||
|
||||
from onionrcrypto import getourkeypair
|
||||
def _proper_shutdown(o_inst):
|
||||
localcommand.local_command('shutdown')
|
||||
sys.exit(1)
|
||||
|
@ -72,7 +72,7 @@ def daemon(o_inst):
|
|||
logger.debug('Started .onion service: %s' % (logger.colors.underline + net.myID))
|
||||
else:
|
||||
logger.debug('.onion service disabled')
|
||||
logger.info('Using public key: %s' % (logger.colors.underline + o_inst._crypto.pubKey[:52]), terminal=True)
|
||||
logger.info('Using public key: %s' % (logger.colors.underline + getourkeypair.get_keypair()[0][:52]), terminal=True)
|
||||
|
||||
try:
|
||||
time.sleep(1)
|
||||
|
|
|
@ -22,6 +22,7 @@ import sys, getpass
|
|||
import logger, onionrexceptions
|
||||
from onionrutils import stringvalidators, bytesconverter
|
||||
from onionrusers import onionrusers, contactmanager
|
||||
from coredb import keydb
|
||||
import unpaddedbase32
|
||||
def add_ID(o_inst):
|
||||
try:
|
||||
|
@ -82,22 +83,22 @@ def friend_command(o_inst):
|
|||
action = action.lower()
|
||||
if action == 'list':
|
||||
# List out peers marked as our friend
|
||||
for friend in contactmanager.ContactManager.list_friends(o_inst.):
|
||||
for friend in contactmanager.ContactManager.list_friends():
|
||||
logger.info(friend.publicKey + ' - ' + friend.get_info('name'), terminal=True)
|
||||
elif action in ('add', 'remove'):
|
||||
try:
|
||||
friend = sys.argv[3]
|
||||
if not stringvalidators.validate_pub_key(friend):
|
||||
raise onionrexceptions.InvalidPubkey('Public key is invalid')
|
||||
if friend not in o_inst..listPeers():
|
||||
if friend not in keydb.listkeys.list_peers():
|
||||
raise onionrexceptions.KeyNotKnown
|
||||
friend = onionrusers.OnionrUser(o_inst., friend)
|
||||
friend = onionrusers.OnionrUser(friend)
|
||||
except IndexError:
|
||||
logger.warn('Friend ID is required.', terminal=True)
|
||||
action = 'error' # set to 'error' so that the finally block does not process anything
|
||||
except onionrexceptions.KeyNotKnown:
|
||||
o_inst..addPeer(friend)
|
||||
friend = onionrusers.OnionrUser(o_inst., friend)
|
||||
o_inst.addPeer(friend)
|
||||
friend = onionrusers.OnionrUser(friend)
|
||||
finally:
|
||||
if action == 'add':
|
||||
friend.setTrust(1)
|
||||
|
|
|
@ -36,7 +36,7 @@ class OnionrCrypto:
|
|||
self.secrets = secrets
|
||||
self.deterministicRequirement = 25 # Min deterministic password/phrase length
|
||||
self.HASH_ID_ROUNDS = 2000
|
||||
self.keyManager = keymanager.KeyManager(self)
|
||||
self.keyManager = keymanager.KeyManager()
|
||||
|
||||
# Load our own pub/priv Ed25519 keys, gen & save them if they don't exist
|
||||
if os.path.exists(self._keyFile):
|
||||
|
@ -52,47 +52,6 @@ class OnionrCrypto:
|
|||
self.keyManager.addKey(self.pubKey, self.privKey)
|
||||
return
|
||||
|
||||
def edVerify(self, data, key, sig, encodedData=True):
|
||||
'''Verify signed data (combined in nacl) to an ed25519 key'''
|
||||
try:
|
||||
key = nacl.signing.VerifyKey(key=key, encoder=nacl.encoding.Base32Encoder)
|
||||
except nacl.exceptions.ValueError:
|
||||
#logger.debug('Signature by unknown key (cannot reverse hash)')
|
||||
return False
|
||||
except binascii.Error:
|
||||
logger.warn('Could not load key for verification, invalid padding')
|
||||
return False
|
||||
retData = False
|
||||
sig = base64.b64decode(sig)
|
||||
try:
|
||||
data = data.encode()
|
||||
except AttributeError:
|
||||
pass
|
||||
if encodedData:
|
||||
try:
|
||||
retData = key.verify(data, sig) # .encode() is not the same as nacl.encoding
|
||||
except nacl.exceptions.BadSignatureError:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
retData = key.verify(data, sig)
|
||||
except nacl.exceptions.BadSignatureError:
|
||||
pass
|
||||
return retData
|
||||
|
||||
def edSign(self, data, key, encodeResult=False):
|
||||
'''Ed25519 sign data'''
|
||||
try:
|
||||
data = data.encode()
|
||||
except AttributeError:
|
||||
pass
|
||||
key = nacl.signing.SigningKey(seed=key, encoder=nacl.encoding.Base32Encoder)
|
||||
retData = ''
|
||||
if encodeResult:
|
||||
retData = key.sign(data, encoder=nacl.encoding.Base64Encoder).signature.decode() # .encode() is not the same as nacl.encoding
|
||||
else:
|
||||
retData = key.sign(data).signature
|
||||
return retData
|
||||
|
||||
def pubKeyEncrypt(self, data, pubkey, encodedData=False):
|
||||
'''Encrypt to a public key (Curve25519, taken from base32 Ed25519 pubkey)'''
|
||||
|
@ -113,25 +72,6 @@ class OnionrCrypto:
|
|||
|
||||
return retVal
|
||||
|
||||
def pubKeyDecrypt(self, data, pubkey='', privkey='', encodedData=False):
|
||||
'''pubkey decrypt (Curve25519, taken from Ed25519 pubkey)'''
|
||||
decrypted = False
|
||||
if encodedData:
|
||||
encoding = nacl.encoding.Base64Encoder
|
||||
else:
|
||||
encoding = nacl.encoding.RawEncoder
|
||||
if privkey == '':
|
||||
privkey = self.privKey
|
||||
ownKey = nacl.signing.SigningKey(seed=privkey, encoder=nacl.encoding.Base32Encoder()).to_curve25519_private_key()
|
||||
|
||||
if stringvalidators.validate_pub_key(privkey):
|
||||
privkey = nacl.signing.SigningKey(seed=privkey, encoder=nacl.encoding.Base32Encoder()).to_curve25519_private_key()
|
||||
anonBox = nacl.public.SealedBox(privkey)
|
||||
else:
|
||||
anonBox = nacl.public.SealedBox(ownKey)
|
||||
decrypted = anonBox.decrypt(data, encoder=encoding)
|
||||
return decrypted
|
||||
|
||||
def symmetricEncrypt(self, data, key, encodedKey=False, returnEncoded=True):
|
||||
'''Encrypt data with a 32-byte key (Salsa20-Poly1305 MAC)'''
|
||||
if encodedKey:
|
||||
|
@ -252,37 +192,3 @@ class OnionrCrypto:
|
|||
logger.debug("Invalid token, bad proof")
|
||||
|
||||
return retData
|
||||
|
||||
@staticmethod
|
||||
def replayTimestampValidation(timestamp):
|
||||
if epoch.get_epoch() - int(timestamp) > 2419200:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def safeCompare(one, two):
|
||||
# Do encode here to avoid spawning core
|
||||
try:
|
||||
one = one.encode()
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
two = two.encode()
|
||||
except AttributeError:
|
||||
pass
|
||||
return hmac.compare_digest(one, two)
|
||||
|
||||
@staticmethod
|
||||
def randomShuffle(theList):
|
||||
myList = list(theList)
|
||||
shuffledList = []
|
||||
myListLength = len(myList) + 1
|
||||
while myListLength > 0:
|
||||
removed = secrets.randbelow(myListLength)
|
||||
try:
|
||||
shuffledList.append(myList.pop(removed))
|
||||
except IndexError:
|
||||
pass
|
||||
myListLength = len(myList)
|
||||
return shuffledList
|
|
@ -0,0 +1,5 @@
|
|||
from . import safecompare, replayvalidation, randomshuffle
|
||||
|
||||
replay_validator = replayvalidation.replay_timestamp_validation
|
||||
random_shuffle = randomshuffle.random_shuffle
|
||||
safe_compare = safecompare.safe_compare
|
|
@ -0,0 +1,13 @@
|
|||
import secrets
|
||||
def random_shuffle(theList):
|
||||
myList = list(theList)
|
||||
shuffledList = []
|
||||
myListLength = len(myList) + 1
|
||||
while myListLength > 0:
|
||||
removed = secrets.randbelow(myListLength)
|
||||
try:
|
||||
shuffledList.append(myList.pop(removed))
|
||||
except IndexError:
|
||||
pass
|
||||
myListLength = len(myList)
|
||||
return shuffledList
|
|
@ -0,0 +1,6 @@
|
|||
import utils # onionr utils epoch, not this utils
|
||||
def replay_timestamp_validation(timestamp):
|
||||
if utils.epoch.get_epoch() - int(timestamp) > 2419200:
|
||||
return False
|
||||
else:
|
||||
return True
|
|
@ -0,0 +1,12 @@
|
|||
import hmac
|
||||
def safe_compare(one, two):
|
||||
# Do encode here to avoid spawning core
|
||||
try:
|
||||
one = one.encode()
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
two = two.encode()
|
||||
except AttributeError:
|
||||
pass
|
||||
return hmac.compare_digest(one, two)
|
|
@ -0,0 +1,24 @@
|
|||
import nacl.encoding, nacl.public, nacl.signing
|
||||
from .. import getourkeypair
|
||||
pair = getourkeypair.get_keypair()
|
||||
our_pub_key = pair[0]
|
||||
our_priv_key = pair[1]
|
||||
|
||||
def pub_key_decrypt(data, pubkey='', privkey='', encodedData=False):
|
||||
'''pubkey decrypt (Curve25519, taken from Ed25519 pubkey)'''
|
||||
decrypted = False
|
||||
if encodedData:
|
||||
encoding = nacl.encoding.Base64Encoder
|
||||
else:
|
||||
encoding = nacl.encoding.RawEncoder
|
||||
if privkey == '':
|
||||
privkey = our_priv_key
|
||||
ownKey = nacl.signing.SigningKey(seed=privkey, encoder=nacl.encoding.Base32Encoder()).to_curve25519_private_key()
|
||||
|
||||
if stringvalidators.validate_pub_key(privkey):
|
||||
privkey = nacl.signing.SigningKey(seed=privkey, encoder=nacl.encoding.Base32Encoder()).to_curve25519_private_key()
|
||||
anonBox = nacl.public.SealedBox(privkey)
|
||||
else:
|
||||
anonBox = nacl.public.SealedBox(ownKey)
|
||||
decrypted = anonBox.decrypt(data, encoder=encoding)
|
||||
return decrypted
|
|
@ -0,0 +1,17 @@
|
|||
import os
|
||||
import keymanager, config, filepaths
|
||||
from . import generate
|
||||
def get_keypair():
|
||||
key_m = keymanager.KeyManager()
|
||||
if os.path.exists(filepaths.keys_file):
|
||||
if len(config.get('general.public_key', '')) > 0:
|
||||
pubKey = config.get('general.public_key')
|
||||
else:
|
||||
pubKey = key_m.getPubkeyList()[0]
|
||||
privKey = key_m.getPrivkey(pubKey)
|
||||
else:
|
||||
keys = generate.generate_pub_key()
|
||||
pubKey = keys[0]
|
||||
privKey = keys[1]
|
||||
key_m.addKey(pubKey, privKey)
|
||||
return (pubKey, privKey)
|
|
@ -0,0 +1,44 @@
|
|||
import base64, binascii
|
||||
import nacl.encoding, nacl.signing, nacl.exceptions
|
||||
import logger
|
||||
def ed_sign(data, key, encodeResult=False):
|
||||
'''Ed25519 sign data'''
|
||||
try:
|
||||
data = data.encode()
|
||||
except AttributeError:
|
||||
pass
|
||||
key = nacl.signing.SigningKey(seed=key, encoder=nacl.encoding.Base32Encoder)
|
||||
retData = ''
|
||||
if encodeResult:
|
||||
retData = key.sign(data, encoder=nacl.encoding.Base64Encoder).signature.decode() # .encode() is not the same as nacl.encoding
|
||||
else:
|
||||
retData = key.sign(data).signature
|
||||
return retData
|
||||
|
||||
def ed_verify(data, key, sig, encodedData=True):
|
||||
'''Verify signed data (combined in nacl) to an ed25519 key'''
|
||||
try:
|
||||
key = nacl.signing.VerifyKey(key=key, encoder=nacl.encoding.Base32Encoder)
|
||||
except nacl.exceptions.ValueError:
|
||||
#logger.debug('Signature by unknown key (cannot reverse hash)')
|
||||
return False
|
||||
except binascii.Error:
|
||||
logger.warn('Could not load key for verification, invalid padding')
|
||||
return False
|
||||
retData = False
|
||||
sig = base64.b64decode(sig)
|
||||
try:
|
||||
data = data.encode()
|
||||
except AttributeError:
|
||||
pass
|
||||
if encodedData:
|
||||
try:
|
||||
retData = key.verify(data, sig) # .encode() is not the same as nacl.encoding
|
||||
except nacl.exceptions.BadSignatureError:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
retData = key.verify(data, sig)
|
||||
except nacl.exceptions.BadSignatureError:
|
||||
pass
|
||||
return retData
|
|
@ -18,11 +18,10 @@
|
|||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
'''
|
||||
import multiprocessing, nacl.encoding, nacl.hash, nacl.utils, time, math, threading, binascii, sys, json
|
||||
import config, logger, onionrblockapi, storagecounter, onionrcrypto
|
||||
import config, logger, onionrblockapi, storagecounter
|
||||
from onionrutils import bytesconverter
|
||||
|
||||
from onionrcrypto import hashers
|
||||
config.reload()
|
||||
crypto = onionrcrypto.OnionrCrypto()
|
||||
def getDifficultyModifier():
|
||||
'''returns the difficulty modifier for block storage based
|
||||
on a variety of factors, currently only disk use.
|
||||
|
@ -227,7 +226,7 @@ class POW:
|
|||
#token = nacl.hash.blake2b(rand + self.data).decode()
|
||||
self.metadata['pow'] = nonce
|
||||
payload = json.dumps(self.metadata).encode() + b'\n' + self.data
|
||||
token = crypto.sha3Hash(payload)
|
||||
token = hashers.sha3_hash(payload)
|
||||
try:
|
||||
# on some versions, token is bytes
|
||||
token = token.decode()
|
||||
|
|
|
@ -21,7 +21,7 @@ import json
|
|||
import logger, onionrexceptions
|
||||
from etc import onionrvalues
|
||||
from onionrutils import stringvalidators, epoch, bytesconverter
|
||||
import config, onionrvalues, filepaths, onionrcrypto
|
||||
import config, filepaths, onionrcrypto
|
||||
def validate_metadata(metadata, blockData):
|
||||
'''Validate metadata meets onionr spec (does not validate proof value computation), take in either dictionary or json string'''
|
||||
# TODO, make this check sane sizes
|
||||
|
|
|
@ -49,9 +49,9 @@ class SubprocessPOW:
|
|||
|
||||
self.data = bytesconverter.str_to_bytes(data)
|
||||
# Calculate difficulty. Dumb for now, may use good algorithm in the future.
|
||||
self.difficulty = onionrproofs.getDifficultyForNewBlock(bytes(json_metadata + b'\n' + self.data)
|
||||
self.difficulty = onionrproofs.getDifficultyForNewBlock(bytes(json_metadata + b'\n' + self.data))
|
||||
|
||||
logger.info('Computing POW (difficulty: %s)...' % self.difficulty)
|
||||
logger.info('Computing POW (difficulty: %s)...' % (self.difficulty,))
|
||||
|
||||
self.mainHash = '0' * 64
|
||||
self.puzzle = self.mainHash[0:min(self.difficulty, len(self.mainHash))]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import os
|
||||
def read_static(file, ret_bin=False):
|
||||
static_file = os.path.realpath(__file__) + '../static-data/' + file
|
||||
static_file = os.path.dirname(os.path.realpath(__file__)) + '/../static-data/' + file
|
||||
|
||||
if ret_bin:
|
||||
mode = 'rb'
|
||||
|
|
Loading…
Reference in New Issue