progress in removing core

master
Kevin Froman 2019-07-20 10:52:03 -05:00
parent 348ec1081f
commit e7c8c93dab
16 changed files with 68 additions and 229 deletions

View File

@ -34,6 +34,8 @@ from utils import detectoptimization
if detectoptimization.detect_optimization():
sys.stderr.write('Error, Onionr cannot be run in optimized mode\n')
sys.exit(1)
from utils import createdirs
createdirs.create_dirs()
import os, base64, random, shutil, time, platform, signal
from threading import Thread
import config, logger, onionrplugins as plugins, onionrevents as events
@ -42,7 +44,7 @@ from netcontroller import NetController
from onionrblockapi import Block
import onionrproofs, onionrexceptions, communicator, setupconfig
import onionrcommands as commands # Many command definitions are here
from utils import identifyhome, createdirs
from utils import identifyhome
from coredb import keydb
import filepaths
@ -75,7 +77,6 @@ class Onionr:
# Load global configuration data
data_exists = Onionr.setupConfig(self.dataDir, self)
createdirs.create_dirs()
if netcontroller.tor_binary() is None:
logger.error('Tor is not installed', terminal=True)

View File

@ -21,7 +21,7 @@ import sqlite3, os
import logger, onionrcrypto
from onionrutils import epoch, bytesconverter
from coredb import dbfiles
crypto = onionrcrypto.OnionrCrypto()
class OnionrBlackList:
def __init__(self):
self.blacklistDB = dbfiles.blacklist_db
@ -31,7 +31,7 @@ class OnionrBlackList:
return
def inBlacklist(self, data):
hashed = bytesconverter.bytes_to_str(crypto.sha3Hash(data))
hashed = bytesconverter.bytes_to_str(onionrcrypto.hashers.sha3_hash(data))
retData = False
if not hashed.isalnum():
@ -100,6 +100,7 @@ class OnionrBlackList:
1=peer
2=pubkey
'''
# we hash the data so we can remove data entirely from our node's disk
hashed = bytesconverter.bytes_to_str(crypto.sha3Hash(data))
if len(hashed) > 64:

View File

@ -1 +1,3 @@
from . import insert
from . import insert
insert = insert.insert_block

View File

@ -3,15 +3,18 @@ from onionrutils import bytesconverter, epoch
import storagecounter, filepaths, onionrstorage
import onionrevents as events
from etc import powchoice, onionrvalues
def insert_block(onionr_inst, data, header='txt', sign=False, encryptType='', symKey='', asymPeer='', meta = {}, expire=None, disableForward=False):
import config, onionrcrypto as crypto, subprocesspow, onionrexceptions
from onionrusers import onionrusers
from onionrutils import localcommand, blockmetadata
import coredb
def insert_block(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
'''
use_subprocess = powchoice.use_subprocess(onionr_inst.config)
use_subprocess = powchoice.use_subprocess(config)
requirements = onionrvalues.OnionrValues()
storage_counter = storagecounter.StorageCounter()
crypto = onionr_inst.crypto
allocationReachedMessage = 'Cannot insert block, disk allocation reached.'
if storage_counter.isFull():
logger.error(allocationReachedMessage)
@ -23,7 +26,7 @@ def insert_block(onionr_inst, data, header='txt', sign=False, encryptType='', sy
createTime = epoch.get_epoch()
dataNonce = bytesconverter.bytes_to_str(hashers.sha3_hash(data))
dataNonce = bytesconverter.bytes_to_str(crypto.hashers.sha3_hash(data))
try:
with open(filepaths.data_nonce_file, 'r') as nonces:
if dataNonce in nonces:
@ -78,31 +81,23 @@ def insert_block(onionr_inst, data, header='txt', sign=False, encryptType='', sy
jsonMeta = json.dumps(meta)
plaintextMeta = jsonMeta
if sign:
signature = crypto.edSign(jsonMeta.encode() + data, key=crypto.privKey, encodeResult=True)
signature = crypto.signing.ed_sign(jsonMeta.encode() + data, key=crypto.priv_key, encodeResult=True)
signer = crypto.pubKey
if len(jsonMeta) > 1000:
raise onionrexceptions.InvalidMetadata('meta in json encoded form must not exceed 1000 bytes')
user = onionrusers.OnionrUser(symKey)
# encrypt block metadata/sig/content
if encryptType == 'sym':
if len(symKey) < requirements.passwordLength:
raise onionrexceptions.SecurityError('Weak encryption key')
jsonMeta = crypto.symmetricEncrypt(jsonMeta, key=symKey, returnEncoded=True).decode()
data = crypto.symmetricEncrypt(data, key=symKey, returnEncoded=True).decode()
signature = crypto.symmetricEncrypt(signature, key=symKey, returnEncoded=True).decode()
signer = crypto.symmetricEncrypt(signer, key=symKey, returnEncoded=True).decode()
raise NotImplementedError("not yet implemented")
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 = crypto.pubKeyEncrypt(jsonMeta, asymPeer, encodedData=True).decode()
data = crypto.pubKeyEncrypt(data, asymPeer, encodedData=True).decode()
signature = crypto.pubKeyEncrypt(signature, asymPeer, encodedData=True).decode()
signer = crypto.pubKeyEncrypt(signer, asymPeer, encodedData=True).decode()
jsonMeta = crypto.encryption.pub_key_encrypt(jsonMeta, asymPeer, encodedData=True).decode()
data = crypto.encryption.pub_key_encrypt(data, asymPeer, encodedData=True).decode()
signature = crypto.pub_key_encrypt(signature, asymPeer, encodedData=True).decode()
signer = crypto.pub_key_encrypt(signer, asymPeer, encodedData=True).decode()
try:
onionrusers.OnionrUser(asymPeer, saveUser=True)
except ValueError:
@ -141,8 +136,8 @@ def insert_block(onionr_inst, data, header='txt', sign=False, encryptType='', sy
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(retData)
coredb.blockmetadb.add.add_to_block_DB(retData, selfInsert=True, dataSaved=True)
blockmetadata.process_block_metadata(retData)
'''
if retData != False:
if plaintextPeer == onionrvalues.DENIABLE_PEER_ADDRESS:

View File

@ -25,7 +25,6 @@ from onionrutils import checkcommunicator, mnemonickeys
from utils import sizeutils
from coredb import blockmetadb, daemonqueue, keydb
import onionrcrypto
crypto = onionrcrypto.OnionrCrypto()
def show_stats(o_inst):
try:
# define stats messages here
@ -89,7 +88,7 @@ def show_details(o_inst):
details = {
'Node Address' : o_inst.get_hostname(),
'Web Password' : o_inst.getWebPassword(),
'Public Key' : crypto.pubKey,
'Public Key' : onionrcrypto.pub_key,
'Human-readable Public Key' : mnemonickeys.get_human_readable_ID()
}

View File

@ -17,178 +17,10 @@
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, binascii, base64, hashlib, time, sys, hmac, secrets
import nacl.signing, nacl.encoding, nacl.public, nacl.hash, nacl.pwhash, nacl.utils, nacl.secret
import unpaddedbase32
import logger, onionrproofs
from onionrutils import stringvalidators, epoch, bytesconverter
import filepaths
import onionrexceptions, keymanager, onionrutils
import config
from . import generate, hashers
config.reload()
class OnionrCrypto:
def __init__(self):
self._keyFile = filepaths.keys_file
self.pubKey = None
self.privKey = None
self.secrets = secrets
self.deterministicRequirement = 25 # Min deterministic password/phrase length
self.HASH_ID_ROUNDS = 2000
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):
if len(config.get('general.public_key', '')) > 0:
self.pubKey = config.get('general.public_key')
else:
self.pubKey = self.keyManager.getPubkeyList()[0]
self.privKey = self.keyManager.getPrivkey(self.pubKey)
else:
keys = self.generatePubKey()
self.pubKey = keys[0]
self.privKey = keys[1]
self.keyManager.addKey(self.pubKey, self.privKey)
return
from . import generate, hashers, getourkeypair, signing, encryption
def pubKeyEncrypt(self, data, pubkey, encodedData=False):
'''Encrypt to a public key (Curve25519, taken from base32 Ed25519 pubkey)'''
pubkey = unpaddedbase32.repad(bytesconverter.str_to_bytes(pubkey))
retVal = ''
box = None
data = bytesconverter.str_to_bytes(data)
pubkey = nacl.signing.VerifyKey(pubkey, encoder=nacl.encoding.Base32Encoder()).to_curve25519_public_key()
if encodedData:
encoding = nacl.encoding.Base64Encoder
else:
encoding = nacl.encoding.RawEncoder
box = nacl.public.SealedBox(pubkey)
retVal = box.encrypt(data, encoder=encoding)
return retVal
def symmetricEncrypt(self, data, key, encodedKey=False, returnEncoded=True):
'''Encrypt data with a 32-byte key (Salsa20-Poly1305 MAC)'''
if encodedKey:
encoding = nacl.encoding.Base64Encoder
else:
encoding = nacl.encoding.RawEncoder
# Make sure data is bytes
if type(data) != bytes:
data = data.encode()
box = nacl.secret.SecretBox(key, encoder=encoding)
if returnEncoded:
encoding = nacl.encoding.Base64Encoder
else:
encoding = nacl.encoding.RawEncoder
encrypted = box.encrypt(data, encoder=encoding)
return encrypted
def symmetricDecrypt(self, data, key, encodedKey=False, encodedMessage=False, returnEncoded=False):
'''Decrypt data to a 32-byte key (Salsa20-Poly1305 MAC)'''
if encodedKey:
encoding = nacl.encoding.Base64Encoder
else:
encoding = nacl.encoding.RawEncoder
box = nacl.secret.SecretBox(key, encoder=encoding)
if encodedMessage:
encoding = nacl.encoding.Base64Encoder
else:
encoding = nacl.encoding.RawEncoder
decrypted = box.decrypt(data, encoder=encoding)
if returnEncoded:
decrypted = base64.b64encode(decrypted)
return decrypted
def generateSymmetric(self):
'''Generate a symmetric key (bytes) and return it'''
return binascii.hexlify(nacl.utils.random(nacl.secret.SecretBox.KEY_SIZE))
def generatePubKey(self):
'''Generate a Ed25519 public key pair, return tuple of base32encoded pubkey, privkey'''
return generate.generate_pub_key()
def generateDeterministic(self, passphrase, bypassCheck=False):
'''Generate a Ed25519 public key pair from a password'''
passStrength = self.deterministicRequirement
passphrase = bytesconverter.str_to_bytes(passphrase) # Convert to bytes if not already
# Validate passphrase length
if not bypassCheck:
if len(passphrase) < passStrength:
raise onionrexceptions.PasswordStrengthError("Passphase must be at least %s characters" % (passStrength,))
# KDF values
kdf = nacl.pwhash.argon2id.kdf
salt = b"U81Q7llrQcdTP0Ux" # Does not need to be unique or secret, but must be 16 bytes
ops = nacl.pwhash.argon2id.OPSLIMIT_SENSITIVE
mem = nacl.pwhash.argon2id.MEMLIMIT_SENSITIVE
key = kdf(32, passphrase, salt, opslimit=ops, memlimit=mem) # Generate seed for ed25519 key
key = nacl.signing.SigningKey(key)
return (key.verify_key.encode(nacl.encoding.Base32Encoder).decode(), key.encode(nacl.encoding.Base32Encoder).decode())
def pubKeyHashID(self, pubkey=''):
'''Accept a ed25519 public key, return a truncated result of X many sha3_256 hash rounds'''
if pubkey == '':
pubkey = self.pubKey
prev = ''
pubkey = bytesconverter.str_to_bytes(pubkey)
for i in range(self.HASH_ID_ROUNDS):
try:
prev = prev.encode()
except AttributeError:
pass
hasher = hashlib.sha3_256()
hasher.update(pubkey + prev)
prev = hasher.hexdigest()
result = prev
return result
def sha3Hash(self, data):
return hashers.sha3_hash(data)
def blake2bHash(self, data):
return hashers.blake2b_hash(data)
def verifyPow(self, blockContent):
'''
Verifies the proof of work associated with a block
'''
retData = False
dataLen = len(blockContent)
try:
blockContent = blockContent.encode()
except AttributeError:
pass
blockHash = self.sha3Hash(blockContent)
try:
blockHash = blockHash.decode() # bytes on some versions for some reason
except AttributeError:
pass
difficulty = onionrproofs.getDifficultyForNewBlock(blockContent, ourBlock=False)
if difficulty < int(config.get('general.minimum_block_pow')):
difficulty = int(config.get('general.minimum_block_pow'))
mainHash = '0000000000000000000000000000000000000000000000000000000000000000'#nacl.hash.blake2b(nacl.utils.random()).decode()
puzzle = mainHash[:difficulty]
if blockHash[:difficulty] == puzzle:
# logger.debug('Validated block pow')
retData = True
else:
logger.debug("Invalid token, bad proof")
return retData
keypair = getourkeypair.get_keypair()
pub_key = keypair[0]
priv_key = keypair[1]

View File

@ -1,9 +1,29 @@
import nacl.encoding, nacl.public, nacl.signing
from .. import getourkeypair
import unpaddedbase32
pair = getourkeypair.get_keypair()
our_pub_key = pair[0]
our_priv_key = pair[1]
def pub_key_encrypt(data, pubkey, encodedData=False):
'''Encrypt to a public key (Curve25519, taken from base32 Ed25519 pubkey)'''
pubkey = unpaddedbase32.repad(bytesconverter.str_to_bytes(pubkey))
retVal = ''
box = None
data = bytesconverter.str_to_bytes(data)
pubkey = nacl.signing.VerifyKey(pubkey, encoder=nacl.encoding.Base32Encoder()).to_curve25519_public_key()
if encodedData:
encoding = nacl.encoding.Base64Encoder
else:
encoding = nacl.encoding.RawEncoder
box = nacl.public.SealedBox(pubkey)
retVal = box.encrypt(data, encoder=encoding)
return retVal
def pub_key_decrypt(data, pubkey='', privkey='', encodedData=False):
'''pubkey decrypt (Curve25519, taken from Ed25519 pubkey)'''
decrypted = False

View File

@ -33,11 +33,11 @@ def __event_caller(event_name, data = {}, onionr = None):
try:
call(plugins.get_plugin(plugin), event_name, data, get_pluginapi(onionr, data))
except ModuleNotFoundError as e:
logger.warn('Disabling nonexistant plugin "%s"...' % plugin)
logger.warn('Disabling nonexistant plugin "%s"...' % plugin, terminal=True)
plugins.disable(plugin, onionr, stop_event = False)
except Exception as e:
logger.warn('Event "%s" failed for plugin "%s".' % (event_name, plugin))
logger.debug(str(e))
logger.warn('Event "%s" failed for plugin "%s".' % (event_name, plugin), terminal=True)
logger.debug(str(e), terminal=True)
def event(event_name, data = {}, onionr = None, threaded = True):

View File

@ -18,7 +18,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
'''
import onionrplugins, logger, onionrcrypto
import onionrplugins, logger
from onionrutils import localcommand
from coredb import daemonqueue
class DaemonAPI:
@ -154,7 +154,6 @@ class pluginapi:
self.plugins = PluginAPI(self)
self.commands = CommandAPI(self)
self.web = WebAPI(self)
self.crypto = onionrcrypto.OnionrCrypto()
def get_onionr(self):
return self.onionr
@ -162,9 +161,6 @@ class pluginapi:
def get_data(self):
return self.data
def get_crypto(self):
return self.crypto
def get_daemonapi(self):
return self.daemon

View File

@ -26,7 +26,6 @@ def getDifficultyModifier():
'''returns the difficulty modifier for block storage based
on a variety of factors, currently only disk use.
'''
classInst = coreOrUtilsInst
retData = 0
useFunc = storagecounter.StorageCounter().getPercent

View File

@ -24,14 +24,7 @@ import filepaths, onionrcrypto, dbcreator, onionrexceptions
from onionrcrypto import hashers
DB_ENTRY_SIZE_LIMIT = 10000 # Will be a config option
def dbCreate():
try:
dbcreator.DBCreator().createBlockDataDB()
except FileExistsError:
pass
def _dbInsert(blockHash, data):
dbCreate()
conn = sqlite3.connect(dbfiles.block_data_db, timeout=10)
c = conn.cursor()
data = (blockHash, data)
@ -40,7 +33,6 @@ def _dbInsert(blockHash, data):
conn.close()
def _dbFetch(blockHash):
dbCreate()
conn = sqlite3.connect(dbfiles.block_data_db, timeout=10)
c = conn.cursor()
for i in c.execute('SELECT data from blockData where hash = ?', (blockHash,)):
@ -54,7 +46,6 @@ def deleteBlock(blockHash):
if os.path.exists('%s/%s.dat' % (filepaths.block_data_location, blockHash)):
os.remove('%s/%s.dat' % (filepaths.block_data_location, blockHash))
return True
dbCreate()
conn = sqlite3.connect(dbfiles.block_data_db, timeout=10)
c = conn.cursor()
data = (blockHash,)
@ -91,7 +82,7 @@ def getData(bHash):
with open(fileLocation, 'rb') as block:
retData = block.read()
else:
retData = _dbFetch(coreInst, bHash)
retData = _dbFetch(bHash)
if retData is None:
raise onionrexceptions.NoDataAvailable("Block data for %s is not available" % [bHash])
return retData

View File

@ -1,12 +1,11 @@
import sys, sqlite3
import onionrstorage, onionrexceptions, onionrcrypto
import onionrstorage, onionrexceptions, onionrcrypto as crypto
import filepaths, storagecounter
from coredb import dbfiles
def set_data(data):
'''
Set the data assciated with a hash
'''
crypto = onionrcrypto.OnionrCrypto()
storage_counter = storagecounter.StorageCounter()
data = data
dataSize = sys.getsizeof(data)
@ -14,7 +13,7 @@ def set_data(data):
if not type(data) is bytes:
data = data.encode()
dataHash = crypto.sha3Hash(data)
dataHash = crypto.hashers.sha3_hash(data)
if type(dataHash) is bytes:
dataHash = dataHash.decode()

View File

@ -30,9 +30,13 @@ def get_hostname():
maxWait = 3
while True:
if cache.get('client_api') is None:
hostname = getclientapiserver.get_client_API_server()
cache.put('hostname', hostname)
cache.flush()
try:
hostname = getclientapiserver.get_client_API_server()
except FileNotFoundError:
hostname = False
else:
cache.put('hostname', hostname)
cache.flush()
else:
hostname = cache.get('hostname')
if hostname == '' or hostname is None:
@ -48,9 +52,11 @@ def local_command(command, data='', silent = True, post=False, postData = {}, ma
'''
# TODO: URL encode parameters, just as an extra measure. May not be needed, but should be added regardless.
hostname = get_hostname()
if hostname == False: return False
if data != '':
data = '&data=' + urllib.parse.quote_plus(data)
payload = 'http://%s/%s%s' % (hostname, command, data)
try:
if post:
retData = requests.post(payload, data=postData, headers={'token': config.get('client.webpassword'), 'Connection':'close'}, timeout=(maxWait, maxWait)).text

View File

@ -23,6 +23,6 @@ import onionrcrypto
def get_human_readable_ID(pub=''):
'''gets a human readable ID from a public key'''
if pub == '':
pub = onionrcrypto.OnionrCrypto().pubKey
pub = onionrcrypto.pub_key
pub = base64.b16encode(base64.b32decode(pub)).decode()
return ' '.join(pgpwords.wordify(pub))

View File

@ -96,7 +96,6 @@ def on_init(api, data = None):
inputted is executed. Could be called when daemon is starting or when
just the client is running.
'''
# Doing this makes it so that the other functions can access the api object
# by simply referencing the variable `pluginapi`.
global pluginapi

View File

@ -22,9 +22,8 @@
import subprocess, os
import multiprocessing, threading, time, json
from multiprocessing import Pipe, Process
import onionrblockapi, config, onionrutils, logger, onionrproofs, onionrcrypto
import onionrblockapi, config, onionrutils, logger, onionrproofs, onionrcrypto as crypto
from onionrutils import bytesconverter
crypto = onionrcrypto.OnionrCrypto()
class SubprocessPOW:
def __init__(self, data, metadata, subproc_count=None):
'''
@ -105,7 +104,7 @@ class SubprocessPOW:
# Serialize metadata, combine with block data
payload = json.dumps(metadata).encode() + b'\n' + data
# Check sha3_256 hash of block, compare to puzzle. Send payload if puzzle finished
token = crypto.sha3Hash(payload)
token = crypto.hashers.sha3_hash(payload)
token = bytesconverter.bytes_to_str(token) # ensure token is string
if puzzle == token[0:difficulty]:
pipe.send(payload)