mirror of
https://github.com/Valeh2012/PersonalVotingMachine
synced 2025-12-10 02:35:12 +02:00
first commit
This commit is contained in:
153
extended-setup/main/impl/controllers/AuthorizationController.cpp
Normal file
153
extended-setup/main/impl/controllers/AuthorizationController.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* @file AuthorizationController.cpp
|
||||
* @brief AuthorizationController implementation file
|
||||
* */
|
||||
|
||||
#include "cJSON.h"
|
||||
#include "controller.h"
|
||||
#include "module.h"
|
||||
|
||||
AuthorizationController::AuthorizationController(BaseModel *model, const char* sni){
|
||||
|
||||
this->model = static_cast<UserModel *>(model);
|
||||
this->sni = sni;
|
||||
this->vw = new IndexView();
|
||||
}
|
||||
|
||||
char* AuthorizationController::generateAuthenticateRequestJSON(){
|
||||
|
||||
cJSON *root, *params, *param;
|
||||
root = cJSON_CreateObject();
|
||||
cJSON_AddNumberToObject(root, "id", 0.0);
|
||||
cJSON_AddItemToObject(root, "method", cJSON_CreateString("RPC.Authenticate"));
|
||||
|
||||
params = cJSON_CreateArray();
|
||||
cJSON_AddItemToObject(root, "params", params);
|
||||
|
||||
cJSON_AddItemToArray(params, param = cJSON_CreateObject());
|
||||
cJSON_AddStringToObject(param, "OS", "FreeRTOS");
|
||||
cJSON_AddStringToObject(param, "PhoneNo", this->model->phone);
|
||||
cJSON_AddStringToObject(param, "IDCode", this->model->ID);
|
||||
|
||||
char* pretty = cJSON_Print(root);
|
||||
cJSON_Delete(root);
|
||||
|
||||
return pretty;
|
||||
}
|
||||
|
||||
char* AuthorizationController::generateAuthenticateStatusRequestJSON(){
|
||||
|
||||
cJSON *root, *params, *param;
|
||||
root = cJSON_CreateObject();
|
||||
cJSON_AddNumberToObject(root, "id", 0.0);
|
||||
cJSON_AddItemToObject(root, "method", cJSON_CreateString("RPC.AuthenticateStatus"));
|
||||
|
||||
params = cJSON_CreateArray();
|
||||
cJSON_AddItemToObject(root, "params", params);
|
||||
|
||||
cJSON_AddItemToArray(params, param = cJSON_CreateObject());
|
||||
cJSON_AddStringToObject(param, "OS", "FreeRTOS");
|
||||
cJSON_AddStringToObject(param, "SessionID", this->model->ssid);
|
||||
cJSON_AddStringToObject(param, "SessionCode", this->model->sscode);
|
||||
|
||||
char* pretty = cJSON_Print(root);
|
||||
cJSON_Delete(root);
|
||||
|
||||
return pretty;
|
||||
}
|
||||
|
||||
void AuthorizationController::index(){
|
||||
|
||||
ESP_LOGI(TAG, "%s", this->model->ID);
|
||||
|
||||
this->vw->render((void *) "Authorization");
|
||||
this->vw->setLabel((char *) "Use mobile-ID");
|
||||
}
|
||||
|
||||
void AuthorizationController::auth(){
|
||||
|
||||
this->vw->showLoader(true);
|
||||
// Start mobilID Authentication
|
||||
try{
|
||||
cJSON *authJson = RPC::Instance().send_json_rpc(sni, generateAuthenticateRequestJSON());
|
||||
if(authJson == NULL){
|
||||
throw "Empty response";
|
||||
}
|
||||
if( cJSON_GetObjectItem(authJson, "error")->valuestring != NULL){
|
||||
throw cJSON_GetObjectItem(authJson, "error")->valuestring;
|
||||
}
|
||||
|
||||
cJSON* params = cJSON_GetObjectItem(authJson, "result");
|
||||
|
||||
int len = strlen(cJSON_GetObjectItem(params, "SessionID")->valuestring);
|
||||
this->model->ssid = (char *) malloc(len +1);
|
||||
memset(this->model->ssid, 0, len + 1);
|
||||
memcpy(this->model->ssid, cJSON_GetObjectItem(params, "SessionID")->valuestring, len);
|
||||
|
||||
len = strlen(cJSON_GetObjectItem(params, "SessionCode")->valuestring);
|
||||
this->model->sscode = (char *) malloc(len +1);
|
||||
memset(this->model->sscode, 0, len + 1);
|
||||
memcpy(this->model->sscode, cJSON_GetObjectItem(params, "SessionCode")->valuestring, len);
|
||||
|
||||
char pin[25];
|
||||
bzero(pin, 25);
|
||||
strncat(pin, "Verification code: ", 20);
|
||||
strncat(pin, cJSON_GetObjectItem(params, "ChallengeID")->valuestring, 5);
|
||||
|
||||
cJSON_Delete(authJson);
|
||||
|
||||
this->vw->setLabel(pin);
|
||||
}
|
||||
catch(const char* msg){
|
||||
this->vw->setLabel((char *) msg);
|
||||
this->vw->showLoader(false);
|
||||
throw msg;
|
||||
}
|
||||
}
|
||||
|
||||
void AuthorizationController::authStatus(){
|
||||
|
||||
try{
|
||||
char* authStatusReq = generateAuthenticateStatusRequestJSON();
|
||||
cJSON * result, * authJson;
|
||||
do{
|
||||
ESP_LOGI(TAG, "waiting to confirm pin");
|
||||
for(int i=10; i>0; i--){
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
// Check authentication status
|
||||
ESP_LOGI(TAG, "authorization status request sent");
|
||||
authJson = RPC::Instance().send_json_rpc(sni, authStatusReq );
|
||||
if(authJson == NULL){
|
||||
throw "Empty response";
|
||||
}
|
||||
|
||||
result = cJSON_GetObjectItem(authJson, "result");
|
||||
if( cJSON_GetObjectItem(authJson, "error")->valuestring != NULL){
|
||||
throw cJSON_GetObjectItem(authJson, "error")->valuestring;
|
||||
}
|
||||
if(strcmp(cJSON_GetObjectItem(result, "Status")->valuestring, "POLL") == 0){
|
||||
continue;
|
||||
}
|
||||
if(strcmp(cJSON_GetObjectItem(result, "Status")->valuestring, "OK") == 0){
|
||||
int len = strlen(cJSON_GetObjectItem(result, "AuthToken")->valuestring);
|
||||
this->model->authToken = (char *)malloc(len + 1);
|
||||
memset(this->model->authToken, 0, len + 1);
|
||||
memcpy(this->model->authToken, cJSON_GetObjectItem(result, "AuthToken")->valuestring, len);
|
||||
this->vw->setLabel((char *) "Confirmed!");
|
||||
this->vw->showLoader(false);
|
||||
break;
|
||||
}
|
||||
cJSON_free(authJson);
|
||||
}
|
||||
while(1);
|
||||
|
||||
cJSON_Delete(authJson);
|
||||
}
|
||||
catch(const char* msg){
|
||||
this->vw->setLabel((char *) msg);
|
||||
this->vw->showLoader(false);
|
||||
throw msg;
|
||||
}
|
||||
}
|
||||
123
extended-setup/main/impl/controllers/ChoiceController.cpp
Normal file
123
extended-setup/main/impl/controllers/ChoiceController.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* @file ChoiceController.cpp
|
||||
* @brief ChoiceController implementation file
|
||||
* */
|
||||
|
||||
#include "cJSON.h"
|
||||
#include "controller.h"
|
||||
|
||||
ChoiceController::ChoiceController(BaseModel *model, const char* sni){
|
||||
|
||||
this->vw = new ChoiceView();
|
||||
this->model = static_cast<ChoiceModel*>(model);
|
||||
this->sni = sni;
|
||||
}
|
||||
|
||||
void ChoiceController::index(){
|
||||
|
||||
try{
|
||||
this->vw->render(NULL);
|
||||
char* choicesRequestJson = generateChoicesRequestJSON(this->model);
|
||||
// Get choices from server
|
||||
cJSON *choicesJson = RPC::Instance().send_json_rpc(sni, choicesRequestJson);
|
||||
cJSON *result;
|
||||
if(choicesJson == NULL){
|
||||
throw "Empty response";
|
||||
}
|
||||
if( cJSON_GetObjectItem(choicesJson, "error")->valuestring != NULL){
|
||||
throw cJSON_GetObjectItem(choicesJson, "error")->valuestring;
|
||||
}
|
||||
|
||||
result = cJSON_GetObjectItem(choicesJson, "result");
|
||||
|
||||
this->model->choices = (char *) malloc(21);
|
||||
memset(this->model->choices, 0, 21);
|
||||
strncpy(this->model->choices, cJSON_GetObjectItem(result, "Choices")->valuestring, 21);
|
||||
|
||||
unsigned char* list = (unsigned char *) cJSON_GetObjectItem(result, "List")->valuestring;
|
||||
|
||||
size_t bufflen = strlen((char*) list);
|
||||
bufflen = (bufflen/4) *3 +1; // length before base64 encoding
|
||||
|
||||
unsigned char *decoded_list = (unsigned char *) malloc(bufflen);
|
||||
if(decoded_list == NULL) throw "insufficient memory";
|
||||
memset(decoded_list, 0, bufflen);
|
||||
|
||||
size_t len;
|
||||
|
||||
int error = mbedtls_base64_decode(decoded_list, bufflen, &len, list, strlen( (char*) list));
|
||||
if(error) throw "Error decoding choice list";
|
||||
|
||||
cJSON *parsedList = cJSON_Parse((char *) decoded_list);
|
||||
parse_object(parsedList, (char *)"" );
|
||||
ESP_LOGI(TAG, "total candidates: %d", this->model->choice_list->size());
|
||||
|
||||
this->vw->showLoader(false);
|
||||
this->vw->render((void *) this->model);
|
||||
cJSON_Delete(parsedList);
|
||||
free(decoded_list);
|
||||
cJSON_Delete(choicesJson);
|
||||
}
|
||||
catch(const char* msg){
|
||||
this->vw->setLabel((char *) msg);
|
||||
this->vw->showLoader(false);
|
||||
throw msg;
|
||||
}
|
||||
}
|
||||
|
||||
char* ChoiceController::generateChoicesRequestJSON(ChoiceModel *cm){
|
||||
|
||||
cJSON *root, *params, *param;
|
||||
root = cJSON_CreateObject();
|
||||
cJSON_AddNumberToObject(root, "id", 0.0);
|
||||
cJSON_AddItemToObject(root, "method", cJSON_CreateString("RPC.VoterChoices"));
|
||||
|
||||
params = cJSON_CreateArray();
|
||||
cJSON_AddItemToObject(root, "params", params);
|
||||
|
||||
cJSON_AddItemToArray(params, param=cJSON_CreateObject());
|
||||
cJSON_AddStringToObject(param, "AuthMethod", "ticket");
|
||||
cJSON_AddStringToObject(param, "AuthToken", cm->authToken);
|
||||
cJSON_AddStringToObject(param, "OS", "Operating System,2,0");
|
||||
cJSON_AddStringToObject(param, "SessionID", cm->ssid);
|
||||
|
||||
char* pretty = cJSON_Print(root);
|
||||
cJSON_Delete(root);
|
||||
|
||||
return pretty;
|
||||
}
|
||||
|
||||
|
||||
void ChoiceController::parse_object(cJSON *item, char* par){
|
||||
|
||||
cJSON *subitem=item->child;
|
||||
if ( !subitem ) { // leaf nodes are candidates
|
||||
while(item){
|
||||
|
||||
choice_t *c = new choice_t(); // create new choice element
|
||||
|
||||
c->candidate = (char *) malloc(strlen(item->valuestring)+1); // allocate memory for candidate field
|
||||
memset(c->candidate, 0, strlen(item->valuestring) +1); // set content 0
|
||||
memcpy(c->candidate, item->valuestring, strlen(item->valuestring)); // copy from json to struct field
|
||||
|
||||
c->code = (char *) malloc(strlen(item->string)+1); // allocate memory for code field
|
||||
memset(c->code, 0, strlen(item->string) +1); // set content 0
|
||||
memcpy(c->code, item->string, strlen(item->string)); // copy from json to struct field
|
||||
|
||||
c->party = (char *) malloc(strlen(par)+1); // allocate memory for party field
|
||||
memset(c->party, 0, strlen(par) +1); // set content 0
|
||||
memcpy(c->party, par, strlen(par)); // copy from json to struct field
|
||||
|
||||
this->model->choice_list->push_back(*c); // push choice element to vector (list of choices)
|
||||
|
||||
item = item->next; // go to next candidate
|
||||
}
|
||||
}
|
||||
while (subitem){
|
||||
// handle subitem
|
||||
if (subitem->child) {
|
||||
parse_object(subitem->child, subitem->string);
|
||||
}
|
||||
subitem=subitem->next;
|
||||
}
|
||||
}
|
||||
338
extended-setup/main/impl/controllers/EncryptionController.cpp
Normal file
338
extended-setup/main/impl/controllers/EncryptionController.cpp
Normal file
@@ -0,0 +1,338 @@
|
||||
/**
|
||||
* @file EncryptionController.cpp
|
||||
* @brief EncryptionController implementation file
|
||||
* */
|
||||
|
||||
#include "esp_log.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include "esp_system.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
extern "C" {
|
||||
#include "mbedtls/bignum.h"
|
||||
}
|
||||
|
||||
#include "controller.h"
|
||||
#include "converter.h"
|
||||
|
||||
#ifndef modlength
|
||||
#define modlength 96 /**< 3072 bits = 384 bytes = 96 words */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Struct to store ElGamal encryption results.
|
||||
* g is group generator and pk is public key
|
||||
* In general, ElGamal encyption cipher is a pair (c1, c2). But, we'll need randomness later for verification,
|
||||
* so we also keep random number
|
||||
* */
|
||||
typedef struct{
|
||||
mbedtls_mpi c1; /**< c1 = g^r mod p */
|
||||
mbedtls_mpi c2; /**< c2 = c1*g^pk mod p */
|
||||
mbedtls_mpi random; /**< r */
|
||||
}elgamal_cipher_t;
|
||||
|
||||
typedef struct{
|
||||
mbedtls_mpi* base;
|
||||
mbedtls_mpi* exponent;
|
||||
mbedtls_mpi* buff;
|
||||
mbedtls_mpi* mod;
|
||||
uint8_t flag;
|
||||
int error;
|
||||
}task_param_t;
|
||||
|
||||
void taskMont(void* data){
|
||||
|
||||
task_param_t* params = (task_param_t*) data;
|
||||
|
||||
params->error = mbedtls_mpi_exp_mod(params->buff, params->base, params->exponent, params->mod, NULL);
|
||||
|
||||
params->flag = 1;
|
||||
|
||||
for(;;){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief secure big random generator
|
||||
*
|
||||
* Multi-precision integer (mpi) is an array of 64bit unsigned integers in big endian representation. This method
|
||||
* creates grows input parameter to the length of modlength, then fills the array with random unsigned integers using
|
||||
* esp_random()
|
||||
*
|
||||
* @param mpi The destination MPI. This must point to an initialized MPI.
|
||||
*
|
||||
*/
|
||||
void mpi_RandomNumber(mbedtls_mpi * mpi ){
|
||||
|
||||
srand ( time(NULL) );
|
||||
mbedtls_mpi_grow(mpi, modlength);
|
||||
|
||||
for(int i = 0;i < modlength; i++){
|
||||
mpi->p[i] = (mbedtls_mpi_uint) esp_random();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief fast multi-core ElGamal implementation
|
||||
* ElGamal is a homomorphic encryption method used in ivxv protocol.
|
||||
* 3072 bit long keys provide 128 bit security.
|
||||
*
|
||||
* @param pk public key
|
||||
* @param m encoded plaintext
|
||||
* @param res pointer to cipher struct
|
||||
* @param mod pointer to modulus variable
|
||||
*
|
||||
* @returns 0 if successful, -1 otherwise
|
||||
* */
|
||||
int ElGamalEncrypt(mbedtls_mpi * pk, mbedtls_mpi* m, elgamal_cipher_t * res, mbedtls_mpi * mod){
|
||||
|
||||
esp_err_t error;
|
||||
mbedtls_mpi rnd, g, c1, c2;
|
||||
mbedtls_mpi_init(&c1);
|
||||
mbedtls_mpi_init(&c2);
|
||||
mbedtls_mpi_init(&rnd);
|
||||
mbedtls_mpi_init(&g);
|
||||
|
||||
mpi_RandomNumber(&rnd);
|
||||
error = mbedtls_mpi_read_string(&g, 10, "2");
|
||||
if(error) return error;
|
||||
|
||||
task_param_t * c1Params = new task_param_t();
|
||||
c1Params->base = &g;
|
||||
c1Params->exponent = &rnd;
|
||||
c1Params->buff = &c1;
|
||||
c1Params->mod = mod;
|
||||
|
||||
TaskHandle_t c1Task;
|
||||
xTaskCreatePinnedToCore(taskMont, "C1_Mont", 4192, (void *) c1Params, 0 , &c1Task, 1);
|
||||
|
||||
mbedtls_mpi c3;
|
||||
mbedtls_mpi_init(&c3);
|
||||
error = mbedtls_mpi_exp_mod(&c3, pk, &rnd, mod, NULL);
|
||||
if(error) return error;
|
||||
|
||||
error = esp_mpi_mul_mpi_mod(&c2, &c3, m, mod);
|
||||
if(error) return error;
|
||||
|
||||
while(!c1Params->flag){
|
||||
|
||||
}
|
||||
vTaskDelete(c1Task);
|
||||
if(c1Params->error) return c1Params->error;
|
||||
|
||||
error = mbedtls_mpi_copy(&res->c1, &c1); if(error) return error;
|
||||
error = mbedtls_mpi_copy(&res->c2, &c2); if(error) return error;
|
||||
error = mbedtls_mpi_copy(&res->random, &rnd); if(error) return error;
|
||||
|
||||
mbedtls_mpi_free(&c1);
|
||||
mbedtls_mpi_free(&c2);
|
||||
mbedtls_mpi_free(&c3);
|
||||
mbedtls_mpi_free(&rnd);
|
||||
mbedtls_mpi_free(&g);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EncryptionController::EncryptionController(BaseModel *model){
|
||||
|
||||
this->model = static_cast<EncryptionModel *>(model);
|
||||
this->vw = new IndexView();
|
||||
}
|
||||
|
||||
void EncryptionController::index(){
|
||||
|
||||
this->vw->render((void *)"Encryption");
|
||||
this->vw->setLabel((char *) "Parsing encryption\ncertificate");
|
||||
this->vw->showLoader(true);
|
||||
try{
|
||||
unsigned char * PK_DER = (unsigned char *) malloc(1024);
|
||||
memset(PK_DER, 0, 1024);
|
||||
size_t lenPK = 1024;
|
||||
memset(PK_DER, 0 , lenPK);
|
||||
int error = converter::convert_pem_to_der(this->model->keypem, this->model->keypem_length, PK_DER, &lenPK); //! * First, convert election public key file to DER format*/
|
||||
if(error) throw "unable to parse pem file";
|
||||
|
||||
unsigned char *p = PK_DER;
|
||||
const unsigned char *end = p + lenPK;
|
||||
size_t len; int i;
|
||||
|
||||
mbedtls_asn1_buf oid, oid_params;
|
||||
memset( &oid, 0, sizeof( mbedtls_asn1_buf ) );
|
||||
memset( &oid_params, 0, sizeof( mbedtls_asn1_buf ) );
|
||||
|
||||
mbedtls_mpi mod;
|
||||
mbedtls_mpi_init(&mod);
|
||||
|
||||
//! * Start decoding ASN1 DER encoded key contents using mbedtls_asn1 library /
|
||||
error = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if(error) throw "ASN1 parse error";
|
||||
error = mbedtls_asn1_get_alg(&p, end, &oid, &oid_params); if(error) throw "ASN1 parse error";
|
||||
unsigned char * q = oid_params.p;
|
||||
const unsigned char *q_end = q + oid_params.len;
|
||||
error = mbedtls_asn1_get_mpi(&q, q_end, &mod); if(error) throw "ASN1 parse error"; //! * extract mod
|
||||
|
||||
error = mbedtls_asn1_get_tag(&q, q_end, &len, MBEDTLS_ASN1_INTEGER); if(error) throw "ASN1 parse error";
|
||||
q += len;
|
||||
error = mbedtls_asn1_get_tag(&q, q_end, &len, 0x1B ); if(error) throw "ASN1 parse error"; //! * extract electionID
|
||||
this->model->election_id = (char *)malloc(len+1);
|
||||
memset(this->model->election_id, 0, len+1);
|
||||
memcpy(this->model->election_id, q, len);
|
||||
|
||||
mbedtls_asn1_bitstring bs = {0, 0 , NULL};
|
||||
error = mbedtls_asn1_get_bitstring(&p, end, &bs); if(error) throw "ASN1 parse error";
|
||||
p = bs.p;
|
||||
error = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if(error) throw "ASN1 parse error";
|
||||
|
||||
mbedtls_mpi key;
|
||||
mbedtls_mpi_init(&key);
|
||||
|
||||
error = mbedtls_asn1_get_mpi(&p, end, &key); if(error) throw "ASN1 parse error"; //! * extract 3072bit public key
|
||||
if(error) throw "key error";
|
||||
if(p != end){
|
||||
printf("Error. Didn't parse until the end\n");
|
||||
throw "Incomplete ASN";
|
||||
}
|
||||
|
||||
/**
|
||||
* * Then, pad the ballot using following scheme
|
||||
*
|
||||
* padded-ballot = '\x00' '\x01' *'\xff' '\x00' ballot
|
||||
*
|
||||
*/
|
||||
len = mbedtls_mpi_bitlen(&key);
|
||||
len /= 8;
|
||||
unsigned char *padded_ballot = (unsigned char *) malloc(len + 1);
|
||||
memset(padded_ballot, 0xFF, len);
|
||||
padded_ballot[0] = 0x00;
|
||||
padded_ballot[1] = 0x01;
|
||||
padded_ballot[len] = 0x00; // end of string (null-terminated)
|
||||
padded_ballot[len - strlen(this->model->ballot) - 1] = 0x00;
|
||||
for(i=1;i<=strlen(this->model->ballot);i++){
|
||||
padded_ballot[len - i] = this->model->ballot[strlen(this->model->ballot) - i];
|
||||
}
|
||||
|
||||
mbedtls_mpi plaintext;
|
||||
mbedtls_mpi_init(&plaintext);
|
||||
|
||||
error = mbedtls_mpi_read_binary(&plaintext, padded_ballot, len); //! * convert padded ballot to group element
|
||||
if (error) throw "ballot mpi conversion error";
|
||||
free(padded_ballot);
|
||||
|
||||
mbedtls_mpi pq; //pq = (modulus-1)/2
|
||||
mbedtls_mpi_init(&pq);
|
||||
error = mbedtls_mpi_sub_int(&pq, &mod, 1); if(error) throw "error at mod - 1";
|
||||
error = mbedtls_mpi_div_int(&pq, NULL, &pq, 2); if(error) throw "error at pq // 2";
|
||||
|
||||
//! * encode plaintext as a quadratic residue in the set
|
||||
mbedtls_mpi encoded_plaintext, res;
|
||||
mbedtls_mpi_init(&encoded_plaintext);
|
||||
mbedtls_mpi_init(&res);
|
||||
error = mbedtls_mpi_exp_mod(&res, &plaintext, &pq, &mod, NULL); if(error) throw "quadratic residue check error";
|
||||
if( mbedtls_mpi_cmp_int(&res, 1) == 0){
|
||||
error = mbedtls_mpi_copy(&encoded_plaintext, &plaintext);
|
||||
if(error) throw "mpi copy error";
|
||||
ESP_LOGI(TAG, "quadratic residue");
|
||||
}else{
|
||||
error = mbedtls_mpi_sub_mpi(&encoded_plaintext, &mod, &plaintext);
|
||||
if(error) throw "mpi substract error";
|
||||
}
|
||||
|
||||
elgamal_cipher_t *cipher = new elgamal_cipher_t();
|
||||
mbedtls_mpi_init(&cipher->c1);
|
||||
mbedtls_mpi_init(&cipher->c2);
|
||||
mbedtls_mpi_init(&cipher->random);
|
||||
|
||||
time_t before_enc, after_enc;
|
||||
time(&before_enc);
|
||||
error = ElGamalEncrypt(&key, &encoded_plaintext, cipher, &mod); //! * encrypt and store results in cipher
|
||||
time(&after_enc);
|
||||
ESP_LOGI(TAG, "encryption took %ld seconds", (long) after_enc - (long) before_enc);
|
||||
if(error) throw "Encryption error";
|
||||
ESP_LOGI(TAG, "plaintext encrypted");
|
||||
|
||||
unsigned char * rndASN = (unsigned char*) malloc( len );
|
||||
memset(rndASN, 0, len);
|
||||
error = mbedtls_mpi_write_binary(&cipher->random, rndASN, len ); //! * convert used random number into hex and base64 encode it.
|
||||
if(error) throw "error in rnd binary export";
|
||||
|
||||
this->model->rndBase64 = (unsigned char *)malloc(2*len);
|
||||
memset(this->model->rndBase64,0, 2*len);
|
||||
error = mbedtls_base64_encode(this->model->rndBase64, 2*len, &len, rndASN, len);
|
||||
if(error) throw "Random number hash error";
|
||||
//! * start DER encoding of cipher
|
||||
puts((char *) this->model->rndBase64);
|
||||
|
||||
unsigned char * asnder = (unsigned char *) malloc(1220);
|
||||
memset(asnder, 0, 1220);
|
||||
unsigned char *asn_end = asnder + 1220;
|
||||
int succ, total_succ = 0;
|
||||
|
||||
succ = mbedtls_asn1_write_mpi(&asn_end, asnder, &cipher->c2); //! * convert second component of cipher into hex and encode as ASN1 Integer
|
||||
total_succ+=succ;
|
||||
|
||||
succ = mbedtls_asn1_write_mpi(&asn_end, asnder, &cipher->c1); //! * convert first component of cipher into hex and encode as ASN1 Integer
|
||||
total_succ+=succ;
|
||||
|
||||
succ = mbedtls_asn1_write_len(&asn_end, asnder, total_succ);
|
||||
total_succ+=succ;
|
||||
succ = mbedtls_asn1_write_tag(&asn_end, asnder, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
|
||||
total_succ+=succ;
|
||||
|
||||
int params_total = 0;
|
||||
succ = mbedtls_asn1_write_raw_buffer(&asn_end, asnder, oid_params.p, oid_params.len);
|
||||
params_total+=succ;
|
||||
succ = mbedtls_asn1_write_len(&asn_end, asnder, oid_params.len);
|
||||
params_total+=succ;
|
||||
succ = mbedtls_asn1_write_tag(&asn_end, asnder, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
|
||||
params_total+=succ;
|
||||
|
||||
succ = mbedtls_asn1_write_algorithm_identifier(&asn_end, asnder, (char *) oid.p, oid.len, params_total); //! * append encryption algorithm identifier to DER
|
||||
total_succ+=succ;
|
||||
|
||||
succ = mbedtls_asn1_write_len(&asn_end, asnder, total_succ);
|
||||
total_succ+=succ;
|
||||
succ = mbedtls_asn1_write_tag(&asn_end, asnder, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
|
||||
total_succ+=succ;
|
||||
|
||||
this->model->ballotASN = (unsigned char *) malloc(total_succ+1);
|
||||
memset(this->model->ballotASN, 0, total_succ + 1);
|
||||
memcpy(this->model->ballotASN, asnder+1220-total_succ, total_succ);
|
||||
this->model->ballotLength = total_succ;
|
||||
|
||||
free(asnder);
|
||||
free(PK_DER);
|
||||
free(rndASN);
|
||||
mbedtls_mpi_free(&mod);
|
||||
mbedtls_mpi_free(&pq);
|
||||
mbedtls_mpi_free(&key);
|
||||
mbedtls_mpi_free(&plaintext);
|
||||
mbedtls_mpi_free(&encoded_plaintext);
|
||||
mbedtls_mpi_free(&res);
|
||||
mbedtls_mpi_free(&cipher->c1);
|
||||
mbedtls_mpi_free(&cipher->c2);
|
||||
mbedtls_mpi_free(&cipher->random);
|
||||
|
||||
// SHA256 hash + Base64 asnder
|
||||
this->model->ballotFileName = (char *)malloc(65);
|
||||
memset(this->model->ballotFileName, 0, 65);
|
||||
snprintf(this->model->ballotFileName, 64, "%s.%s.ballot", this->model->election_id, "1"); //! * set filename for DER encoded encrypted ballot
|
||||
|
||||
this->model->ballotHash = converter::base64hash(this->model->ballotASN, this->model->ballotLength); //! * hash and base64 encode it for future references
|
||||
|
||||
ESP_LOGI(TAG, "ballot hash: %s\n",(char *)this->model->ballotHash);
|
||||
|
||||
this->vw->setLabel((char*) "Encrypted");
|
||||
this->vw->showLoader(false);
|
||||
}
|
||||
catch(const char* msg){
|
||||
this->vw->setLabel((char *) msg);
|
||||
this->vw->showLoader(false);
|
||||
throw msg;
|
||||
}
|
||||
}
|
||||
23
extended-setup/main/impl/controllers/IndexController.cpp
Normal file
23
extended-setup/main/impl/controllers/IndexController.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @file IndexController.cpp
|
||||
* @brief IndexController implementation file
|
||||
* */
|
||||
|
||||
#include "controller.h"
|
||||
|
||||
IndexController::IndexController(){
|
||||
|
||||
this->vw = new IndexView();
|
||||
}
|
||||
|
||||
void IndexController::index(){
|
||||
|
||||
this->vw->render((void *) "Welcome\n");
|
||||
this->vw->setLabel("starting");
|
||||
}
|
||||
void IndexController::end(){
|
||||
|
||||
this->vw->render((void *) "End\n");
|
||||
this->vw->setLabel("Click boot to start again");
|
||||
this->vw->showLoader(false);
|
||||
}
|
||||
31
extended-setup/main/impl/controllers/QRController.cpp
Normal file
31
extended-setup/main/impl/controllers/QRController.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @file QRController.cpp
|
||||
* @brief QRController implementation file
|
||||
* */
|
||||
|
||||
#include "qrcode.h"
|
||||
#include "controller.h"
|
||||
|
||||
QRController::QRController(BaseModel *model){
|
||||
|
||||
this->model = static_cast<QRModel *>(model);
|
||||
this->vw = new QRView();
|
||||
}
|
||||
|
||||
void QRController::index(){
|
||||
|
||||
// The structure to manage the QR code
|
||||
QRCode qrcode;
|
||||
|
||||
// Allocate a chunk of memory to store the QR code
|
||||
uint8_t qrcodeBytes[qrcode_getBufferSize(23)];
|
||||
|
||||
size_t len = strlen(this->model->ssid) + strlen(this->model->voteID) + strlen((char *)this->model->rndBase64) + 3;
|
||||
char* data = (char *) malloc(len);
|
||||
snprintf(data, len, "%s\n%s\n%s",this->model->ssid,this->model->rndBase64,this->model->voteID); //! * concatenate fields
|
||||
|
||||
// create qr code
|
||||
qrcode_initText(&qrcode, qrcodeBytes, 23, ECC_LOW, data);
|
||||
|
||||
this->vw->render((void *) &qrcode);
|
||||
}
|
||||
357
extended-setup/main/impl/controllers/SignatureController.cpp
Normal file
357
extended-setup/main/impl/controllers/SignatureController.cpp
Normal file
@@ -0,0 +1,357 @@
|
||||
/**
|
||||
* @file SignatureController.cpp
|
||||
* @brief SignatureController implementation file
|
||||
* */
|
||||
|
||||
#include "cJSON.h"
|
||||
#include "controller.h"
|
||||
#include "converter.h"
|
||||
|
||||
SignatureController::SignatureController(BaseModel *model, const char * sni){
|
||||
|
||||
this->vw = new IndexView();
|
||||
this->model = static_cast<SignatureModel *>(model);
|
||||
this->sni = sni;
|
||||
}
|
||||
|
||||
void SignatureController::index(){
|
||||
|
||||
try{
|
||||
this->vw->render((void *) "Sign");
|
||||
this->vw->setLabel((char *) "Getting certificate");
|
||||
this->vw->showLoader(true);
|
||||
// Get certificate
|
||||
ESP_LOGI(TAG, "get certificate request sent");
|
||||
cJSON *certificateJson = RPC::Instance().send_json_rpc(sni, generateGetCertificateRequestJSON()); //! * Get certificate from server
|
||||
if(certificateJson == NULL){
|
||||
throw "Empty response";
|
||||
}
|
||||
if( cJSON_GetObjectItem(certificateJson, "error")->valuestring != NULL){ //! * check for error message
|
||||
this->vw->setLabel((char *) cJSON_GetObjectItem(certificateJson, "error")->valuestring);
|
||||
this->vw->showLoader(false);
|
||||
throw cJSON_GetObjectItem(certificateJson, "error")->valuestring;
|
||||
}
|
||||
|
||||
cJSON * result = cJSON_GetObjectItem(certificateJson, "result"); //! * if no error, parse JSON result
|
||||
size_t len = strlen(cJSON_GetObjectItem(result, "Certificate")->valuestring);
|
||||
char * signCertificate = (char *)malloc(len + 1); //! * allocate enough memory to store certificate
|
||||
if(signCertificate == NULL){
|
||||
ESP_LOGE("ivxv", "unable to allocate memory to store certificate");
|
||||
printf("available memory: %d\n", (int) heap_caps_get_largest_free_block(MALLOC_CAP_8BIT));
|
||||
this->vw->setLabel((char *) "Insufficient memory");
|
||||
throw "Insufficient memory";
|
||||
}
|
||||
memset(signCertificate, 0, len + 1);
|
||||
memcpy(signCertificate, cJSON_GetObjectItem(result, "Certificate")->valuestring, len);
|
||||
|
||||
len = (len/64) *65 + len%64;
|
||||
this->model->certificate = (char *)malloc(len+1);
|
||||
memset(this->model->certificate,0, len+1); //! * base64 decode and add line breaks after 64th character
|
||||
int i, j=0;
|
||||
for(i=0;i<strlen(signCertificate);i++){
|
||||
this->model->certificate[j++] = signCertificate[i];
|
||||
if(i && (i+1)%64==0){
|
||||
this->model->certificate[j++] = '\n';
|
||||
}
|
||||
}
|
||||
cJSON_Delete(certificateJson);
|
||||
|
||||
// ASN1 Parse certificate
|
||||
// decode certificate, parse it, hash it, base64 encode it.
|
||||
unsigned char *certificateDER = (unsigned char *) malloc(1600);
|
||||
if(certificateDER == NULL){
|
||||
ESP_LOGE("ivxv", "unable to allocate memory to store certificate DER");
|
||||
printf("available memory: %d\n", (int) heap_caps_get_largest_free_block(MALLOC_CAP_8BIT));
|
||||
this->vw->setLabel((char *) "Insufficient memory");
|
||||
throw "Insufficient memory";
|
||||
}
|
||||
memset(certificateDER, 0, 1600);
|
||||
|
||||
int error = mbedtls_base64_decode(certificateDER, 1600, &len, (unsigned char *)signCertificate, strlen(signCertificate));
|
||||
if(error) throw "Error";
|
||||
int der_length = len;
|
||||
|
||||
unsigned char* p = certificateDER;
|
||||
unsigned char* end = p + len;
|
||||
int version;
|
||||
mbedtls_mpi serial = {0,0,0};
|
||||
char * serialBuf = (char *)malloc(128);
|
||||
memset(serialBuf, 0 , 128);
|
||||
error = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
|
||||
if(error) throw "Error";
|
||||
error = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
|
||||
if(error) throw "Error";
|
||||
error = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC);
|
||||
if(error) throw "Error";
|
||||
error = mbedtls_asn1_get_int(&p, end, &version);
|
||||
if(error) throw "Error";
|
||||
error = mbedtls_asn1_get_mpi(&p, end, &serial);
|
||||
if(error) throw "Error";
|
||||
error = mbedtls_mpi_write_string(&serial, 10, serialBuf, 128, &len); //! * parse certificate serial number
|
||||
if(error) throw "Error";
|
||||
|
||||
mbedtls_asn1_buf oid, oid_params;
|
||||
memset( &oid, 0, sizeof( mbedtls_asn1_buf ) );
|
||||
memset( &oid_params, 0, sizeof( mbedtls_asn1_buf ) );
|
||||
error = mbedtls_asn1_get_alg_null(&p, end, &oid);
|
||||
if(error) throw "Error";
|
||||
error = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
|
||||
if(error) throw "Error";
|
||||
|
||||
char *DN = (char *)malloc(256);
|
||||
memset(DN,0, 256);
|
||||
|
||||
char* CN = (char *) malloc(32);
|
||||
memset(CN,0, 32);
|
||||
|
||||
char* C = (char *) malloc(32);
|
||||
memset(C,0, 32);
|
||||
|
||||
char* O = (char *) malloc(32);
|
||||
memset(O,0, 32);
|
||||
|
||||
char* org = (char *) malloc(32);
|
||||
memset(org,0, 32);
|
||||
|
||||
for(i=0;i<4;i++){
|
||||
memset( &oid, 0, sizeof( mbedtls_asn1_buf ) );
|
||||
memset( &oid_params, 0, sizeof( mbedtls_asn1_buf ) );
|
||||
error = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET);
|
||||
if(error) {
|
||||
throw "Error";
|
||||
}
|
||||
error = mbedtls_asn1_get_alg(&p, end, &oid, &oid_params);
|
||||
if(error) {
|
||||
throw "Error";
|
||||
}
|
||||
if( *(oid.p + 2) == 0x03) strncat(CN, (char *) oid_params.p, oid_params.len);
|
||||
if( *(oid.p + 2) == 0x06) strncat(C, (char *) oid_params.p, oid_params.len);
|
||||
if( *(oid.p + 2) == 0x0A) strncat(O, (char *) oid_params.p, oid_params.len);
|
||||
if( *(oid.p + 2) == 0x61) strncat(org, (char *) oid_params.p, oid_params.len);
|
||||
}
|
||||
if(error) {
|
||||
this->vw->setLabel((char *) "Unexpected error");
|
||||
throw "Error";
|
||||
}
|
||||
snprintf(DN, 256, "CN=%s,organizationIdentifier=%s,O=%s,C=%s", CN, org, O, C); // copy certificate DN field
|
||||
|
||||
unsigned char *certificateHashBase64 = converter::base64hash(certificateDER, der_length);
|
||||
|
||||
free(certificateDER);
|
||||
free(signCertificate);
|
||||
|
||||
// Create signedProperties
|
||||
char *signingTime = (char *) malloc(64);
|
||||
memset(signingTime, 0, 64);
|
||||
time_t now;
|
||||
time(&now);
|
||||
strftime(signingTime, 21,"%Y-%m-%dT%XZ", localtime(&now)); //! * get signing time
|
||||
ESP_LOGI(TAG, "time: %s", signingTime);
|
||||
|
||||
this->model->SP_XML = (char *) malloc(2048);
|
||||
memset(this->model->SP_XML, 0, 2048);
|
||||
snprintf(this->model->SP_XML, 2048, SignedProperties, signingTime, (char *)certificateHashBase64, DN, serialBuf); //! * create SignedProperties XML element
|
||||
|
||||
converter::xmlc14n11(this->model->SP_XML, 2048); //! * canonicalize SignedProperties
|
||||
|
||||
unsigned char *spHashBase64 = converter::base64hash((unsigned char *)this->model->SP_XML, strlen(this->model->SP_XML)); //! * hash (sha256) + base64 encode canonicalize
|
||||
|
||||
// Create signedInfo
|
||||
// encrypted-ballot-name = election-identifier '.' question-identifier '.ballot'
|
||||
this->model->SI_XML = (char *) malloc(2048);
|
||||
memset(this->model->SI_XML, 0, 2048);
|
||||
snprintf(this->model->SI_XML, 2048, SignedInfo, this->model->ballotFileName ,(char *) this->model->ballotHash, spHashBase64); //! create DignedInfo XML element
|
||||
|
||||
converter::xmlc14n11(this->model->SI_XML, 2048);
|
||||
|
||||
this->model->SignedInfoHash = converter::base64hash((unsigned char *)this->model->SI_XML, strlen(this->model->SI_XML));//! * hash(sha268) andbase64 encode canonicalize
|
||||
|
||||
ESP_LOGI(TAG, "signedInfo hash: %s", (char * ) this->model->SignedInfoHash);
|
||||
}
|
||||
catch(const char *msg){
|
||||
throw msg;
|
||||
}
|
||||
}
|
||||
|
||||
char* SignatureController::generateGetCertificateRequestJSON(){
|
||||
|
||||
cJSON *root, *params, *param;
|
||||
root = cJSON_CreateObject();
|
||||
cJSON_AddNumberToObject(root, "id", 0.0);
|
||||
cJSON_AddItemToObject(root, "method", cJSON_CreateString("RPC.GetCertificate"));
|
||||
|
||||
params = cJSON_CreateArray();
|
||||
cJSON_AddItemToObject(root, "params", params);
|
||||
|
||||
cJSON_AddItemToArray(params, param=cJSON_CreateObject());
|
||||
cJSON_AddStringToObject(param, "AuthMethod", "ticket");
|
||||
cJSON_AddStringToObject(param, "AuthToken", this->model->authToken);
|
||||
cJSON_AddStringToObject(param, "OS", "FreeRTOS");
|
||||
cJSON_AddStringToObject(param, "PhoneNo", this->model->phone);
|
||||
cJSON_AddStringToObject(param, "IDCode", this->model->ID);
|
||||
cJSON_AddStringToObject(param, "SessionID", this->model->ssid);
|
||||
|
||||
char* pretty = cJSON_Print(root);
|
||||
cJSON_Delete(root);
|
||||
|
||||
return pretty;
|
||||
}
|
||||
|
||||
|
||||
char* SignatureController::generateSignRequestJSON(){
|
||||
|
||||
cJSON *root, *params, *param;
|
||||
root = cJSON_CreateObject();
|
||||
cJSON_AddNumberToObject(root, "id", 0.0);
|
||||
cJSON_AddItemToObject(root, "method", cJSON_CreateString("RPC.Sign"));
|
||||
|
||||
params = cJSON_CreateArray();
|
||||
cJSON_AddItemToObject(root, "params", params);
|
||||
|
||||
cJSON_AddItemToArray(params, param=cJSON_CreateObject());
|
||||
cJSON_AddStringToObject(param, "AuthMethod", "ticket");
|
||||
cJSON_AddStringToObject(param, "AuthToken", this->model->authToken);
|
||||
cJSON_AddStringToObject(param, "Hash", (char *) this->model->SignedInfoHash);
|
||||
cJSON_AddStringToObject(param, "OS", "FreeRTOS");
|
||||
cJSON_AddStringToObject(param, "PhoneNo", this->model->phone);
|
||||
cJSON_AddStringToObject(param, "IDCode", this->model->ID);
|
||||
cJSON_AddStringToObject(param, "SessionID", this->model->ssid);
|
||||
|
||||
char* pretty = cJSON_Print(root);
|
||||
cJSON_Delete(root);
|
||||
|
||||
return pretty;
|
||||
}
|
||||
|
||||
void SignatureController::sign(){
|
||||
try{
|
||||
ESP_LOGI(TAG, "signing request sent");
|
||||
cJSON * signJson = RPC::Instance().send_json_rpc(sni, generateSignRequestJSON());
|
||||
|
||||
if(cJSON_GetObjectItem(signJson, "error")->valuestring != NULL){
|
||||
throw cJSON_GetObjectItem(signJson, "error")->valuestring;
|
||||
}
|
||||
cJSON * params = cJSON_GetObjectItem(signJson, "result");
|
||||
|
||||
size_t len = strlen(cJSON_GetObjectItem(params, "SessionCode")->valuestring);
|
||||
this->model->sscode = (char *) malloc(len +1);
|
||||
memset(this->model->sscode, 0, len + 1);
|
||||
memcpy(this->model->sscode, cJSON_GetObjectItem(params, "SessionCode")->valuestring, len);
|
||||
|
||||
|
||||
char pin[25];
|
||||
bzero(pin, 25);
|
||||
strncat(pin, "Verification code: ", 20);
|
||||
strncat(pin, cJSON_GetObjectItem(params, "ChallengeID")->valuestring, 5);
|
||||
this->vw->setLabel((char *) pin);
|
||||
|
||||
cJSON_Delete(signJson);
|
||||
}
|
||||
catch(const char *msg){
|
||||
this->vw->setLabel((char *) msg);
|
||||
this->vw->showLoader(false);
|
||||
throw msg;
|
||||
}
|
||||
}
|
||||
|
||||
char* SignatureController::generateSignStatusRequestJSON(){
|
||||
cJSON *root, *params, *param;
|
||||
root = cJSON_CreateObject();
|
||||
cJSON_AddNumberToObject(root, "id", 0.0);
|
||||
cJSON_AddItemToObject(root, "method", cJSON_CreateString("RPC.SignStatus"));
|
||||
|
||||
params = cJSON_CreateArray();
|
||||
cJSON_AddItemToObject(root, "params", params);
|
||||
|
||||
cJSON_AddItemToArray(params, param = cJSON_CreateObject());
|
||||
cJSON_AddStringToObject(param, "OS", "FreeRTOS");
|
||||
cJSON_AddStringToObject(param, "SessionID", this->model->ssid);
|
||||
cJSON_AddStringToObject(param, "SessionCode", this->model->sscode);
|
||||
|
||||
char* pretty = cJSON_Print(root);
|
||||
cJSON_Delete(root);
|
||||
|
||||
return pretty;
|
||||
}
|
||||
|
||||
void SignatureController::status(){
|
||||
|
||||
try{
|
||||
// Poll RPC.SignStatus
|
||||
cJSON *signJson, *result;
|
||||
char* signStatusReq = generateSignStatusRequestJSON();
|
||||
do{
|
||||
ESP_LOGI(TAG, "waiting to confirm pin");
|
||||
for(int i=10; i>0; i--){
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
// check status
|
||||
ESP_LOGI(TAG, "signing status request sent");
|
||||
signJson = RPC::Instance().send_json_rpc(sni, signStatusReq );
|
||||
if(signJson == NULL){
|
||||
throw "Empty response";
|
||||
}
|
||||
|
||||
result = cJSON_GetObjectItem(signJson, "result");
|
||||
if( cJSON_GetObjectItem(signJson, "error")->valuestring != NULL){
|
||||
throw cJSON_GetObjectItem(signJson, "error")->valuestring;
|
||||
}
|
||||
if(strcmp(cJSON_GetObjectItem(result, "Status")->valuestring, "POLL") == 0){
|
||||
continue;
|
||||
}
|
||||
if(strcmp(cJSON_GetObjectItem(result, "Status")->valuestring, "OK") == 0){
|
||||
size_t len = strlen(cJSON_GetObjectItem(result, "Signature")->valuestring);
|
||||
this->model->signature = (char *) malloc(len + 1);
|
||||
memset(this->model->signature, 0, len + 1);
|
||||
memcpy(this->model->signature, cJSON_GetObjectItem(result, "Signature")->valuestring, len);
|
||||
this->vw->setLabel((char *) "PIN CONFIRMED!");
|
||||
break;
|
||||
}
|
||||
|
||||
cJSON_free(signJson);
|
||||
}
|
||||
while(1);
|
||||
this->vw->setLabel((char *)"Successfully signed");
|
||||
this->vw->showLoader(false);
|
||||
ESP_LOGI(TAG, "succesfully signed");
|
||||
|
||||
cJSON_Delete(signJson);
|
||||
}
|
||||
catch(const char *msg){
|
||||
this->vw->setLabel((char *) msg);
|
||||
this->vw->showLoader(false);
|
||||
throw msg;
|
||||
}
|
||||
}
|
||||
|
||||
void SignatureController::combine(){
|
||||
|
||||
try{
|
||||
// Create SignatureValue
|
||||
this->model->SV_XML = (char *) malloc(512);
|
||||
memset(this->model->SV_XML, 0, 512);
|
||||
snprintf(this->model->SV_XML, 511, SignatureValue, this->model->signature);
|
||||
free(this->model->signature);
|
||||
|
||||
// merge above 3 and create signature0.xml
|
||||
this->model->Signature = (char *) malloc(10240);
|
||||
if(this->model->Signature == NULL){
|
||||
ESP_LOGE("ivxv", "unable to allocate memory of 5KB");
|
||||
printf("available memory: %d\n", (int) heap_caps_get_free_size(MALLOC_CAP_8BIT));
|
||||
throw "Insufficient memory";
|
||||
}
|
||||
|
||||
memset(this->model->Signature, 0, 10240);
|
||||
snprintf(this->model->Signature, 10240, Signature, this->model->SI_XML, this->model->SV_XML, this->model->certificate, this->model->SP_XML);
|
||||
free(this->model->SI_XML);
|
||||
free(this->model->SP_XML);
|
||||
free(this->model->SV_XML);
|
||||
free(this->model->certificate);
|
||||
}
|
||||
catch(const char* msg){
|
||||
this->vw->setLabel((char *) msg);
|
||||
this->vw->showLoader(false);
|
||||
throw msg;
|
||||
}
|
||||
}
|
||||
74
extended-setup/main/impl/controllers/VoteController.cpp
Normal file
74
extended-setup/main/impl/controllers/VoteController.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* @file VoteController.cpp
|
||||
* @brief VoteController implementation file
|
||||
* */
|
||||
|
||||
#include "cJSON.h"
|
||||
#include "controller.h"
|
||||
|
||||
VoteController::VoteController(BaseModel *model, const char * sni){
|
||||
|
||||
this->vw = new IndexView();
|
||||
this->model = static_cast<VoteModel *>(model);
|
||||
this->sni = sni;
|
||||
}
|
||||
|
||||
void VoteController::index(){
|
||||
|
||||
try{
|
||||
this->vw->render((void *) "Voting");
|
||||
this->vw->setLabel((char *) "Casting vote");
|
||||
this->vw->showLoader(true);
|
||||
// send last hash to vote and get voteID
|
||||
ESP_LOGI(TAG, "final voting request sent");
|
||||
cJSON* voteJson = RPC::Instance().send_json_rpc(sni, generateVoteRequestJSON()); //! * send signed digital ballot to voting service
|
||||
|
||||
if(voteJson == NULL){
|
||||
throw "Empty response";
|
||||
}
|
||||
if(cJSON_GetObjectItem(voteJson, "error")->valuestring != NULL){ //! * check error message
|
||||
throw cJSON_GetObjectItem(voteJson, "error")->valuestring;
|
||||
}
|
||||
|
||||
cJSON* result = cJSON_GetObjectItem(voteJson, "result"); //! * if no error, parse result
|
||||
size_t len = strlen(cJSON_GetObjectItem(result, "VoteID")->valuestring);
|
||||
this->model->voteID = (char *) malloc(len+1); //! * allocate memory and store voteID
|
||||
memset(this->model->voteID, 0, len+1);
|
||||
memcpy(this->model->voteID, cJSON_GetObjectItem(result, "VoteID")->valuestring,len);
|
||||
|
||||
cJSON_Delete(voteJson);
|
||||
ESP_LOGI(TAG, "voteID: %s", this->model->voteID);
|
||||
this->vw->setLabel((char *) "Vote casted");
|
||||
this->vw->showLoader(false);
|
||||
}
|
||||
catch(const char *msg){
|
||||
this->vw->setLabel((char *) msg);
|
||||
this->vw->showLoader(false);
|
||||
throw msg;
|
||||
}
|
||||
}
|
||||
|
||||
char* VoteController::generateVoteRequestJSON(){
|
||||
|
||||
cJSON *root, *params, *param;
|
||||
root = cJSON_CreateObject();
|
||||
cJSON_AddNumberToObject(root, "id", 0.0);
|
||||
cJSON_AddItemToObject(root, "method", cJSON_CreateString("RPC.Vote"));
|
||||
|
||||
params = cJSON_CreateArray();
|
||||
cJSON_AddItemToObject(root, "params", params);
|
||||
|
||||
cJSON_AddItemToArray(params, param=cJSON_CreateObject());
|
||||
cJSON_AddStringToObject(param, "AuthMethod", "ticket");
|
||||
cJSON_AddStringToObject(param, "AuthToken", this->model->authToken);
|
||||
cJSON_AddStringToObject(param, "Choices", this->model->choices);
|
||||
cJSON_AddStringToObject(param, "SessionID", this->model->ssid);
|
||||
cJSON_AddStringToObject(param, "OS", "FreeRTOS");
|
||||
cJSON_AddStringToObject(param, "Type", "bdoc");
|
||||
cJSON_AddStringToObject(param, "Vote", (char *) this->model->voteBase64);
|
||||
|
||||
char* pretty = cJSON_Print(root);
|
||||
cJSON_Delete(root);
|
||||
|
||||
return pretty;
|
||||
}
|
||||
96
extended-setup/main/impl/controllers/ZipController.cpp
Normal file
96
extended-setup/main/impl/controllers/ZipController.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* @file ZipController.cpp
|
||||
* @brief ZipController implementation file
|
||||
* */
|
||||
|
||||
#include "miniz.h"
|
||||
#include "controller.h"
|
||||
|
||||
ZipController::ZipController(BaseModel *model){
|
||||
|
||||
this->vw = new IndexView();
|
||||
this->model = static_cast<ZipModel *>(model);
|
||||
}
|
||||
|
||||
void ZipController::index(){
|
||||
|
||||
try{
|
||||
this->vw->render((void *) "Sign" );
|
||||
this->vw->setLabel((char *) "Creating BDOC");
|
||||
this->vw->showLoader(true);
|
||||
// create a container with .ballot and .xml files
|
||||
mz_bool status;
|
||||
mz_zip_archive bdoc;
|
||||
mz_zip_zero_struct(&bdoc);
|
||||
size_t len;
|
||||
status = mz_zip_writer_init_heap(&bdoc, 0,10240); //! * init zip heap
|
||||
if(!status){
|
||||
throw mz_zip_get_error_string(bdoc.m_last_error);
|
||||
}
|
||||
|
||||
// Add mimefile
|
||||
char *mimetype = (char *) "application/vnd.etsi.asic-e+zip"; //! * add mimetype file to zip
|
||||
status = mz_zip_writer_add_mem(&bdoc, "mimetype", (void *) mimetype, strlen(mimetype), MZ_NO_COMPRESSION);
|
||||
if (!status){
|
||||
throw mz_zip_get_error_string(bdoc.m_last_error);
|
||||
}
|
||||
|
||||
// Add manifest.xml
|
||||
char* manifestXML = (char *) malloc(512);
|
||||
memset(manifestXML,0,512);
|
||||
snprintf(manifestXML, 512, manifest, "EP2065.1.ballot");
|
||||
|
||||
status = mz_zip_writer_add_mem(&bdoc, "META-INF/manifest.xml", (void *)manifestXML, strlen(manifestXML), MZ_NO_COMPRESSION); //! * add manifest.xml file to zip
|
||||
if (!status){
|
||||
throw mz_zip_get_error_string(bdoc.m_last_error);
|
||||
}
|
||||
|
||||
// Add ballot file
|
||||
status = mz_zip_writer_add_mem(&bdoc, this->model->ballotFileName, (void *) this->model->ballot, this->model->ballotLength, MZ_NO_COMPRESSION); //! * add ballot file to zip
|
||||
if (!status){
|
||||
throw mz_zip_get_error_string(bdoc.m_last_error);
|
||||
}
|
||||
|
||||
// Add signature0.xml
|
||||
status = mz_zip_writer_add_mem(&bdoc, "META-INF/signatures0.xml", (void *) this->model->Signature, strlen(this->model->Signature), MZ_NO_COMPRESSION); //! * add signature file to zip
|
||||
|
||||
if (!status){
|
||||
throw mz_zip_get_error_string(bdoc.m_last_error);
|
||||
}
|
||||
// Close zip file
|
||||
void *zipBuf;
|
||||
status = mz_zip_writer_finalize_heap_archive(&bdoc, &zipBuf, &len);
|
||||
if (!status){
|
||||
throw mz_zip_get_error_string(bdoc.m_last_error);
|
||||
}
|
||||
|
||||
status = mz_zip_writer_end(&bdoc);
|
||||
if (!status){
|
||||
throw "zip end failed";
|
||||
}
|
||||
|
||||
// hash container
|
||||
this->model->voteBase64 = (unsigned char *)malloc(2*len);
|
||||
if(this->model->voteBase64 == NULL){
|
||||
throw "Insufficient memory";
|
||||
}
|
||||
memset(this->model->voteBase64, 0, 2*len);
|
||||
|
||||
int error = mbedtls_base64_encode(this->model->voteBase64, 2*len - 1, &len, (unsigned char *) zipBuf, len); //! * base64 encode zip file
|
||||
if(error) {
|
||||
throw "Base64 encode error";
|
||||
}
|
||||
|
||||
mz_free(zipBuf);
|
||||
free(this->model->Signature);
|
||||
free(this->model->ballot);
|
||||
|
||||
this->vw->setLabel((char*) "Signature complete");
|
||||
this->vw->showLoader(false);
|
||||
}
|
||||
catch(const char *msg){
|
||||
this->vw->setLabel((char *) msg);
|
||||
this->vw->showLoader(false);
|
||||
throw msg;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user