From 097c57b97a704363ad8fb4989cba79527f9ecf5e Mon Sep 17 00:00:00 2001 From: Kevin Froman Date: Sat, 13 Jan 2018 18:07:13 -0600 Subject: [PATCH] work on adding peers, improving docs, and minor bug fixes --- .gitignore | 3 +- communicator.py | 31 +++++++++++++------ core.py | 4 +-- docs/onionr-draft.md | 72 ++++++++++++++++++++++++++++++++++++++++++++ onionr.py | 19 ++++++++++-- tests.py | 5 +-- 6 files changed, 116 insertions(+), 18 deletions(-) create mode 100644 docs/onionr-draft.md diff --git a/.gitignore b/.gitignore index 4c21df2e..0e059a82 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ __pycache__/ data/config.ini data/*.db -dev-enabled \ No newline at end of file +data-old/* +dev-enabled diff --git a/communicator.py b/communicator.py index 2d7e60f5..0b9e582a 100755 --- a/communicator.py +++ b/communicator.py @@ -1,6 +1,11 @@ #!/usr/bin/env python3 ''' - Onionr - P2P Microblogging Platform & Social network. Run with 'help' for usage. +Onionr - P2P Microblogging Platform & Social network. + +This file contains both the OnionrCommunicate class for communcating with peers +and code to operate as a daemon, getting commands from the command queue database (see core.Core.daemonQueue) +''' +''' 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 @@ -14,24 +19,30 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . ''' -import sqlite3, requests, hmac, hashlib, time +import sqlite3, requests, hmac, hashlib, time, sys import core class OnionrCommunicate: def __init__(self): + ''' OnionrCommunicate + + This class handles communication with nodes in the Onionr network. + ''' self._core = core.Core() - while True: - print('Onionr daemon running') - time.sleep(2) return def getRemotePeerKey(self, peerID): '''This function contacts a peer and gets their main PGP key. - This is safe because Tor or I2P is used, but it does not insure that the person is who they say they are + + This is safe because Tor or I2P is used, but it does not ensure that the person is who they say they are ''' url = 'http://' + peerID + '/public/?action=getPGP' r = requests.get(url, headers=headers) response = r.text return response - - - -OnionrCommunicate() \ No newline at end of file +shouldRun = False +try: + if sys.argv[1] == 'run': + shouldRun = True +except IndexError: + pass +if shouldRun: + OnionrCommunicate() \ No newline at end of file diff --git a/core.py b/core.py index 7a67207a..ad37b877 100644 --- a/core.py +++ b/core.py @@ -37,8 +37,8 @@ class Core: # This function simply adds a peer to the DB conn = sqlite3.connect(self.peerDB) c = conn.cursor() - t = (peerID, name) - c.execute('Insert into users (id, name) values(?, ?);', t) + t = (peerID, name, 'unknown') + c.execute('Insert into users (id, name, dateSeen) values(?, ?, ?);', t) conn.commit() conn.close() return True diff --git a/docs/onionr-draft.md b/docs/onionr-draft.md new file mode 100644 index 00000000..5cd8c55d --- /dev/null +++ b/docs/onionr-draft.md @@ -0,0 +1,72 @@ +# Onionr Protocol Spec + +A social network/microblogging platform for Tor & I2P + +Draft Dec 25 2017 + +notes: +Use Blowfish in addition with AES? + +# Overview + +Onionr is an encrypted microblogging & mailing system designed in the spirit of Twitter. +There are no central servers and all traffic is peer to peer by default (routed via Tor or I2P). +User IDs are simply Tor onion service/I2P host id + PGP fingerprint. +Clients consolidate feeds from peers into 1 “timeline” using RSS format. +Private messages are only accessible by the intended peer based on the PGP id. +Onionr is not intended to be a replacement for Ricochet or OnionShare. +All traffic is over onion/I2P because if only some was, then that would make that traffic inherently suspicious. +## Goals: + • Selective sharing of information with friends & public + • Secure & semi-anonymous direct messaging + • Forward secrecy + • Defense in depth + • Data should be secure for years to come, quantum safe (though not necessarily every “layer”) + • Decentralization + * Avoid browser-based exploits that plague similar software + * Avoid timing attacks & unexpected metadata leaks +## Assumptions: + • Tor & I2P’s transport protocols & AES-256 are not broken, sha3-512 2nd preimage attacks will remain infeasible indefinitely + • All traffic is logged indefinitely by powerful adversaries +## Protocol +Clients MUST use HTTP(s) to communicate with one another to maintain compatibility cross platform. HTTPS is recommended, but HTTP is acceptable because Tor & I2P provide transport layer security. +## Connections + When a node first comes online, it attempts to bootstrap using a default list provided by a client. + When two peers connect, they exchange PGP public keys and then generate a shared AES-SHA3-512 HMAC token. These keys are stored in a peer database until expiry. + HMAC tokens are regenerated either every X many communications with a peer or every X minutes. Every 10 communications or every 24 hours is a recommended default. + All valid requests with HMAC should be recorded until used HMAC's expiry to prevent replay attacks. + Peer Types + * Friends: + * Encrypted ‘friends only’ posts to one another + * Usually less strict rate & storage limits + * OPTIONALLY sign one another’s keys. Users may not want to do this in order to avoid exposing their entire friends list. + • Strangers: + * Used for storage of encrypted or public information + * Can only read public posts + * Usually stricter rate & storage limits +## Data Storage/Delivery + + Posts (public or friends only) are stored across the network. + Private messages SHOULD be delivered directly if both peers are online, otherwise stored in the network. + Data SHOULD be stored in an entirely encrypted state when a client is offline, including metadata. Data SHOULD be stored in a minimal size with garbage data to ensure some level of plausible deniablity. + Data SHOULD be stored as long as the node’s user prefers and only erased once disk quota is reached due to new data. + Posts + Posts can contain text and images. All posts MUST be time stamped. + Images SHOULD not be displayed by non-friends by default, to prevent unwanted viewing of offensive material & to reduce attack surface. + All received posts must be verified to be stored and/or displayed to the user. + Posts have two settings: + • Friends only: + ◦ Posts MUST be encrypted to all trusted peers via AES256-HMAC-SHA256 and PGP signed (signed before encryption) and time stamped to prevent replaying. A temporary RSA key for use in every post (or message) is exchanged every X many configured post (or message), for use in addition with PGP and the HMAC. + • Public: + ◦ Posts MUST be PGP signed, and MUST NOT use any encryption. +## Private Messages + + Private messages are messages that can have attached images. They MUST be encrypted via AES256-HMAC-SHA256 and PGP signed (signed before encryption) and time stamped to prevent replaying. A temporary RSA key for use in every message is exchanged every X many configured messages (or posts), for use in addition with PGP and the HMAC. + When both peers are online messages SHOULD be dispatched directly between peers. + All messages must be verified prior to being displayed. + + CLients SHOULD allow configurable message padding. +## Spam mitigation + +To send or receive data, a node can optionally request that the other node generate a hash that when in hexadecimal representation contains a random string at a random location in the string. Clients will configure what difficulty to request, and what difficulty is acceptable for themselves to perform. Difficulty should correlate with recent network & disk usage and data size. Friends can be configured to have less strict (to non existent) limits, separately from strangers. (proof of work). +Rate limits can be strict, as Onionr is not intended to be an instant messaging application. \ No newline at end of file diff --git a/onionr.py b/onionr.py index a923195a..f72e0c44 100755 --- a/onionr.py +++ b/onionr.py @@ -1,6 +1,12 @@ #!/usr/bin/env python3 ''' - Onionr - P2P Microblogging Platform & Social network. Run with 'help' for usage. + Onionr - P2P Microblogging Platform & Social network. + + Onionr is the name for both the protocol and the original/reference software. + + Run with 'help' for usage. +''' +''' 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 @@ -21,6 +27,10 @@ from colors import Colors class Onionr: def __init__(self): + '''Main Onionr class. This is for the CLI program, and does not handle much of the logic. + In general, external programs and plugins should not use this class. + + ''' if os.path.exists('dev-enabled'): print('DEVELOPMENT MODE ENABLED (THIS IS LESS SECURE!)') self._developmentMode = True @@ -35,8 +45,11 @@ class Onionr: # Get configuration and Handle commands self.debug = False # Whole application debugging + try: + os.chdir(sys.path[0]) + except FileNotFoundError: + pass - os.chdir(sys.path[0]) if os.path.exists('data-encrypted.dat'): while True: print('Enter password to decrypt:') @@ -94,7 +107,7 @@ class Onionr: return def daemon(self): if not os.environ.get("WERKZEUG_RUN_MAIN") == "true": - subprocess.Popen(["./communicator.py"]) + subprocess.Popen(["./communicator.py", "run"]) print('Started communicator') api.API(self.config, self.debug) return diff --git a/tests.py b/tests.py index 0a041840..c099f352 100755 --- a/tests.py +++ b/tests.py @@ -49,9 +49,10 @@ class OnionrTests(unittest.TestCase): print('Running peer db insertion test') import core myCore = core.Core() - myCore.createPeerDB() + if not os.path.exists('data/peers.db'): + myCore.createPeerDB() if myCore.addPeer('test'): - self.asserTrue(True) + self.assertTrue(True) else: self.assertTrue(False) def testData_b_Encrypt(self):