Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion dnote/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def index():
"""Return the index.html for the main application."""
error = request.args.get('error', None)
note = Note()
return render_template('index.html', random=note.url, error=error)
return render_template('index.html', note=note, error=error)

@DNOTE.route('/security/', methods=['GET'])
def security():
Expand All @@ -33,6 +33,9 @@ def about():
def show_post():
"""Return the random URL after posting the plaintext."""
new_url = request.form["new_url"]
timestamp = request.form["timestamp"]
signature = request.form["signature"]

note = Note(new_url)
note.plaintext = request.form['paste']

Expand All @@ -42,6 +45,12 @@ def show_post():
if not utils.verify_hashcash(token):
return redirect(url_for('index', error='hashcash'))

try:
note.validate_signature(url=new_url, timestamp=timestamp,
provided_signature=signature)
except Exception as e:
return render_template('signerror.html', error=e)

if passphrase:
note.set_passphrase(passphrase)
note.encrypt()
Expand Down
38 changes: 37 additions & 1 deletion dnote/note.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
import base64
import os
import sys
import time
import zlib
from Crypto.Cipher import AES
from Crypto.Hash import HMAC, SHA512
from Crypto.Hash import HMAC, SHA512, SHA384
from Crypto.Protocol import KDF
from Crypto.Util import Counter

Expand Down Expand Up @@ -60,13 +61,48 @@ class Note(object):
dkey = None # Duress passphrase
plaintext = None # Plain text note
ciphertext = None # Encrypted text
timestamp = None # current time
signature = None # signature

def __init__(self, url=None):
if url is None:
self.create_url()
self.sign_note()
else:
self.decode_url(url)

@staticmethod
def validate_signature(url, timestamp, provided_signature):
# Raise an exception for invalid signature

if url is None or timestamp is None:
raise ValueError("timestamp and/or url are None")

delta = int(time.time()) - int(float(timestamp))
if delta < 0 or delta > dconfig.signature_validity:
raise ValueError("Signature has expired")

computed_signature = Note.get_signature(url=url, timestamp=timestamp)

# FIXME: requires python3.3
#if not HMAC.compare_digest(computed_signature, provided_signature):
if computed_signature != provided_signature:
raise ValueError("Invalid signature provided!")

def sign_note(self):
if self.url is None:
raise ValueError("url has not been set")

self.timestamp = str(time.time())

self.signature = Note.get_signature(url=self.url, timestamp=self.timestamp)

@staticmethod
def get_signature(url, timestamp):
data = "{timestamp}?{url}".format(timestamp=timestamp, url=url)
sig = HMAC.new(dconfig.server_secret, data, SHA384)
return sig.hexdigest()

def exists(self):
"""Checks if note already exists"""
return os.path.exists(self.path())
Expand Down
4 changes: 3 additions & 1 deletion dnote/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ <h1>Self destructing encrypted notes</h1>
{% endif %}
</p>
{% endif %}
<input name="new_url" type="hidden" value="{{ random }}">
<input name="new_url" type="hidden" value="{{ note.url }}"/>
<input name="timestamp" type="hidden" value="{{ note.timestamp }}"/>
<input name="signature" type="hidden" value="{{ note.signature }}"/>
<p>Type or paste your text below:</p>
<textarea style="width:100%; height:250px" id="paste" name="paste"></textarea>
<br/>
Expand Down
7 changes: 7 additions & 0 deletions dnote/templates/signerror.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{% extends "base.html" %}
{% block title %}Signature Error{% endblock %}
{% block content %}
<h1>Error</h1>
<p>Your request appears to have been tampered with. Please try again.</p>
<p>error: {{ error }}</p>
{% endblock %}
2 changes: 2 additions & 0 deletions scripts/generate_dnote_hashes
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,6 @@ if not os.path.exists(dconfig):
f.write('mac_salt = "%s"\n' % os.urandom(16).encode('hex'))
f.write('nonce_salt = "%s"\n' % os.urandom(16).encode('hex'))
f.write('duress_salt = "%s"\n' % os.urandom(16).encode('hex'))
f.write('server_secret = "%s"\n' % os.urandom(64).encode('hex'))
f.write('signature_validity = 300 # seconds\n')
os.chmod(dconfig, 0440)