diff --git a/onionr/apiservers/private/__init__.py b/onionr/apiservers/private/__init__.py
index 504712b6..e15a133e 100644
--- a/onionr/apiservers/private/__init__.py
+++ b/onionr/apiservers/private/__init__.py
@@ -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
diff --git a/onionr/apiservers/public/__init__.py b/onionr/apiservers/public/__init__.py
index 76f3fd79..e411ce75 100644
--- a/onionr/apiservers/public/__init__.py
+++ b/onionr/apiservers/public/__init__.py
@@ -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
diff --git a/onionr/core.py b/onionr/core.py
deleted file mode 100755
index 0d0775c0..00000000
--- a/onionr/core.py
+++ /dev/null
@@ -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 .
-'''
-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)
\ No newline at end of file
diff --git a/onionr/httpapi/apiutils/getblockdata.py b/onionr/httpapi/apiutils/getblockdata.py
index cb0736b5..1a8f7df0 100644
--- a/onionr/httpapi/apiutils/getblockdata.py
+++ b/onionr/httpapi/apiutils/getblockdata.py
@@ -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)
diff --git a/onionr/httpapi/miscclientapi/getblocks.py b/onionr/httpapi/miscclientapi/getblocks.py
index 3a9a4afe..0fb4f787 100644
--- a/onionr/httpapi/miscclientapi/getblocks.py
+++ b/onionr/httpapi/miscclientapi/getblocks.py
@@ -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
diff --git a/onionr/netcontroller/netcontrol.py b/onionr/netcontroller/netcontrol.py
index e0b54804..fc68504d 100644
--- a/onionr/netcontroller/netcontrol.py
+++ b/onionr/netcontroller/netcontrol.py
@@ -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)
diff --git a/onionr/onionrblockapi.py b/onionr/onionrblockapi.py
index e85e4330..9ab2d426 100755
--- a/onionr/onionrblockapi.py
+++ b/onionr/onionrblockapi.py
@@ -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
diff --git a/onionr/onionrcommands/daemonlaunch.py b/onionr/onionrcommands/daemonlaunch.py
index 81030cd1..7785e20d 100755
--- a/onionr/onionrcommands/daemonlaunch.py
+++ b/onionr/onionrcommands/daemonlaunch.py
@@ -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)
diff --git a/onionr/onionrcommands/pubkeymanager.py b/onionr/onionrcommands/pubkeymanager.py
index 8b20a769..e315c40d 100755
--- a/onionr/onionrcommands/pubkeymanager.py
+++ b/onionr/onionrcommands/pubkeymanager.py
@@ -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)
diff --git a/onionr/onionrcrypto/__init__.py b/onionr/onionrcrypto/__init__.py
index b1fa4af5..df5a9088 100755
--- a/onionr/onionrcrypto/__init__.py
+++ b/onionr/onionrcrypto/__init__.py
@@ -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:
@@ -251,38 +191,4 @@ class OnionrCrypto:
else:
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
\ No newline at end of file
+ return retData
\ No newline at end of file
diff --git a/onionr/onionrcrypto/cryptoutils/__init__.py b/onionr/onionrcrypto/cryptoutils/__init__.py
new file mode 100644
index 00000000..4e1c5c30
--- /dev/null
+++ b/onionr/onionrcrypto/cryptoutils/__init__.py
@@ -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
\ No newline at end of file
diff --git a/onionr/onionrcrypto/cryptoutils/randomshuffle.py b/onionr/onionrcrypto/cryptoutils/randomshuffle.py
new file mode 100644
index 00000000..05f859fc
--- /dev/null
+++ b/onionr/onionrcrypto/cryptoutils/randomshuffle.py
@@ -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
\ No newline at end of file
diff --git a/onionr/onionrcrypto/cryptoutils/replayvalidation.py b/onionr/onionrcrypto/cryptoutils/replayvalidation.py
new file mode 100644
index 00000000..fbb581f3
--- /dev/null
+++ b/onionr/onionrcrypto/cryptoutils/replayvalidation.py
@@ -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
\ No newline at end of file
diff --git a/onionr/onionrcrypto/cryptoutils/safecompare.py b/onionr/onionrcrypto/cryptoutils/safecompare.py
new file mode 100644
index 00000000..ddd6b58e
--- /dev/null
+++ b/onionr/onionrcrypto/cryptoutils/safecompare.py
@@ -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)
\ No newline at end of file
diff --git a/onionr/onionrcrypto/encryption/__init__.py b/onionr/onionrcrypto/encryption/__init__.py
new file mode 100644
index 00000000..e676851e
--- /dev/null
+++ b/onionr/onionrcrypto/encryption/__init__.py
@@ -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
\ No newline at end of file
diff --git a/onionr/onionrcrypto/getourkeypair.py b/onionr/onionrcrypto/getourkeypair.py
new file mode 100644
index 00000000..0eba1abc
--- /dev/null
+++ b/onionr/onionrcrypto/getourkeypair.py
@@ -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)
diff --git a/onionr/onionrcrypto/signing/__init__.py b/onionr/onionrcrypto/signing/__init__.py
new file mode 100644
index 00000000..a46aacc2
--- /dev/null
+++ b/onionr/onionrcrypto/signing/__init__.py
@@ -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
\ No newline at end of file
diff --git a/onionr/onionrproofs.py b/onionr/onionrproofs.py
index bc555077..349d8ec7 100755
--- a/onionr/onionrproofs.py
+++ b/onionr/onionrproofs.py
@@ -18,11 +18,10 @@
along with this program. If not, see .
'''
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()
diff --git a/onionr/onionrutils/validatemetadata.py b/onionr/onionrutils/validatemetadata.py
index ef3cde95..6515753a 100644
--- a/onionr/onionrutils/validatemetadata.py
+++ b/onionr/onionrutils/validatemetadata.py
@@ -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
diff --git a/onionr/subprocesspow.py b/onionr/subprocesspow.py
index 674aea00..95586ca0 100755
--- a/onionr/subprocesspow.py
+++ b/onionr/subprocesspow.py
@@ -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))]
diff --git a/onionr/utils/readstatic.py b/onionr/utils/readstatic.py
index adbe1cf6..7ad93556 100644
--- a/onionr/utils/readstatic.py
+++ b/onionr/utils/readstatic.py
@@ -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'