working on preventing replay attacks with block content
parent
ba2e5d7da9
commit
06dc97869e
|
@ -36,7 +36,7 @@ def importBlockFromData(content, coreInst):
|
|||
|
||||
metas = coreInst._utils.getBlockMetadataFromData(content) # returns tuple(metadata, meta), meta is also in metadata
|
||||
metadata = metas[0]
|
||||
if coreInst._utils.validateMetadata(metadata): # check if metadata is valid
|
||||
if coreInst._utils.validateMetadata(metadata, metas[2]): # check if metadata is valid
|
||||
if coreInst._crypto.verifyPow(content): # check if POW is enough/correct
|
||||
logger.info('Block passed proof, saving.')
|
||||
blockHash = coreInst.setData(content)
|
||||
|
|
|
@ -206,7 +206,7 @@ class OnionrCommunicatorDaemon:
|
|||
metas = self._core._utils.getBlockMetadataFromData(content) # returns tuple(metadata, meta), meta is also in metadata
|
||||
metadata = metas[0]
|
||||
#meta = metas[1]
|
||||
if self._core._utils.validateMetadata(metadata): # check if metadata is valid
|
||||
if self._core._utils.validateMetadata(metadata, metas[2]): # check if metadata is valid, and verify nonce
|
||||
if self._core._crypto.verifyPow(content): # check if POW is enough/correct
|
||||
logger.info('Block passed proof, saving.')
|
||||
self._core.setData(content)
|
||||
|
|
|
@ -22,7 +22,7 @@ from onionrblockapi import Block
|
|||
|
||||
import onionrutils, onionrcrypto, onionrproofs, onionrevents as events, onionrexceptions, onionrvalues
|
||||
import onionrblacklist
|
||||
|
||||
import dbcreator
|
||||
if sys.version_info < (3, 6):
|
||||
try:
|
||||
import sha3
|
||||
|
@ -46,6 +46,8 @@ class Core:
|
|||
self.bootstrapList = []
|
||||
self.requirements = onionrvalues.OnionrValues()
|
||||
self.torPort = torPort
|
||||
self.dataNonceFile = 'data/block-nonces.dat'
|
||||
self.dbCreate = dbcreator.DBCreator(self)
|
||||
|
||||
self.usageFile = 'data/disk-usage.txt'
|
||||
|
||||
|
@ -188,89 +190,20 @@ class Core:
|
|||
def createAddressDB(self):
|
||||
'''
|
||||
Generate the address database
|
||||
|
||||
types:
|
||||
1: I2P b32 address
|
||||
2: Tor v2 (like facebookcorewwwi.onion)
|
||||
3: Tor v3
|
||||
'''
|
||||
conn = sqlite3.connect(self.addressDB)
|
||||
c = conn.cursor()
|
||||
c.execute('''CREATE TABLE adders(
|
||||
address text,
|
||||
type int,
|
||||
knownPeer text,
|
||||
speed int,
|
||||
success int,
|
||||
DBHash text,
|
||||
powValue text,
|
||||
failure int,
|
||||
lastConnect int,
|
||||
lastConnectAttempt int,
|
||||
trust int
|
||||
);
|
||||
''')
|
||||
conn.commit()
|
||||
conn.close()
|
||||
self.dbCreate.createAddressDB()
|
||||
|
||||
def createPeerDB(self):
|
||||
'''
|
||||
Generate the peer sqlite3 database and populate it with the peers table.
|
||||
'''
|
||||
# generate the peer database
|
||||
conn = sqlite3.connect(self.peerDB)
|
||||
c = conn.cursor()
|
||||
c.execute('''CREATE TABLE peers(
|
||||
ID text not null,
|
||||
name text,
|
||||
adders text,
|
||||
blockDBHash text,
|
||||
forwardKey text,
|
||||
dateSeen not null,
|
||||
bytesStored int,
|
||||
trust int,
|
||||
pubkeyExchanged int,
|
||||
hashID text,
|
||||
pow text not null);
|
||||
''')
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return
|
||||
self.dbCreate.createPeerDB()
|
||||
|
||||
def createBlockDB(self):
|
||||
'''
|
||||
Create a database for blocks
|
||||
|
||||
hash - the hash of a block
|
||||
dateReceived - the date the block was recieved, not necessarily when it was created
|
||||
decrypted - if we can successfully decrypt the block (does not describe its current state)
|
||||
dataType - data type of the block
|
||||
dataFound - if the data has been found for the block
|
||||
dataSaved - if the data has been saved for the block
|
||||
sig - optional signature by the author (not optional if author is specified)
|
||||
author - multi-round partial sha3-256 hash of authors public key
|
||||
dateClaimed - timestamp claimed inside the block, only as trustworthy as the block author is
|
||||
'''
|
||||
if os.path.exists(self.blockDB):
|
||||
raise Exception("Block database already exists")
|
||||
conn = sqlite3.connect(self.blockDB)
|
||||
c = conn.cursor()
|
||||
c.execute('''CREATE TABLE hashes(
|
||||
hash text not null,
|
||||
dateReceived int,
|
||||
decrypted int,
|
||||
dataType text,
|
||||
dataFound int,
|
||||
dataSaved int,
|
||||
sig text,
|
||||
author text,
|
||||
dateClaimed int
|
||||
);
|
||||
''')
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
return
|
||||
self.dbCreate.createBlockDB()
|
||||
|
||||
def addToBlockDB(self, newHash, selfInsert=False, dataSaved=False):
|
||||
'''
|
||||
|
@ -702,6 +635,7 @@ class Core:
|
|||
signature = ''
|
||||
signer = ''
|
||||
metadata = {}
|
||||
# metadata is full block metadata, meta is internal, user specified metadata
|
||||
|
||||
# only use header if not set in provided meta
|
||||
if not header is None:
|
||||
|
@ -749,6 +683,12 @@ class Core:
|
|||
metadata['sig'] = signature
|
||||
metadata['signer'] = signer
|
||||
metadata['time'] = str(self._utils.getEpoch())
|
||||
|
||||
nonce = self._utils.bytesToStr(self._crypto.sha3Hash(data))
|
||||
|
||||
# TODO check in advance
|
||||
with open(self.dataNonceFile, 'a') as nonceFile:
|
||||
nonceFile.write(nonce + '\n')
|
||||
|
||||
# send block data (and metadata) to POW module to get tokenized block data
|
||||
proof = onionrproofs.POW(metadata, data)
|
||||
|
|
|
@ -41,6 +41,9 @@ class InvalidMetadata(Exception):
|
|||
class BlacklistedBlock(Exception):
|
||||
pass
|
||||
|
||||
class DataExists(Exception):
|
||||
pass
|
||||
|
||||
class InvalidHexHash(Exception):
|
||||
'''When a string is not a valid hex string of appropriate length for a hash value'''
|
||||
pass
|
||||
|
|
|
@ -334,7 +334,7 @@ class OnionrUtils:
|
|||
|
||||
return retVal
|
||||
|
||||
def validateMetadata(self, metadata):
|
||||
def validateMetadata(self, 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
|
||||
retData = False
|
||||
|
@ -364,7 +364,24 @@ class OnionrUtils:
|
|||
break
|
||||
else:
|
||||
# if metadata loop gets no errors, it does not break, therefore metadata is valid
|
||||
retData = True
|
||||
# make sure we do not have another block with the same data content (prevent data duplication and replay attacks)
|
||||
try:
|
||||
with open(self._core.dataNonceFile, 'r') as nonceFile:
|
||||
nonce = self._core._utils.bytesToStr(self._core._crypto.sha3Hash(blockData))
|
||||
if nonce in nonceFile.read():
|
||||
retData = False # we've seen that nonce before, so we can't pass metadata
|
||||
raise onionrexceptions.DataExists
|
||||
except FileNotFoundError:
|
||||
retData = True
|
||||
except onionrexceptions.DataExists:
|
||||
# do not set retData to True, because nonce has been seen before
|
||||
pass
|
||||
else:
|
||||
retData = True
|
||||
if retData:
|
||||
# Executes if data not seen
|
||||
with open(self._core.dataNonceFile, 'a') as nonceFile:
|
||||
nonceFile.write(nonce + '\n')
|
||||
else:
|
||||
logger.warn('In call to utils.validateMetadata, metadata must be JSON string or a dictionary object')
|
||||
|
||||
|
|
Loading…
Reference in New Issue