tor-dam

tor distributed announce mechanism (not a dht)
git clone https://git.parazyd.org/tor-dam
Log | Files | Refs | README | LICENSE

commit 9ebcc235e967e4998e86125edee43ae2cf5e1ad8
parent e0423709ee2442f0904b284c02d9b9b09639921f
Author: parazyd <parazyd@dyne.org>
Date:   Sat, 25 Nov 2017 03:39:35 +0100

implement basic PoC

Diffstat:
MREADME.md | 1+
Acrypto.py | 27+++++++++++++++++++++++++++
Adamn.py | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adir.py | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 181 insertions(+), 0 deletions(-)

diff --git a/README.md b/README.md @@ -20,3 +20,4 @@ Questions * Handling consensus? * How to keep track of node status? +* Could the DECODE website could host a directory? diff --git a/crypto.py b/crypto.py @@ -0,0 +1,27 @@ +# See LICENSE file for copyright and license details + +from base64 import b64decode, b64encode +from Crypto.PublicKey import RSA +from Crypto.Signature import PKCS1_v1_5 +from Crypto.Hash import SHA512 + + +def make_sign(privkey, message): + rsakey = RSA.importKey(privkey) + signer = PKCS1_v1_5.new(rsakey) + digest = SHA512.new() + + digest.update(message.encode('utf-8')) + sign = signer.sign(digest) + return b64encode(sign) # .decode('utf-8') + + +def verify_sign(pubkey, message, signature): + rsakey = RSA.importKey(pubkey) + signer = PKCS1_v1_5.new(rsakey) + digest = SHA512.new() + + digest.update(message.encode('utf-8')) + if signer.verify(digest, b64decode(signature)): + return True + return False diff --git a/damn.py b/damn.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +# See LICENSE file for copyright and license details. + +from os.path import isfile +from getpass import getpass +from stem.control import Controller +import simplejson as json +import requests + +from creds import tor_auth_pass +from crypto import make_sign + + +PORTMAP = { + # HS: local + 80: 49371, +} + + +def start_new_hs(ctl=None): + if not ctl: + assert False, 'No controller passed.' + return ctl.create_ephemeral_hidden_service(PORTMAP, key_type='NEW', + key_content='BEST', + await_publication=True) + + +def start_hs(ctl=None, ktype=None, kcont=None): + if not ktype or not kcont: + assert False, 'No key data passed.' + if not ctl: + assert False, 'No controller passed.' + + return ctl.create_ephemeral_hidden_service(PORTMAP, key_type=ktype, + key_content=kcont, + await_publication=True) + + +def main(): + controller = Controller.from_port() + controller.authenticate(password=tor_auth_pass) + + if not isfile('decode-tor.key'): + print('No existing HS key. Creating one...') + service = start_new_hs(ctl=controller) + with open('decode-tor.key', 'w') as kfile: + kfile.write('%s:%s' % (service.private_key_type, + service.private_key)) + else: + print('Found existing HS key. Starting up...') + with open('decode-tor.key', 'r') as kfile: + ktype, kcont = kfile.read().split(':', 1) + service = start_hs(ctl=controller, ktype=ktype, kcont=kcont) + + print(' * Started HS at %s.onion' % service.service_id) + + print(' * Signing my message...') + message = 'I am a DECODE node!' + rawkey = '-----BEGIN RSA PRIVATE KEY-----\n' + with open('decode-tor.key', 'r') as kfile: + rawkey += kfile.read().split(':', 1)[1] + rawkey += '\n-----END RSA PRIVATE KEY-----\n' + sign = make_sign(rawkey, message) + + print(' * Announcing myself to the directory!') + payload = [{ + 'type': 'node', + 'address': '%s.onion' % service.service_id, + 'message': message, + 'signature': sign, + }] + # resp = requests.post('http://qzhpi3jsbuvndnaw.onion/post', + resp = requests.post('http://localhost:49371/post', + data=json.dumps(payload), + headers={'Content-Type': 'application/json'}, + # proxies={'http': 'socks5://127.0.0.1:9050'} + ) + + input('Press Enter to exit.') + return + + +if __name__ == '__main__': + main() diff --git a/dir.py b/dir.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +# See LICENSE file for copyright and license details. + +from os.path import isfile +from time import time +import simplejson as json +from flask import Flask, request +from stem.control import Controller + +from creds import tor_auth_pass +from crypto import verify_sign + + +APP = Flask(__name__) + + +def parseapi(query): + mtype = query.get('type') + maddr = query.get('address') + mmesg = query.get('message') + msign = query.get('signature') + + nodedata = { + 'type': mtype, + 'address': maddr, + 'message': mmesg, + 'signature': msign, + 'firstseen': int(time()), + 'lastseen': int(time()), + } + + # It's already there. + for i in dirdata: + if i['address'] == maddr: + return False + + with Controller.from_port() as controller: + controller.authenticate(password=tor_auth_pass) + desc = controller.get_hidden_service_descriptor(maddr) + pkey = desc.permanent_key + nodedata['publickey'] = pkey + + if verify_sign(pkey, mmesg, msign): + dirdata.append(nodedata) + with open('decode-dir.json', 'w') as dirf: + dirf.write(json.dumps(dirdata, indent=2)) + + +@APP.route('/') +def main(): + return 'Main page\n' + + +@APP.route('/post', methods=['POST']) +def post(): + if request.get_json(): + for i in request.get_json(): + parseapi(i) + print(i) + return '' + + +if __name__ == '__main__': + if not isfile('decode-dir.json'): + with open('decode-dir.json', 'w') as f: + f.write('[]') + with open('decode-dir.json', 'r') as f: + dirdata = json.loads(f.read()) + APP.run(host='127.0.0.1', port=49371, threaded=True, debug=True)