URI: 
       timplement basic PoC - tordam - A library for peer discovery inside the Tor network
  HTML git clone https://git.parazyd.org/tordam
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 9ebcc235e967e4998e86125edee43ae2cf5e1ad8
   DIR parent e0423709ee2442f0904b284c02d9b9b09639921f
  HTML Author: parazyd <parazyd@dyne.org>
       Date:   Sat, 25 Nov 2017 03:39:35 +0100
       
       implement basic PoC
       
       Diffstat:
         M README.md                           |       1 +
         A crypto.py                           |      27 +++++++++++++++++++++++++++
         A damn.py                             |      84 +++++++++++++++++++++++++++++++
         A dir.py                              |      69 ++++++++++++++++++++++++++++++
       
       4 files changed, 181 insertions(+), 0 deletions(-)
       ---
   DIR diff --git a/README.md b/README.md
       t@@ -20,3 +20,4 @@ Questions
        
        * Handling consensus?
        * How to keep track of node status?
       +* Could the DECODE website could host a directory?
   DIR diff --git a/crypto.py b/crypto.py
       t@@ -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
   DIR diff --git a/damn.py b/damn.py
       t@@ -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()
   DIR diff --git a/dir.py b/dir.py
       t@@ -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)