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) 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 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(): 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 render(request, "polls/event_setup.html", {"is_trustee": True,
return HttpResponseRedirect(reverse("user_home")) "can_submit": False,
"access_denied_reason": "You have already submitted your public key for this event. Thank you!"
})
if request.method == "POST": if request.method == "POST":
form = EventSetupForm(request.POST) form = EventSetupForm(request.POST)
# If form data is valid, create a TrusteeKey object with the supplied public key # If form data is valid, create a TrusteeKey object with the supplied public key
if form.is_valid(): 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 = TrusteeKey.objects.get_or_create(event=event, user=email_key[0].user)[0]
key.key = public_key key.key = public_key
key.save() key.save()
@ -280,11 +282,18 @@ def event_trustee_setup(request, event_id):
return HttpResponseRedirect(reverse("user_home")) return HttpResponseRedirect(reverse("user_home"))
else: else:
form = EventSetupForm() 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? else:
messages.add_message(request, messages.WARNING, 'You do not have permission to access: ' + request.path) return render(request, "polls/event_setup.html", {"is_trustee": False,
return HttpResponseRedirect(reverse("user_home")) "can_submit": False,
"access_denied_reason": "You do not have permission to access this page."
})
def event_end(request, event_id): 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 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(): if PartialBallotDecryption.objects.filter(event=event, user=trustee).count() == event.total_num_opts():
return render(request, "polls/event_decrypt.html", {"is_trustee": True,
warning_msg = 'You have already provided your decryption key for this event - Thank You' "can_submit": False,
messages.add_message(request, messages.WARNING, warning_msg) "access_denied_reason": "You have already submitted your partial decryptions for this event. Thank you!"
})
return HttpResponseRedirect(reverse("user_home"))
elif request.method == "GET": elif request.method == "GET":
# Get the Trustee's original PK - used in the template for SK validation # Get the Trustee's original PK - used in the template for SK validation
trustee_pk = TrusteeKey.objects.get(event=event, user=trustee).key trustee_pk = TrusteeKey.objects.get(event=event, user=trustee).key
@ -344,7 +352,9 @@ def event_trustee_decrypt(request, event_id):
"event": event, "event": event,
"user_email": trustee.email, "user_email": trustee.email,
"trustee_pk": trustee_pk, "trustee_pk": trustee_pk,
"poll_ciphers": poll_ciphers "poll_ciphers": poll_ciphers,
"is_trustee": True,
"can_submit": True
}) })
elif request.method == "POST": elif request.method == "POST":
@ -359,7 +369,7 @@ def event_trustee_decrypt(request, event_id):
input_name = str("") input_name = str("")
input_name = "poll-" + str(i) + "-cipher-" + str(j) 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, PartialBallotDecryption.objects.create(event=event,
poll=polls[i], poll=polls[i],
@ -381,8 +391,10 @@ def event_trustee_decrypt(request, event_id):
return HttpResponseRedirect(reverse("user_home")) return HttpResponseRedirect(reverse("user_home"))
# Without an access key, the client does not have permission to access this page # 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 render(request, "polls/event_decrypt.html", {"is_trustee": False,
return HttpResponseRedirect(reverse("user_home")) "can_submit": False,
"access_denied_reason": "You don't have permission to access this page."
})
def manage_questions(request, event_id): 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/event_vote.js' %}" type="text/javascript"></script>
<script src="{% static 'js/vote_audit.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/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/rand.js' %}"></script>
<script type="text/javascript" src="{% static 'js/core/rom_curve.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 //these other functions might not be used
//I don't think this is used //I don't think this is used
demosEncrypt.downloadSecretKey = function() { demosEncrypt.downloadSecretKey = function() {

View file

@ -4,6 +4,8 @@
{% block sk-file-name %}{{ event.title|safe }}{% endblock %} {% block sk-file-name %}{{ event.title|safe }}{% endblock %}
{% block content %} {% block content %}
{% if is_trustee and can_submit %}
<script type="text/javascript"> <script type="text/javascript">
// This is what we expect the SK supplied by the trustee to generate // This is what we expect the SK supplied by the trustee to generate
var trustee_pk = "{{ trustee_pk }}"; var trustee_pk = "{{ trustee_pk }}";
@ -48,8 +50,8 @@
<br/> <br/>
{% endfor %} {% endfor %}
<button id="decrypt-btn" <button id="decrypt-btn"
type="button"
onclick="decryptSubmitCiphers()" onclick="decryptSubmit()"
class="btn btn-success"> class="btn btn-success">
Send Partial Decryptions</button> Send Partial Decryptions</button>
</form> </form>
@ -58,13 +60,13 @@
</div> </div>
<!-- Information Dialog called upon request --> <!-- Information Dialog called upon request -->
<div class="modal fade" id="modalDialog" role="dialog" tabindex="-1" data-backdrop="static"> <div class="modal fade" id="EventDecryptionModalDialog" role="dialog" tabindex="-1" data-backdrop="static">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<!-- Dialog content--> <!-- Dialog content-->
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h4 class="modal-title" style="text-align: center"><strong>Partial Decryption Successfully Received</strong></h4> <h4 class="modal-title" style="text-align: center"><strong>Partial Decryptions Successfully Received</strong></h4>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<p>Thank you! You can now close down this page.</p> <p>Thank you! You can now close down this page.</p>
@ -76,5 +78,12 @@
</div> </div>
</div> </div>
{% else %}
<div class="container">
<div class="alert alert-warning" role="alert">
<p>{{ access_denied_reason }}</p>
</div>
</div>
{% endif %}
{% endblock %} {% endblock %}

View file

@ -6,6 +6,11 @@
{% block content %} {% block content %}
<script type="text/javascript">
var EVENT_TITLE = "{{ event.title|safe }}";
</script>
{% if is_trustee and can_submit %}
<div class="container"> <div class="container">
<h2>Trustee Event Setup for Event '{{ event.title }}'</h2> <h2>Trustee Event Setup for Event '{{ event.title }}'</h2>
<hr/> <hr/>
@ -19,7 +24,7 @@
<div class="alert alert-warning" role="alert" style="margin-top: 0.75em;"> <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. <strong>Warning:</strong> This key can <strong>NOT</strong> be recalculated if forgotten or lost! Ensure you back this up.
</div> </div>
<button id="keygen-btn" onclick="demosEncrypt.generateKeys()" class="btn btn-success">Generate</button> <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> <a id="download-btn" role="button" href="#" class="btn btn-primary" disabled>Download</a>
</div> </div>
</div> </div>
@ -30,10 +35,37 @@
<form method="post" action="" class=""> <form method="post" action="" class="">
{% crispy form %} {% crispy form %}
<p>Ensure your secret key is backed up before submitting.</p> <p>Ensure your secret key is backed up before submitting.</p>
<input id="public-submit" class="btn btn-danger" type="submit" value="Submit" disabled/> <button id="public-submit" class="btn btn-danger" type="button" onclick="submitPublicKey()" disabled>Submit</button>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
<!-- 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>
{% else %}
<div class="container">
<div class="alert alert-warning" role="alert">
<p>{{ access_denied_reason }}</p>
</div>
</div>
{% endif %}
{% endblock %} {% endblock %}

View file

@ -1,6 +1,7 @@
// -------------- Global vars -------------------- // -------------- Global vars --------------------
var filesHandleSK = document.getElementById('files_sk_upload'); var filesHandleSK = document.getElementById('files_sk_upload');
var CSRF = $( "input[name='csrfmiddlewaretoken']" ).val(); var CSRF = $( "input[name='csrfmiddlewaretoken']" ).val();
var partialDecryptions = {};
// -------------- Helper fns -------------------- // -------------- Helper fns --------------------
//SK checking algorithm - If PK and SK matches, it returns True; otherwise, it returns false. //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)); 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) { function getKeyBytes(key, byteArray) {
for(let i = 0; i < key.length; i += 4) { for(let i = 0; i < key.length; i += 4) {
let B64EncodedByte = key.substring(i, i + 4); let B64EncodedByte = key.substring(i, i + 4);
@ -23,8 +32,8 @@ function getKeyBytes(key, byteArray) {
} }
} }
function showDialog(titleTxt, bodyTxt) { function showDecryptDialog(titleTxt, bodyTxt) {
var modalDialog = $('#modalDialog'); var modalDialog = $('#EventDecryptionModalDialog');
var title = modalDialog.find('.modal-title'); var title = modalDialog.find('.modal-title');
var body = modalDialog.find('.modal-body'); var body = modalDialog.find('.modal-body');
@ -79,7 +88,7 @@ function validateSKFromString(SKStr) {
return skCheck(ctx, params, sk, pk); return skCheck(ctx, params, sk, pk);
} }
function decryptSubmitCiphers() { function decryptSubmit() {
var skString = $('#secret-key').val(); var skString = $('#secret-key').val();
if (!skString) { if (!skString) {
@ -96,7 +105,6 @@ function decryptSubmitCiphers() {
inputs.each(function() { //for each ciphertext to decrypt inputs.each(function() { //for each ciphertext to decrypt
let input = $(this); let input = $(this);
console.log(input.attr('name'));
var ciphertext = { var ciphertext = {
C1: null, C1: null,
@ -116,10 +124,38 @@ function decryptSubmitCiphers() {
var bytes = []; var bytes = [];
partial.D.toBytes(bytes); partial.D.toBytes(bytes);
input.val(bytes.toString()); 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) { function processFileSKChange(event) {
var files = event.target.files; var files = event.target.files;
@ -154,3 +190,8 @@ function processFileSKChange(event) {
if(filesHandleSK) { if(filesHandleSK) {
filesHandleSK.addEventListener('change', processFileSKChange, false); 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();
});