ajg
This commit is contained in:
parent
dff885437e
commit
08b5985396
9 changed files with 704 additions and 562 deletions
|
@ -21,5 +21,6 @@ urlpatterns = [
|
||||||
url(r'^(?P<event_id>[0-9a-f-]+)/poll/(?P<poll_id>[0-9a-f-]+)/vote/$', views.event_vote, name='event-vote'),
|
url(r'^(?P<event_id>[0-9a-f-]+)/poll/(?P<poll_id>[0-9a-f-]+)/vote/$', views.event_vote, name='event-vote'),
|
||||||
url(r'^(?P<event_id>[0-9a-f-]+)/create/poll/$', login_required(views.manage_questions), name='create-poll'),
|
url(r'^(?P<event_id>[0-9a-f-]+)/create/poll/$', login_required(views.manage_questions), name='create-poll'),
|
||||||
url(r'^(?P<event_id>[0-9a-f-]+)/poll/(?P<poll_id>[0-9a-f-]+)/edit$', login_required(views.edit_poll), name='edit-poll'),
|
url(r'^(?P<event_id>[0-9a-f-]+)/poll/(?P<poll_id>[0-9a-f-]+)/edit$', login_required(views.edit_poll), name='edit-poll'),
|
||||||
url(r'^audit/$', views.vote_audit, name='vote_audit')
|
url(r'^audit/$', views.vote_audit, name='vote_audit'),
|
||||||
|
url(r'^find_ballot/$', views.find_ballot, name='find_ballot')
|
||||||
]
|
]
|
||||||
|
|
|
@ -117,11 +117,41 @@ def edit_poll(request, event_id, poll_id):
|
||||||
|
|
||||||
|
|
||||||
def vote_audit(request):
|
def vote_audit(request):
|
||||||
encrypted_ballot = get_object_or_404(EncBallot, handle=''+urllib.quote_plus(request.GET.get('handle', None)))
|
handle1 = request.GET.get('handle1', None)
|
||||||
|
handle2 = request.GET.get('handle2', None)
|
||||||
|
vars = {}
|
||||||
|
|
||||||
|
if handle:
|
||||||
|
encrypted_ballot1 = get_object_or_404(EncBallot, handle=''+urllib.quote_plus(handle1))
|
||||||
|
|
||||||
|
if handle2:
|
||||||
|
encrypted_ballot2 = get_object_or_404(EncBallot, handle=''+urllib.quote_plus(handle2))
|
||||||
|
|
||||||
return render(request, "polls/vote_audit.html",
|
return render(request, "polls/vote_audit.html",
|
||||||
{
|
{
|
||||||
"ballot": encrypted_ballot.ballot
|
"handle1": handle1,
|
||||||
|
"ballot1": encrypted_ballot1.ballot,
|
||||||
|
"handle2": handle2,
|
||||||
|
"ballot2": encrypted_ballot2.ballot
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def find_ballot(request):
|
||||||
|
voter_id = request.GET.get('vid', None)
|
||||||
|
poll_id = request.GET.get('pid', None)
|
||||||
|
ballot = get_object_or_404(Ballot, voter=voter_id, poll=poll_id)
|
||||||
|
hash1 = request.GET.get('hash1', None)
|
||||||
|
hash2 = request.GET.get('hash2', None)
|
||||||
|
|
||||||
|
if not ballot.cast:
|
||||||
|
messages.add_message(request, messages.WARNING, "This ballot has not been cast.")
|
||||||
|
return HttpResponseRedirect(reverse("user_home"))
|
||||||
|
|
||||||
|
return render(request, "polls/find_ballot.html",
|
||||||
|
{
|
||||||
|
"ballot": ballot.json_str,
|
||||||
|
"hash1": hash1,
|
||||||
|
"hash2": hash2
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
<script src="{% static 'js/decrypt_event.js' %}" type="text/javascript"></script>
|
<script src="{% static 'js/decrypt_event.js' %}" type="text/javascript"></script>
|
||||||
<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/find_ballot.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 src="{% static 'js/event_setup.js' %}" type="text/javascript"></script>
|
||||||
|
|
||||||
|
|
11
allauthdemo/templates/polls/find_ballot.html
Normal file
11
allauthdemo/templates/polls/find_ballot.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{% extends "bases/bootstrap-with-nav.html" %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<pre hidden id="ballot_found">{{ ballot }}</pre>
|
||||||
|
<pre hidden id="ballot_hashes">{{ hash1 }};{{ hash2 }}</pre>
|
||||||
|
<h1 id="ballot_result"></h1>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -4,15 +4,31 @@
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<input id="SK" value="temporary" type="text"/>
|
<label class="gp-1" for="handle1">Ballot #1 handle:</label>
|
||||||
<button id="begin-test">Verify Ballot</button>
|
<input class="gp-1" id="handle1" value="{{ handle1 }}" type="text"/>
|
||||||
<br>
|
<label class="gp-1" for="handle2">Ballot handle:</label>
|
||||||
<br>
|
<input class="gp-1" id="handle2" value="{{ handle2 }}" type="text"/>
|
||||||
<label for="ballot">AES-encrypted ballot from server</label>
|
<button class="gp-1" id="retrieve-ballots">Retrieve Ballots</button>
|
||||||
<pre id="ballot">{{ ballot }}</pre>
|
|
||||||
<label for="ballot-content">Decrypted ballot</label>
|
<hr>
|
||||||
<pre id="ballot-content"></pre>
|
|
||||||
<label for="ballot">Ballot encoding</label>
|
<label class="gp-2" for="ballot1">AES-encrypted ballot #1 from server</label>
|
||||||
<pre id="ballot-result"></pre>
|
<pre class="gp-2" id="ballot1">{{ ballot }}</pre>
|
||||||
|
<input class="gp-2" id="SK1" value="temporary" type="text"/>
|
||||||
|
<button class="gp-2" id="decrypt-ballot1">Decrypt Ballot</button>
|
||||||
|
<label class="gp-3" for="ballot-content1">Decrypted ballot</label>
|
||||||
|
<pre class="gp-3" id="ballot-content1"></pre>
|
||||||
|
<label class="gp-3" for="ballot-result1">Ballot encoding</label>
|
||||||
|
<pre class="gp-3" id="ballot-result1"></pre>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<label class="gp-2" for="ballot2">AES-encrypted ballot #2 from server</label>
|
||||||
|
<pre class="gp-2" id="ballot2">{{ ballot2 }}</pre>
|
||||||
|
<input class="gp-2" id="SK2" value="temporary" type="text"/>
|
||||||
|
<button class="gp-2" id="decrypt-ballot2">Decrypt Ballot</button>
|
||||||
|
<label class="gp-3" for="ballot-content2">Decrypted ballot</label>
|
||||||
|
<pre class="gp-3" id="ballot-content2"></pre>
|
||||||
|
<label class="gp-3" for="ballot-result2">Ballot encoding</label>
|
||||||
|
<pre class="gp-3" id="ballot-result2"></pre>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -328,12 +328,51 @@ function generateBallots() {
|
||||||
var ballotB = generateBallot();
|
var ballotB = generateBallot();
|
||||||
progressBar.setAttribute("style", "width: 100%;");
|
progressBar.setAttribute("style", "width: 100%;");
|
||||||
|
|
||||||
showFirstQRCode(ballotA, ballotB, selectedOption);
|
showIDsQRCode(ballotA, ballotB, selectedOption);
|
||||||
}, 150);
|
}, 150);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showIDsQRCode(ballotA, ballotB, selectedOption) {
|
||||||
|
var voterID = window.location.search.slice(1).split(/=(.+)/)[1];
|
||||||
|
var eventID = window.location.href.split('/')[4];
|
||||||
|
var pollID = $('#poll-num').text();
|
||||||
|
|
||||||
|
// Display a QR code with ID details
|
||||||
|
var modalDialog = $('#modalDialog');
|
||||||
|
var title = modalDialog.find('.modal-title');
|
||||||
|
var body = modalDialog.find('.modal-body');
|
||||||
|
|
||||||
|
body.empty();
|
||||||
|
title.text('Step 0 of 3: Scan this');
|
||||||
|
|
||||||
|
let pleaseScanP = document.createElement('p');
|
||||||
|
pleaseScanP.innerHTML = "Please scan the following QR code from your DEMOS 2 mobile application:";
|
||||||
|
|
||||||
|
let QRDiv = document.createElement('div');
|
||||||
|
var QRCodeImg = document.createElement('img');
|
||||||
|
QRCodeImg.setAttribute('class', 'QR-code');
|
||||||
|
QRCodeImg.setAttribute('id', "qr-img");
|
||||||
|
new QRCode(QRCodeImg, voterID+";"+eventID+";"+pollID);
|
||||||
|
QRDiv.append(QRCodeImg);
|
||||||
|
|
||||||
|
body.append(pleaseScanP);
|
||||||
|
body.append(QRDiv);
|
||||||
|
|
||||||
|
// Prepare the appropriate dialog buttons
|
||||||
|
updateDialogButtons(DIALOG_BTN_STATES.STEP_1);
|
||||||
|
|
||||||
|
if(!dialogOpen) {
|
||||||
|
modalDialog.modal('toggle');
|
||||||
|
dialogOpen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#nextDialogBtn').click(function(e) {
|
||||||
|
showHashQRCode(ballotA, ballotB, selectedOption);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Called in stage 1 of 3 in the voting process
|
// Called in stage 1 of 3 in the voting process
|
||||||
function showFirstQRCode(ballotA, ballotB, selectedOption) {
|
function showHashQRCode(ballotA, ballotB, selectedOption) {
|
||||||
var ballots = new Array(ballotA, ballotB);
|
var ballots = new Array(ballotA, ballotB);
|
||||||
var ballotHashes = new Array(2);
|
var ballotHashes = new Array(2);
|
||||||
|
|
||||||
|
@ -350,7 +389,7 @@ function showFirstQRCode(ballotA, ballotB, selectedOption) {
|
||||||
title.text('Step 1 of 3: Link Your Vote');
|
title.text('Step 1 of 3: Link Your Vote');
|
||||||
|
|
||||||
let pleaseScanP = document.createElement('p');
|
let pleaseScanP = document.createElement('p');
|
||||||
pleaseScanP.innerHTML = "Please scan the following QR code from your DEMOS 2 mobile application:";
|
pleaseScanP.innerHTML = "Please scan the following QR code from your DEMOS 2 auditor:";
|
||||||
|
|
||||||
let QRDiv = document.createElement('div');
|
let QRDiv = document.createElement('div');
|
||||||
var QRCodeImg = document.createElement('img');
|
var QRCodeImg = document.createElement('img');
|
||||||
|
@ -551,19 +590,22 @@ function sendBallotsToServer(selection, selectedBallot, otherBallot) {
|
||||||
var pk = new ctx.ECP(0);
|
var pk = new ctx.ECP(0);
|
||||||
pk.copy(tempPK.PK);
|
pk.copy(tempPK.PK);
|
||||||
|
|
||||||
var voterID = window.location.search.slice(1).split(/=(.+)/)[1];//.slice(0, -2);
|
// Prepares the unselected ballot to send, encrypted, to the server.
|
||||||
|
// Creates the unique ballot ID for the unselected ballot
|
||||||
|
var voterID = window.location.search.slice(1).split(/=(.+)/)[1];
|
||||||
var eventID = window.location.href.split('/')[4];
|
var eventID = window.location.href.split('/')[4];
|
||||||
var pollNum = $('#poll-num').text();
|
var pollNum = $('#poll-num').text();
|
||||||
var ballotID = encodeURIComponent(btoa(JSON.stringify({voterID: voterID, eventID: eventID, pollNum: pollNum})));
|
var ballotID = encodeURIComponent(btoa(JSON.stringify({voterID: voterID, eventID: eventID, pollNum: pollNum})));
|
||||||
|
|
||||||
// TODO: Generate a SK rather than using a static one. UUID generated server side and then injected JS side?
|
// TODO: Generate a SK rather than using a static one. UUID generated server side and then injected JS side?
|
||||||
JSON.stringify(otherBallot)
|
|
||||||
var SK = "temporary";
|
var SK = "temporary";
|
||||||
var encAlt = sjcl.encrypt(SK, JSON.stringify(otherBallot));
|
var encAlt = sjcl.encrypt(SK, JSON.stringify({ballotID: ballotID, ballot: otherBallot}));
|
||||||
|
|
||||||
|
// Generates an HMAC to protect the encrypted ballot from tampering.
|
||||||
var out = (new sjcl.misc.hmac(key, sjcl.hash.sha256)).mac(encAlt);
|
var out = (new sjcl.misc.hmac(key, sjcl.hash.sha256)).mac(encAlt);
|
||||||
var hmac = sjcl.codec.hex.fromBits(out);
|
var hmac = sjcl.codec.hex.fromBits(out);
|
||||||
let selectedBallotAsStr = JSON.stringify(selectedBallot);
|
|
||||||
|
|
||||||
|
// Prepares the selected ballot to submit to the server.
|
||||||
|
let selectedBallotAsStr = JSON.stringify(selectedBallot);
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type : "POST",
|
type : "POST",
|
||||||
url : window.location,
|
url : window.location,
|
||||||
|
@ -593,7 +635,7 @@ function onAfterBallotSend(ballotID, SK, hmac) {
|
||||||
instructions1P.innerHTML = instructions1Txt;
|
instructions1P.innerHTML = instructions1Txt;
|
||||||
body.append(instructions1P);
|
body.append(instructions1P);
|
||||||
|
|
||||||
// Add the second section: QR code that contains the ballot identifier
|
// Add the second section: QR code that contains the ballot identifier and HMAC
|
||||||
var QRCodeImg = document.createElement('img');
|
var QRCodeImg = document.createElement('img');
|
||||||
QRCodeImg.setAttribute('class', 'QR-code');
|
QRCodeImg.setAttribute('class', 'QR-code');
|
||||||
new QRCode(QRCodeImg, ballotID+";"+btoa(hmac));
|
new QRCode(QRCodeImg, ballotID+";"+btoa(hmac));
|
||||||
|
|
10
static/js/find_ballot.js
Normal file
10
static/js/find_ballot.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
$( document ).ready(function() {
|
||||||
|
ballotHash = SHA256Hash(stringtobytes(JSON.stringify($('#ballot-found').text())), true);
|
||||||
|
var hashes = $('#ballot_hashes').text().split(';');
|
||||||
|
$('#ballot_result').text("Ballot not found!");
|
||||||
|
for (var i = 0; i <= 1; i++) {
|
||||||
|
if (hashes[i] == ballotHash) {
|
||||||
|
$('#ballot_result').text("Ballot found!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -6,6 +6,25 @@ function getBytes(arr) {
|
||||||
return new Uint8Array(arr);
|
return new Uint8Array(arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$( document ).ready(function() {
|
||||||
|
$('.gp-2, .gp-3').hide();
|
||||||
|
var n = 0;
|
||||||
|
for (var i = 0; i <= 1; i++) {
|
||||||
|
if ($('#handle'+i).val() != "") {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n == 2) {
|
||||||
|
$('ballot-group'+i+' .gp-1').css('opacity','0.6');
|
||||||
|
$('#retrieve-ballots').prop('disabled', true);
|
||||||
|
$('ballot-group'+i+' .gp-2').show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#retrieve-ballots').click(function() {
|
||||||
|
window.location = "/audit?handle="+$('#handle1').val()+'&handle2='+$('#handle2').val();
|
||||||
|
});
|
||||||
|
|
||||||
$('#begin-test').click(function() {
|
$('#begin-test').click(function() {
|
||||||
var ctx = new CTX("BN254CX");
|
var ctx = new CTX("BN254CX");
|
||||||
var ciphertext = {
|
var ciphertext = {
|
||||||
|
@ -44,7 +63,19 @@ $('#begin-test').click(function() {
|
||||||
// test whether C2/(C1)^r = g^0 or g^1, and record g's exponent.
|
// test whether C2/(C1)^r = g^0 or g^1, and record g's exponent.
|
||||||
//var c1 = ctx.PAIR.GTpow(ciphertext.C1, ciphertext.r);
|
//var c1 = ctx.PAIR.GTpow(ciphertext.C1, ciphertext.r);
|
||||||
|
|
||||||
var m = ciphertext.C2.div(Math.pow(ciphertext.C1, ciphertext.r));
|
var B;
|
||||||
|
var j;
|
||||||
|
for (j = 0; j <= 1; j++) {
|
||||||
|
//use D as temp var
|
||||||
|
B = new ctx.BIG(j);
|
||||||
|
D = ctx.PAIR.G1mul(params.g1,B);
|
||||||
|
if (D.equals(gM)) {
|
||||||
|
return {
|
||||||
|
M:j
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
console.log("m = "+m);
|
console.log("m = "+m);
|
||||||
encoding += (m) ? "1" : "0";
|
encoding += (m) ? "1" : "0";
|
||||||
|
|
||||||
|
|
Reference in a new issue