commit 9ebcc235e967e4998e86125edee43ae2cf5e1ad8
parent e0423709ee2442f0904b284c02d9b9b09639921f
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(-)
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)