bitagora-booth
Advanced tools
Comparing version 1.0.4 to 1.0.5
182
booth.js
@@ -1,2 +0,2 @@ | ||
const bitagoraVersion = '1.0.4'; | ||
const bitagoraVersion = '1.0.5'; | ||
const CryptoJS = require('crypto-js'); | ||
@@ -29,8 +29,8 @@ const Ecdsa = require('elliptic'); | ||
class Vote { | ||
constructor(id, ballot, certSig, certKey, voterSig, voterKey, ctx) { | ||
this.id = CryptoJS.SHA1(id).toString(); /* 20 bytes SHA1 hash of ID to guarantee that vote is cast only once */ | ||
constructor(idToken, userId, ballot, certSig, certKey, voterSig, voterKey, ctx) { | ||
this.id = CryptoJS.SHA1(idToken).toString(); /* 20 bytes SHA1 hash of ID to guarantee that vote is cast only once */ | ||
this.options = getOptions(ctx.options); /* 6 bytes - if 2 options: "\xaa\xaa\x00\x01\xaa\xaa" */ | ||
this.questions = Bs58.decode(ctx.options.substr(0,4)).toString('hex') + Bs58.decode(ctx.options.substr(10,4)).toString('hex'); /* 6 bytes : 3 bytes option 1, 3 bytes option 2 decoded from Base58 and in hex */ | ||
this.ballot = 'ffff' + ballot + 'ffff'; /* 5 bytes with padding "\xFFFF" + "\x00" or "\x01" + "\xFFFF" */ | ||
this.idPartial = getIdPartial(id, ctx.idState); /* 3 bytes: 2 bytes partial ID number to guarantee partial ident and check */ | ||
this.idPartial = getIdPartial(userId.substr(15,8), ctx.idState); /* 3 bytes: 2 bytes partial ID number to guarantee partial ident and check */ | ||
this.date = today.getUTCFullYear() + ('0' + (today.getUTCMonth()+1)).slice(-2) + ('0' + today.getUTCDate()).slice(-2); /*4 bytes: date of vote utc format "yyyymmdd" has to match token signed by server */ | ||
@@ -52,3 +52,3 @@ this.certTag = 'f2'; /* 1 byte "\x02" indicating beginning of server signature/pubkey */ | ||
function getOptions(optionString) { | ||
var options = optionString.replace( /^\D+/g, ''); | ||
var options = optionString.replace(/\D/g, ''); | ||
if (options.length > 6 || options.length < 2) return null; | ||
@@ -62,15 +62,13 @@ var string = ''; | ||
case 2: | ||
string = 'aaaa' + options + 'aaaa'; | ||
string = 'aaaa' + string + 'aaaa'; | ||
break; | ||
case 3: | ||
string = 'aaaa' + options + 'aa'; | ||
string = 'aaaa' + string + 'aa'; | ||
break; | ||
case 4: | ||
string = 'aa' + options + 'aa'; | ||
string = 'aa' + string + 'aa'; | ||
break; | ||
case 5: | ||
string = 'aa' + options; | ||
string = 'aa' + string; | ||
break; | ||
default: | ||
string = options; | ||
} | ||
@@ -121,70 +119,49 @@ return string; | ||
function validateVote (vote) { | ||
/* Checks that the vote is valid. Only check not done here is to check that the vote has not been cast already with vote.id */ | ||
/* Also check that the questions and options match the data on genesis block */ | ||
/* Questions bytes 0..4 and 6..9 converted from base58 */ | ||
/* Options bytes that are not "\xaa" */ | ||
/* Finally, check that the vote date is not earlier than the startDate or later than the endDate coded on the genesis block */ | ||
/* Checks that the vote is valid. Only check not done here is to check that the vote has not been cast already with vote.id */ | ||
/* Also check that the questions and options match the data on genesis block */ | ||
/* Questions bytes 0..4 and 6..9 converted from base58 */ | ||
/* Options bytes that are not "\xaa" */ | ||
/* Finally, check that the vote date is not earlier than the startDate or later than the endDate coded on the genesis block */ | ||
var options = vote.options.replace(/a/g, '').match(/.{2}/g); | ||
var included = false; | ||
for (var i = 0; i < options.length; i++) { | ||
if (vote.ballot.substr(4,2) == options[i]) included = true; | ||
} | ||
if (!included) { | ||
console.log('Invalid ballot'); | ||
return false; | ||
} | ||
if (vote.idPartial == null) { | ||
console.log('No id partial'); | ||
return false; | ||
} | ||
var checksum = CryptoJS.SHA256(CryptoJS.SHA256(vote.id + vote.options + vote.questions + vote.ballot + vote.idPartial + vote.date + vote.certTag + vote.certSig + vote.certKeyLength + vote.certKey ) ).toString().substr(0,6); | ||
if (checksum != vote.checkSum) { | ||
console.log('Invalid checksum'); | ||
return false; | ||
} | ||
if (!validateCertSig(vote)) { | ||
console.log('Invalid certifier signature'); | ||
return false; | ||
} | ||
if (!validateVoterSig(vote)) { | ||
console.log('Invalid voter signature'); | ||
return false; | ||
} | ||
return true; | ||
}; | ||
var options = vote.options.replace(/a/g, '').match(/.{2}/g); | ||
var included = false; | ||
for (var i = 0; i < options.length; i++) { | ||
if (vote.ballot.substr(4,2) == options[i]) included = true; | ||
} | ||
if (!included) { | ||
console.log('Invalid ballot'); | ||
return false; | ||
} | ||
if (vote.idPartial == null) { | ||
console.log('No id partial'); | ||
return false; | ||
} | ||
var checksum = CryptoJS.SHA256(CryptoJS.SHA256(vote.id + vote.options + vote.questions + vote.ballot + vote.idPartial + vote.date + vote.certTag + vote.certSig + vote.certKeyLength + vote.certKey ) ).toString().substr(0,6); | ||
if (checksum != vote.checkSum) { | ||
console.log('Invalid checksum'); | ||
return false; | ||
} | ||
if (!validateCertSig(vote)) { | ||
console.log('Invalid certifier signature'); | ||
return false; | ||
} | ||
if (!validateVoterSig(vote)) { | ||
console.log('Invalid voter signature'); | ||
return false; | ||
} | ||
return true; | ||
}; | ||
function generateNewVote (voteData, ctx) { | ||
var id = voteData.id; /* ID introduced by user and certified by server */ | ||
var ballot = voteData.ballot; /* Vote by user with options available */ | ||
var certSig = voteData.certSig; | ||
var certKey = voteData.certKey; | ||
return new Vote(id, ballot, certSig, certKey, null, null, ctx); | ||
}; | ||
var idToken = voteData.id; /* ID token sent by server */ | ||
var userId = voteData.userId; /* ID introduced by user */ | ||
var ballot = voteData.ballot; /* Vote by user with options available */ | ||
var certSig = voteData.certSig; | ||
var certKey = voteData.certKey; | ||
return new Vote(idToken, userId, ballot, certSig, certKey, null, null, ctx); | ||
}; | ||
function completeVote (vote, id, signature, pubkey, ctx) { | ||
return new Vote(id, vote.ballot.substr(4,2), vote.certSig, vote.certKey, signature, pubkey, ctx); | ||
}; | ||
function encryptMessage(payload){ | ||
var salt = CryptoJS.lib.WordArray.random(128/8); | ||
var iv = CryptoJS.lib.WordArray.random(128/8); | ||
console.log('salt '+ salt ); | ||
console.log('iv '+ iv ); | ||
var key128Bits100Iterations = CryptoJS.PBKDF2("Secret Passphrase", salt, { keySize: 128/32, iterations: 100 }); | ||
console.log( 'key128Bits100Iterations '+ key128Bits100Iterations); | ||
var encrypted = CryptoJS.AES.encrypt(payload, key128Bits100Iterations, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); | ||
} | ||
function decryptMessage(encrypted){ | ||
var salt = CryptoJS.enc.Hex.parse("4acfedc7dc72a9003a0dd721d7642bde"); | ||
var iv = CryptoJS.enc.Hex.parse("69135769514102d0eded589ff874cacd"); | ||
var encrypted = "PU7jfTmkyvD71ZtISKFcUQ=="; | ||
var key = CryptoJS.PBKDF2("Secret Passphrase", salt, { keySize: 128/32, iterations: 100 }); | ||
console.log( 'key '+ key); | ||
var decrypt = CryptoJS.AES.decrypt(encrypted, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); | ||
var ddd = decrypt.toString(CryptoJS.enc.Utf8); | ||
console.log('ddd '+ddd); | ||
} | ||
function completeVote (vote, idToken, userId, signature, pubkey, ctx) { | ||
return new Vote(idToken, userId, vote.ballot.substr(4,2), vote.certSig, vote.certKey, signature, pubkey, ctx); | ||
}; | ||
@@ -199,39 +176,38 @@ /////// UTILS //////////////////// | ||
module.exports = { | ||
register: function(id) { | ||
var buf = new Buffer(id, "hex"); | ||
return Bs58.encode(buf); | ||
}, | ||
vote: function(data, context) { | ||
if (data == null) return false; | ||
var ctx = new Context(context); | ||
var newVote = generateNewVote(data, ctx); | ||
var newVoteScript = getVoteScript(newVote); | ||
var privkey_hex = Bs58.decode(data.privKeyB58).toString("hex"); | ||
var signature = signScript(newVoteScript, privkey_hex); | ||
var pubkey = EC.keyFromPrivate(privkey_hex, 'hex').getPublic(true, 'hex'); | ||
if (signature) { | ||
newVote = completeVote(newVote, data.id, signature, pubkey, ctx); | ||
console.log('Completed vote: ' + JSON.stringify(newVote)); | ||
console.log('Completed vote hex: ' + getVoteHex(newVote)); | ||
if (validateVote(newVote)) { | ||
console.log('Vote is valid'); | ||
return JSON.stringify(newVoteScript); | ||
console.log("Starting vote in booth.js"); | ||
console.log(data); | ||
console.log(context); | ||
if (data == null || context == null) return false; | ||
try { | ||
var ctx = new Context(context); | ||
var newVote = generateNewVote(data, ctx); | ||
var newVoteScript = getVoteScript(newVote); | ||
var privkey_hex = Bs58.decode(data.privKeyB58).toString("hex"); | ||
var signature = signScript(newVoteScript, privkey_hex); | ||
var pubkey = EC.keyFromPrivate(privkey_hex, 'hex').getPublic(true, 'hex'); | ||
if (signature) { | ||
newVote = completeVote(newVote, data.idToken, data.userId, signature, pubkey, ctx); | ||
console.log('Completed vote: ' + JSON.stringify(newVote)); | ||
console.log('Completed vote hex: ' + getVoteHex(newVote)); | ||
if (validateVote(newVote)) { | ||
console.log('Vote is valid'); | ||
return JSON.stringify(newVoteScript); | ||
} else { | ||
console.log('Vote is not valid'); | ||
return false; | ||
} | ||
} else { | ||
console.log('Vote is not valid'); | ||
console.log('Vote script: ' + JSON.stringify(newVoteScript)); | ||
console.log('Signature failed'); | ||
return false; | ||
} | ||
} else { | ||
console.log('Vote script: ' + JSON.stringify(newVoteScript)); | ||
console.log('Signature failed'); | ||
} catch(e) { | ||
console.log("Error"); | ||
console.log(e); | ||
return false; | ||
} | ||
}, | ||
check: function(key, context) { | ||
console.log("Checking vote"); | ||
console.log(key); | ||
return key; | ||
} | ||
} | ||
{ | ||
"name": "bitagora-booth", | ||
"version": "1.0.4", | ||
"version": "1.0.5", | ||
"description": "Bitagora booth js functions", | ||
@@ -5,0 +5,0 @@ "main": "booth.js", |
8915
190