Merge pull request #24 from vincentmdealmeida/EventSetupDecrypt

The generic functionality of the event_vote page has been replicated …
This commit is contained in:
Vincent 2018-09-05 11:52:59 +01:00 committed by GitHub
commit 7e601a25e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 311 additions and 178 deletions

View file

@ -253,14 +253,16 @@ def event_trustee_setup(request, event_id):
email_key = event.keys.filter(key=access_key)
if email_key.exists() and event.users_trustees.filter(email=email_key[0].user.email).exists():
if TrusteeKey.objects.filter(event=event, user=email_key[0].user).exists():
messages.add_message(request, messages.WARNING, 'You have already submitted your key for this event')
return HttpResponseRedirect(reverse("user_home"))
return render(request, "polls/event_setup.html", {"is_trustee": True,
"can_submit": False,
"access_denied_reason": "You have already submitted your public key for this event. Thank you!"
})
if request.method == "POST":
form = EventSetupForm(request.POST)
# If form data is valid, create a TrusteeKey object with the supplied public key
if form.is_valid():
public_key = request.POST["public_key"]
public_key = request.POST.get("public_key")
key = TrusteeKey.objects.get_or_create(event=event, user=email_key[0].user)[0]
key.key = public_key
key.save()
@ -280,11 +282,18 @@ def event_trustee_setup(request, event_id):
return HttpResponseRedirect(reverse("user_home"))
else:
form = EventSetupForm()
return render(request, "polls/event_setup.html", {"event": event, "form": form, "user_email": email_key[0].user.email})
return render(request, "polls/event_setup.html", {"event": event,
"form": form,
"user_email": email_key[0].user.email,
"is_trustee": True,
"can_submit": True
})
#if no key or is invalid?
messages.add_message(request, messages.WARNING, 'You do not have permission to access: ' + request.path)
return HttpResponseRedirect(reverse("user_home"))
else:
return render(request, "polls/event_setup.html", {"is_trustee": False,
"can_submit": False,
"access_denied_reason": "You do not have permission to access this page."
})
def event_end(request, event_id):
@ -311,11 +320,10 @@ def event_trustee_decrypt(request, event_id):
if email_key.exists() and event.users_trustees.filter(email=trustee.email).exists():
if PartialBallotDecryption.objects.filter(event=event, user=trustee).count() == event.total_num_opts():
warning_msg = 'You have already provided your decryption key for this event - Thank You'
messages.add_message(request, messages.WARNING, warning_msg)
return HttpResponseRedirect(reverse("user_home"))
return render(request, "polls/event_decrypt.html", {"is_trustee": True,
"can_submit": False,
"access_denied_reason": "You have already submitted your partial decryptions for this event. Thank you!"
})
elif request.method == "GET":
# Get the Trustee's original PK - used in the template for SK validation
trustee_pk = TrusteeKey.objects.get(event=event, user=trustee).key
@ -344,7 +352,9 @@ def event_trustee_decrypt(request, event_id):
"event": event,
"user_email": trustee.email,
"trustee_pk": trustee_pk,
"poll_ciphers": poll_ciphers
"poll_ciphers": poll_ciphers,
"is_trustee": True,
"can_submit": True
})
elif request.method == "POST":
@ -359,7 +369,7 @@ def event_trustee_decrypt(request, event_id):
input_name = str("")
input_name = "poll-" + str(i) + "-cipher-" + str(j)
part_dec = request.POST[input_name]
part_dec = request.POST.get(input_name)
PartialBallotDecryption.objects.create(event=event,
poll=polls[i],
@ -381,8 +391,10 @@ def event_trustee_decrypt(request, event_id):
return HttpResponseRedirect(reverse("user_home"))
# Without an access key, the client does not have permission to access this page
messages.add_message(request, messages.WARNING, 'You do not have permission to decrypt this Event.')
return HttpResponseRedirect(reverse("user_home"))
return render(request, "polls/event_decrypt.html", {"is_trustee": False,
"can_submit": False,
"access_denied_reason": "You don't have permission to access this page."
})
def manage_questions(request, event_id):

View file

@ -22,6 +22,7 @@
<script src="{% static 'js/event_vote.js' %}" type="text/javascript"></script>
<script src="{% static 'js/vote_audit.js' %}" type="text/javascript"></script>
<script src="{% static 'js/encrypt.js' %}" type="text/javascript"></script>
<script src="{% static 'js/event_setup.js' %}" type="text/javascript"></script>
<script type="text/javascript" src="{% static 'js/core/rand.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/rom_curve.js' %}"></script>
@ -66,73 +67,6 @@
}
function getBytes(arr) {
for(var i = 0; i < arr.length; i++) {
arr[i] = parseInt(arr[i]);
}
return new Uint8Array(arr);
}
//new function
demosEncrypt.decryptSubmitCiphers = function() {
};
//new function
demosEncrypt.generateKeys = function() {
var parameter = $("#event-param").val();
var tempParams = JSON.parse(JSON.parse(parameter).crypto);
//the full objects need to be initalised as per the library, then copy the values we need into it
//I follow Bingsheng's code as to what objects are used in the parameter object
var ctx = new CTX("BN254CX"); //new context we can use
var n = new ctx.BIG();
var g1 = new ctx.ECP();
var g2 = new ctx.ECP2();
//copying the values
n.copy(tempParams.n);
g1.copy(tempParams.g1);
g2.copy(tempParams.g2);
var params = {
n:n,
g1:g1,
g2:g2
}
var PKbytes = [];
var SKbytes = [];
var keypair = keyGen(params);
keypair.PK.toBytes(PKbytes);
keypair.SK.toBytes(SKbytes);
var PKB64Encoded = "";
for(let i = 0; i < PKbytes.length; i++) {
PKB64Encoded += btoa(PKbytes[i]);
}
var SKB64Encoded = "";
for(let j = 0; j < SKbytes.length; j++) {
SKB64Encoded += btoa(SKbytes[j]);
}
$('input#public-key').val(PKB64Encoded);
$('input#secret-key').val(SKB64Encoded);
//mostly code from before here
var blob = new Blob([SKB64Encoded], {type : 'text/plain'});
var dlBtn = $('a#download-btn');
var url = URL.createObjectURL(blob);
var fileName = $(dlBtn).attr("href", url);
$(dlBtn).attr("download", "sk-{% block sk-file-name %}{% endblock %}".replace(/[\W]/g, "-"));
$(dlBtn).attr("disabled", false);
$("#public-submit").attr("disabled", false);
}
//these other functions might not be used
//I don't think this is used
demosEncrypt.downloadSecretKey = function() {

View file

@ -4,77 +4,86 @@
{% block sk-file-name %}{{ event.title|safe }}{% endblock %}
{% block content %}
<script type="text/javascript">
// This is what we expect the SK supplied by the trustee to generate
var trustee_pk = "{{ trustee_pk }}";
var tempParams = "{{ event.EID_crypto|escapejs }}";
tempParams = JSON.parse(tempParams);
</script>
{% if is_trustee and can_submit %}
<script type="text/javascript">
// This is what we expect the SK supplied by the trustee to generate
var trustee_pk = "{{ trustee_pk }}";
<div class="container">
<h2>Trustee Event Decryption for Event '{{ event.title }}'</h2>
<hr/>
<div class="panel panel-default">
<div class="panel-heading"><strong>Upload your Secret Key as '{{ user_email }}'</strong></div>
<div class="panel panel-body">
<input id="secret-key" name="secret-key" class="textinput textInput form-control" type="text" disabled/>
<div class="alert alert-info" role="alert" style="margin-top: 0.75em;">
Your secret key will be used to decrypt the event and get a vote tally for every poll.
It won't be sent to the server.
var tempParams = "{{ event.EID_crypto|escapejs }}";
tempParams = JSON.parse(tempParams);
</script>
<div class="container">
<h2>Trustee Event Decryption for Event '{{ event.title }}'</h2>
<hr/>
<div class="panel panel-default">
<div class="panel-heading"><strong>Upload your Secret Key as '{{ user_email }}'</strong></div>
<div class="panel panel-body">
<input id="secret-key" name="secret-key" class="textinput textInput form-control" type="text" disabled/>
<div class="alert alert-info" role="alert" style="margin-top: 0.75em;">
Your secret key will be used to decrypt the event and get a vote tally for every poll.
It won't be sent to the server.
</div>
<label for="files_sk_upload" class="btn btn-primary">
<span class="glyphicon glyphicon-cloud-upload"></span>
Upload Key
</label>
<input type="file" id="files_sk_upload" name="file" class="btn-info">
</div>
<label for="files_sk_upload" class="btn btn-primary">
<span class="glyphicon glyphicon-cloud-upload"></span>
Upload Key
</label>
<input type="file" id="files_sk_upload" name="file" class="btn-info">
</div>
<br/>
<div class="panel-heading"><strong>Encrypted Event Data</strong></div>
<div class="panel panel-body">
<form id="cipher-form" method="POST">
{% csrf_token %}
{% for opts_ciphers in poll_ciphers %}
{% for cipher in opts_ciphers %}
<input id="cipher"
name="poll-{{ forloop.parentloop.counter0 }}-cipher-{{ forloop.counter0 }}"
class="textinput textInput form-control"
type="text"
value="{ &quot;C1&quot;: &quot;{{ cipher.C1 }}&quot;, &quot;C2&quot;: &quot;{{ cipher.C2 }}&quot; }"
/>
<br/>
<div class="panel-heading"><strong>Encrypted Event Data</strong></div>
<div class="panel panel-body">
<form id="cipher-form" method="POST">
{% csrf_token %}
{% for opts_ciphers in poll_ciphers %}
{% for cipher in opts_ciphers %}
<input id="cipher"
name="poll-{{ forloop.parentloop.counter0 }}-cipher-{{ forloop.counter0 }}"
class="textinput textInput form-control"
type="text"
value="{ &quot;C1&quot;: &quot;{{ cipher.C1 }}&quot;, &quot;C2&quot;: &quot;{{ cipher.C2 }}&quot; }"
/>
<br/>
{% endfor %}
<br/>
{% endfor %}
<br/>
{% endfor %}
<button id="decrypt-btn"
onclick="decryptSubmitCiphers()"
class="btn btn-success">
Send Partial Decryptions</button>
</form>
<button id="decrypt-btn"
type="button"
onclick="decryptSubmit()"
class="btn btn-success">
Send Partial Decryptions</button>
</form>
</div>
</div>
</div>
</div>
<!-- Information Dialog called upon request -->
<div class="modal fade" id="modalDialog" role="dialog" tabindex="-1" data-backdrop="static">
<div class="modal-dialog" role="document">
<!-- Dialog content-->
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" style="text-align: center"><strong>Partial Decryption Successfully Received</strong></h4>
</div>
<div class="modal-body">
<p>Thank you! You can now close down this page.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<!-- Information Dialog called upon request -->
<div class="modal fade" id="EventDecryptionModalDialog" role="dialog" tabindex="-1" data-backdrop="static">
<div class="modal-dialog" role="document">
<!-- Dialog content-->
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" style="text-align: center"><strong>Partial Decryptions Successfully Received</strong></h4>
</div>
<div class="modal-body">
<p>Thank you! You can now close down this page.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
{% else %}
<div class="container">
<div class="alert alert-warning" role="alert">
<p>{{ access_denied_reason }}</p>
</div>
</div>
{% endif %}
{% endblock %}

View file

@ -6,34 +6,66 @@
{% block content %}
<div class="container">
<h2>Trustee Event Setup for Event '{{ event.title }}'</h2>
<hr/>
<h4>Key Generation For: {{ user_email }}</h4>
<br/>
<div class="panel panel-default">
<div class="panel-heading"><strong>Step 1: Generate and Download Your Secret Key</strong></div>
<div class="panel panel-body">
<input id="secret-key" class="textinput textInput form-control" type="text"/>
<input id="event-param" type="text" value="{{event.EID}}" hidden/>
<div class="alert alert-warning" role="alert" style="margin-top: 0.75em;">
<strong>Warning:</strong> This key can <strong>NOT</strong> be recalculated if forgotten or lost! Ensure you back this up.
<script type="text/javascript">
var EVENT_TITLE = "{{ event.title|safe }}";
</script>
{% if is_trustee and can_submit %}
<div class="container">
<h2>Trustee Event Setup for Event '{{ event.title }}'</h2>
<hr/>
<h4>Key Generation For: {{ user_email }}</h4>
<br/>
<div class="panel panel-default">
<div class="panel-heading"><strong>Step 1: Generate and Download Your Secret Key</strong></div>
<div class="panel panel-body">
<input id="secret-key" class="textinput textInput form-control" type="text"/>
<input id="event-param" type="text" value="{{event.EID}}" hidden/>
<div class="alert alert-warning" role="alert" style="margin-top: 0.75em;">
<strong>Warning:</strong> This key can <strong>NOT</strong> be recalculated if forgotten or lost! Ensure you back this up.
</div>
<button id="keygen-btn" onclick="generateKeys()" class="btn btn-success">Generate</button>
<a id="download-btn" role="button" href="#" class="btn btn-primary" disabled>Download</a>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading"><strong>Step 2: Submit Your Public Key</strong></div>
<div class="panel panel-body">
{% load crispy_forms_tags %}
<form method="post" action="" class="">
{% crispy form %}
<p>Ensure your secret key is backed up before submitting.</p>
<button id="public-submit" class="btn btn-danger" type="button" onclick="submitPublicKey()" disabled>Submit</button>
</form>
</div>
</div>
<button id="keygen-btn" onclick="demosEncrypt.generateKeys()" class="btn btn-success">Generate</button>
<a id="download-btn" role="button" href="#" class="btn btn-primary" disabled>Download</a>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading"><strong>Step 2: Submit Your Public Key</strong></div>
<div class="panel panel-body">
{% load crispy_forms_tags %}
<form method="post" action="" class="">
{% crispy form %}
<p>Ensure your secret key is backed up before submitting.</p>
<input id="public-submit" class="btn btn-danger" type="submit" value="Submit" disabled/>
</form>
<!-- Information Dialog called upon request -->
<div class="modal fade" id="EventSetupModalDialog" role="dialog" tabindex="-1" data-backdrop="static">
<div class="modal-dialog" role="document">
<!-- Dialog content-->
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" style="text-align: center"><strong>Public Key Successfully Received</strong></h4>
</div>
<div class="modal-body">
<p>Thank you! You can now close down this page.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
</div>
{% else %}
<div class="container">
<div class="alert alert-warning" role="alert">
<p>{{ access_denied_reason }}</p>
</div>
</div>
{% endif %}
{% endblock %}

View file

@ -1,6 +1,7 @@
// -------------- Global vars --------------------
var filesHandleSK = document.getElementById('files_sk_upload');
var CSRF = $( "input[name='csrfmiddlewaretoken']" ).val();
var partialDecryptions = {};
// -------------- Helper fns --------------------
//SK checking algorithm - If PK and SK matches, it returns True; otherwise, it returns false.
@ -15,6 +16,14 @@ function csrfSafeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function getBytes(arr) {
for(var i = 0; i < arr.length; i++) {
arr[i] = parseInt(arr[i]);
}
return new Uint8Array(arr);
}
function getKeyBytes(key, byteArray) {
for(let i = 0; i < key.length; i += 4) {
let B64EncodedByte = key.substring(i, i + 4);
@ -23,8 +32,8 @@ function getKeyBytes(key, byteArray) {
}
}
function showDialog(titleTxt, bodyTxt) {
var modalDialog = $('#modalDialog');
function showDecryptDialog(titleTxt, bodyTxt) {
var modalDialog = $('#EventDecryptionModalDialog');
var title = modalDialog.find('.modal-title');
var body = modalDialog.find('.modal-body');
@ -79,7 +88,7 @@ function validateSKFromString(SKStr) {
return skCheck(ctx, params, sk, pk);
}
function decryptSubmitCiphers() {
function decryptSubmit() {
var skString = $('#secret-key').val();
if (!skString) {
@ -96,7 +105,6 @@ function decryptSubmitCiphers() {
inputs.each(function() { //for each ciphertext to decrypt
let input = $(this);
console.log(input.attr('name'));
var ciphertext = {
C1: null,
@ -116,10 +124,38 @@ function decryptSubmitCiphers() {
var bytes = [];
partial.D.toBytes(bytes);
input.val(bytes.toString());
partialDecryptions[input.attr('name')] = bytes.toString();
});
submitPartialDecryptions();
}
}
function onAfterPartialDecryptionsSend() {
showDecryptDialog('Partial Decryptions Successfully Received',
'Thank you! You can now close down this page.');
}
function submitPartialDecryptions() {
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", CSRF);
}
}
});
$.ajax({
type : "POST",
url : window.location,
data : partialDecryptions,
success : function(){
onAfterPartialDecryptionsSend();
}
});
}
function processFileSKChange(event) {
var files = event.target.files;
@ -153,4 +189,9 @@ function processFileSKChange(event) {
if(filesHandleSK) {
filesHandleSK.addEventListener('change', processFileSKChange, false);
}
}
$('#EventDecryptionModalDialog').on('hide.bs.modal', function (e) {
// Update page to reflect the fact that the PK submission has taken place
location.reload();
});

105
static/js/event_setup.js Normal file
View file

@ -0,0 +1,105 @@
var CSRF = $( "input[name='csrfmiddlewaretoken']" ).val();
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function showSetupDialog(titleTxt, bodyTxt) {
var modalDialog = $('#EventSetupModalDialog');
var title = modalDialog.find('.modal-title');
var body = modalDialog.find('.modal-body');
title.text(titleTxt);
var bodyText = bodyTxt;
var p = document.createElement("p");
p.innerHTML = bodyText;
body.empty();
body.append( p );
modalDialog.modal('show');
}
function generateKeys() {
var parameter = $("#event-param").val();
var tempParams = JSON.parse(JSON.parse(parameter).crypto);
//the full objects need to be initalised as per the library, then copy the values we need into it
//I follow Bingsheng's code as to what objects are used in the parameter object
var ctx = new CTX("BN254CX"); //new context we can use
var n = new ctx.BIG();
var g1 = new ctx.ECP();
var g2 = new ctx.ECP2();
//copying the values
n.copy(tempParams.n);
g1.copy(tempParams.g1);
g2.copy(tempParams.g2);
var params = {
n:n,
g1:g1,
g2:g2
}
var PKbytes = [];
var SKbytes = [];
var keypair = keyGen(params);
keypair.PK.toBytes(PKbytes);
keypair.SK.toBytes(SKbytes);
var PKB64Encoded = "";
for(let i = 0; i < PKbytes.length; i++) {
PKB64Encoded += btoa(PKbytes[i]);
}
var SKB64Encoded = "";
for(let j = 0; j < SKbytes.length; j++) {
SKB64Encoded += btoa(SKbytes[j]);
}
$('input#public-key').val(PKB64Encoded);
$('input#secret-key').val(SKB64Encoded);
//mostly code from before here
var blob = new Blob([SKB64Encoded], {type : 'text/plain'});
var dlBtn = $('a#download-btn');
var url = URL.createObjectURL(blob);
$(dlBtn).attr("href", url);
let fileName = "sk-" + EVENT_TITLE.replace(/[\W]/g, "-");
$(dlBtn).attr("download", fileName);
$(dlBtn).attr("disabled", false);
$("#public-submit").attr("disabled", false);
}
function onAfterKeySend() {
showSetupDialog('Public Key Successfully Received',
'Thank you! You can now close down this page.');
}
function submitPublicKey() {
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", CSRF);
}
}
});
$.ajax({
type : "POST",
url : window.location,
data : { public_key: $('input#public-key').val() },
success : function(){
onAfterKeySend();
}
});
}
$('#EventSetupModalDialog').on('hide.bs.modal', function (e) {
// Update page to reflect the fact that the PK submission has taken place
location.reload();
});