From: Christoph Egger Date: Mon, 6 Jan 2020 01:00:47 +0000 (+0100) Subject: Code drop X-Git-Url: https://git.siccegge.de//index.cgi?a=commitdiff_plain;h=006e87bc592a4e6eabea4f7f9caab8e218ebfd85;p=software%2FDIPE.git Code drop --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b25c15b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/CMakeLists.txt b/CMakeLists.txt index 8340506..823157a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,10 @@ cmake_minimum_required (VERSION 2.8.11) project (DIPE) +include(CTest) +include(GoogleTest) + +set(CMAKE_VERBOSE_MAKEFILE on) + add_subdirectory(src) +add_subdirectory(tests) diff --git a/doc/source/api.rst b/doc/source/api.rst new file mode 100644 index 0000000..3bb3d6e --- /dev/null +++ b/doc/source/api.rst @@ -0,0 +1,57 @@ +API Documentation +================= + +Types +----- + +.. c:type:: dipe_param_t + + Stores public parameters used in DIPE. Initialized by :c:func:`dipe_init()` and freed by :c:func:`dipe_free_param` + +.. c:type:: dipe_master_secretkey_t +.. c:type:: dipe_master_publickey_t +.. c:type:: dipe_secretkey_t +.. c:type:: dipe_ctxt_t + +Functions +--------- + +Initialization +~~~~~~~~~~~~~~ + +.. c:function:: void dipe_init(FILE* configfp, dipe_param_t* param) + + initializes public parameters as well as the PBC library + + :param configfp: File structure holding the pairing group definition as understood by PBC + +Key Generation +~~~~~~~~~~~~~~ + +.. c:function:: void dipe_master_keygen(dipe_param_t param, size_t dimension, dipe_master_publickey_t* pk, dipe_master_secretkey_t* sk); + +.. c:function:: void dipe_keygen(dipe_param_t param, dipe_master_secretkey_t msk, char* cid, element_t* y, dipe_secretkey_t* sk); + + :param cid: Client ID, expected to be 16 bytes + :param y: Policy vector for the secret key that is to be generated. Must match with the dimensions when `msk` was generated + :type y: Array of Zn elements + +En/Decryption +~~~~~~~~~~~~~ + +.. c:function:: void dipe_encrypt(dipe_param_t param, dipe_master_publickey mpk, element_t* x, element_t ptxt, dipe_ctxt_t* ctxt) +.. c:function:: void dipe_decrypt(dipe_param_t param, dipe_secretkey_t sk, char* cid, element_t* y, dipe_ctxt_t ctxt, element_t* ptxt) + + :param result: It is the responsibility of the caller to initialize the element to GT and to free it after usage + :type result: :c:type:`element_t` + +Memory Management +~~~~~~~~~~~~~~~~~ + +.. c:function:: void dipe_free_param(dipe_param_t param); +.. c:function:: void dipe_free_master_secretkey(dipe_master_secretkey_t sk); +.. c:function:: void dipe_free_master_publickey(dipe_master_publickey_t pk); +.. c:function:: void dipe_free_secretkey(dipe_secretkey_t sk); + + + diff --git a/doc/source/index.rst b/doc/source/index.rst index 765b815..6e799b7 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -10,6 +10,7 @@ Welcome to DIPE's documentation! :maxdepth: 2 :caption: Contents: + api Indices and tables diff --git a/include/DIPE.h b/include/DIPE.h new file mode 100644 index 0000000..87ebab8 --- /dev/null +++ b/include/DIPE.h @@ -0,0 +1,25 @@ +#include +#include + +extern "C" { + typedef struct dipe_param* dipe_param_t; + typedef struct dipe_master_publickey* dipe_master_publickey_t; + typedef struct dipe_master_secretkey* dipe_master_secretkey_t; + typedef struct dipe_secretkey* dipe_secretkey_t; + typedef struct dipe_ctxt* dipe_ctxt_t; + + void dipe_init(FILE* configfp, dipe_param_t* param); + pairing_t* dipe_get_pairing(dipe_param_t param); + + void dipe_master_keygen(dipe_param_t param, size_t dimension, dipe_master_publickey_t* pk, dipe_master_secretkey_t* sk); + void dipe_keygen(dipe_param_t param, dipe_master_secretkey_t msk, char* cid, element_t* y, dipe_secretkey_t* sk); + + void dipe_encrypt(dipe_param_t param, dipe_master_publickey_t mpk, element_t* x, element_t ptxt, dipe_ctxt_t* ctxt); + void dipe_decrypt(dipe_param_t param, dipe_secretkey_t sk, char* cid, element_t* y, dipe_ctxt_t ctxt, element_t ptxt); + + void dipe_free_param(dipe_param_t param); + void dipe_free_master_secretkey(dipe_master_secretkey_t sk); + void dipe_free_master_publickey(dipe_master_publickey_t pk); + void dipe_free_secretkey(dipe_secretkey_t sk); + void dipe_free_ctxt(dipe_ctxt_t ctxt); +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2d3ee83..ce0076e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,12 @@ option(BUILD_SHARED_LIBS "Build using shared libraries" ON) add_library (DIPE DIPE.cxx) +add_definitions(-Wall -Wextra -Werror) + # Make sure the compiler can find include files for our Hello library # when other libraries or executables link to Hello -target_include_directories (DIPE PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_include_directories (DIPE PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include/) + +target_link_libraries(DIPE pbc) +target_link_libraries(DIPE gmp) +target_link_libraries(DIPE crypto) diff --git a/src/DIPE.cxx b/src/DIPE.cxx index e69de29..321372d 100644 --- a/src/DIPE.cxx +++ b/src/DIPE.cxx @@ -0,0 +1,250 @@ +#include "DIPE.h" +#include + +struct dipe_param { + pairing_t pairing; + element_t g1; + element_t g2; + element_t gt; +}; + +struct dipe_master_publickey { + size_t dimension; + element_t a; + element_t* k; +}; + +struct dipe_master_secretkey { + size_t dimension; + element_t a; + element_t* k; +}; + +struct dipe_secretkey { + size_t dimension; + element_t d; +}; + +struct dipe_ctxt { + size_t dimension; + element_t s; + element_t* cx; + element_t c; +}; + + +namespace { + size_t dipe_h_length(element_t elem, size_t dimension) { + return 16 /*cid*/ + dimension * element_length_in_bytes(elem); + } + + void dipe_generate_h(char* cid, element_t* y, size_t dimension, unsigned char* result) { + memcpy(result, cid, 16); + unsigned char* next_element = result+16; + for (size_t i = 0; i < dimension; ++i) { + element_to_bytes(next_element, y[i]); + next_element += element_length_in_bytes(y[0]); + } + } +} + +void dipe_init(FILE* configfp, dipe_param_t* param) { + char buffer[2<<16]; + (*param) = (dipe_param_t)malloc(sizeof(dipe_param)); + fread(buffer, 1, 2<<16, configfp); + + pairing_init_set_buf((*param)->pairing, buffer, 2<<16); + + element_init_G1((*param)->g1, (*param)->pairing); + element_init_G2((*param)->g2, (*param)->pairing); + element_init_GT((*param)->gt, (*param)->pairing); + + element_random((*param)->g1); + element_random((*param)->g2); + pairing_apply((*param)->gt, (*param)->g1, (*param)->g2, (*param)->pairing); +} + +pairing_t* dipe_get_pairing(dipe_param_t param) { + return &(param->pairing); +} + +void dipe_master_keygen(dipe_param_t param, size_t dimension, dipe_master_publickey_t* pk, dipe_master_secretkey_t* sk) { + *pk = (dipe_master_publickey_t)malloc(sizeof(dipe_master_publickey)); + *sk = (dipe_master_secretkey_t)malloc(sizeof(dipe_master_secretkey)); + + (*sk)->dimension = (*pk)->dimension = dimension; + + element_init_Zr((*sk)->a, param->pairing); + element_init_GT((*pk)->a, param->pairing); + element_random((*sk)->a); + element_pow_zn((*pk)->a, param->gt, (*sk)->a); + + (*sk)->k = (element_t*)calloc(dimension, sizeof(element_t)); + (*pk)->k = (element_t*)calloc(dimension, sizeof(element_t)); + for (size_t i = 0; i < dimension; ++i) { + element_init_Zr((*sk)->k[i], param->pairing); + element_init_G1((*pk)->k[i], param->pairing); + element_random((*sk)->k[i]); + element_pow_zn((*pk)->k[i], param->gt, (*sk)->k[i]); + } +} + +void dipe_keygen(dipe_param_t param, dipe_master_secretkey_t msk, char* cid, element_t* y, dipe_secretkey_t* sk) { + *sk = (dipe_secretkey_t)malloc(sizeof(dipe_secretkey)); + (*sk)->dimension = msk->dimension; + element_init_G2((*sk)->d, param->pairing); + + size_t hash_input_length = dipe_h_length(y[0], msk->dimension); + unsigned char hash_input[hash_input_length]; + element_t h; + element_init_G2(h, param->pairing); + + dipe_generate_h(cid, y, msk->dimension, hash_input); + element_from_hash(h, hash_input, hash_input_length); + + element_t innerp; + element_t tmp; + + element_init_Zr(innerp, param->pairing); + element_init_Zr(tmp, param->pairing); + element_set1(innerp); + + element_from_hash(h, hash_input, hash_input_length); + + for (size_t i = 0; i < msk->dimension; ++i) { + element_mul(tmp, y[i], msk->k[i]); + element_add(innerp, innerp, tmp); + } + + element_t a2; + element_init_G2(a2, param->pairing); + element_pow_zn(h, h, innerp); + element_pow_zn(a2, param->g2, msk->a); + element_mul((*sk)->d, a2, h); + + element_clear(h); + element_clear(innerp); + element_clear(tmp); + element_clear(a2); +} + +void dipe_encrypt(dipe_param_t param, dipe_master_publickey_t mpk, element_t* x, element_t ptxt, dipe_ctxt_t* ctxt) { + *ctxt = (dipe_ctxt_t)malloc(sizeof(dipe_ctxt)); + (*ctxt)->dimension = mpk->dimension; + + element_t r; + element_t s; + element_init_Zr(r, param->pairing); + element_init_Zr(s, param->pairing); + + element_random(r); + element_random(s); + + element_init_G1((*ctxt)->s, param->pairing); + element_pow_zn((*ctxt)->s, param->g1, s); + + element_t k1; + element_t x1; + element_init_G1(k1, param->pairing); + element_init_G1(x1, param->pairing); + + (*ctxt)->cx = (element_t*)calloc(mpk->dimension, sizeof(element_t)); + for (size_t i = 0; i < mpk->dimension; ++i){ + element_pow_zn(x1, param->g1, x[i]); + element_pow_zn(x1, x1, r); + + element_pow_zn(k1, mpk->k[i], s); + + element_init_G1((*ctxt)->cx[i], param->pairing); + element_mul((*ctxt)->cx[i], k1, x1); + } + + element_t at; + element_init_GT(at, param->pairing); + element_pow_zn(at, mpk->a, s); + element_init_GT((*ctxt)->c, param->pairing); + element_mul((*ctxt)->c, at, ptxt); + + element_clear(r); + element_clear(s); + element_clear(k1); + element_clear(x1); + element_clear(at); +} + + +void dipe_decrypt(dipe_param_t param, dipe_secretkey_t sk, char* cid, element_t* y, dipe_ctxt_t ctxt, element_t ptxt) { + size_t hash_input_length = dipe_h_length(y[0], sk->dimension); + unsigned char hash_input[hash_input_length]; + element_t h; + element_init_G2(h, param->pairing); + + dipe_generate_h(cid, y, sk->dimension, hash_input); + element_from_hash(h, hash_input, hash_input_length); + + element_t tmp; + element_t innerp; + element_t hy; + element_init_GT(tmp, param->pairing); + element_init_GT(innerp, param->pairing); + element_init_G2(hy, param->pairing); + + element_set1(innerp); + for (size_t i = 0; i < sk->dimension; ++i) { + element_pow_zn(hy, h, y[i]); + pairing_apply(tmp, ctxt->cx[i], hy, param->pairing); + element_mul(innerp, innerp, tmp); + } + + pairing_apply(ptxt, ctxt->s, sk->d, param->pairing); + element_invert(ptxt, ptxt); + element_mul(ptxt, ptxt, ctxt->c); + element_mul(ptxt, ptxt, innerp); + + element_clear(h); + element_clear(tmp); + element_clear(innerp); + element_clear(hy); +} + + +void dipe_free_param(dipe_param_t param) { + element_clear(param->g1); + element_clear(param->g2); + element_clear(param->gt); + pairing_clear(param->pairing); + free(param); +} + +void dipe_free_master_secretkey(dipe_master_secretkey_t sk) { + for (size_t i = 0; i < sk->dimension; ++i) { + element_clear(sk->k[i]); + } + element_clear(sk->a); + free(sk->k); + free(sk); +} + +void dipe_free_master_publickey(dipe_master_publickey_t pk) { + for (size_t i = 0; i < pk->dimension; ++i) { + element_clear(pk->k[i]); + } + element_clear(pk->a); + free(pk->k); + free(pk); +} + +void dipe_free_secretkey(dipe_secretkey_t sk) { + element_clear(sk->d); + free(sk); +} + +void dipe_free_ctxt(dipe_ctxt_t ctxt) { + for (size_t i = 0; i < ctxt->dimension; ++i) { + element_clear(ctxt->cx[i]); + } + element_clear(ctxt->c); + element_clear(ctxt->s); + free(ctxt->cx); + free(ctxt); +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..288ed8c --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,20 @@ +macro(package_add_test TESTNAME) + # create an exectuable in which the tests will be stored + add_executable(${TESTNAME} ${ARGN}) + # link the Google test infrastructure, mocking library, and a default main fuction to + # the test executable. Remove g_test_main if writing your own main function. + target_link_libraries(${TESTNAME} gtest gtest_main DIPE) + # gtest_discover_tests replaces gtest_add_tests, + # see https://cmake.org/cmake/help/v3.10/module/GoogleTest.html for more options to pass to it + gtest_discover_tests(${TESTNAME} + # set a working directory so your project root so that you can find test data via paths relative to the project root + WORKING_DIRECTORY ${PROJECT_DIR} + PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${PROJECT_DIR}" + ) + set_target_properties(${TESTNAME} PROPERTIES FOLDER tests) +endmacro() + +add_subdirectory(/usr/src/gtest gtest) + +package_add_test(testDIPE testDIPE.cpp) +package_add_test(testPBC testPBC.cpp) diff --git a/tests/a.param b/tests/a.param new file mode 100644 index 0000000..cee0e9b --- /dev/null +++ b/tests/a.param @@ -0,0 +1,8 @@ +type a +q 8780710799663312522437781984754049815806883199414208211028653399266475630880222957078625179422662221423155858769582317459277713367317481324925129998224791 +h 12016012264891146079388821366740534204802954401251311822919615131047207289359704531102844802183906537786776 +r 730750818665451621361119245571504901405976559617 +exp2 159 +exp1 107 +sign1 1 +sign0 1 diff --git a/tests/testDIPE.cpp b/tests/testDIPE.cpp new file mode 100644 index 0000000..0a3e209 --- /dev/null +++ b/tests/testDIPE.cpp @@ -0,0 +1,130 @@ +#include +#include + +#include "DIPE.h" + +static dipe_param_t param; + +TEST(DipeTest, DipeMasterKeygen) { + dipe_master_publickey_t pk; + dipe_master_secretkey_t sk; + + dipe_master_keygen(param, 12, &pk, &sk); + + dipe_free_master_secretkey(sk); + dipe_free_master_publickey(pk); +} + +TEST(DipeTest, DipeKeygen) { + dipe_master_publickey_t pk; + dipe_master_secretkey_t msk; + dipe_secretkey_t sk; + element_t y[5]; + for (size_t i = 0; i < 5; ++i) { + element_init_Zr(y[i], *dipe_get_pairing(param)); + element_random(y[i]); + } + + dipe_master_keygen(param, 5, &pk, &msk); + dipe_keygen(param, msk, "1234567890abcdef", y, &sk); + + dipe_free_master_secretkey(msk); + dipe_free_master_publickey(pk); + dipe_free_secretkey(sk); + + for (size_t i = 0; i < 5; ++i) { + element_clear(y[i]); + } +} + +TEST(DipeTest, DipeDecryptFail) { + dipe_ctxt_t ctxt; + dipe_master_publickey_t pk; + dipe_master_secretkey_t msk; + dipe_secretkey_t sk; + + element_t y[5]; + for (size_t i = 0; i < 5; ++i) { + element_init_Zr(y[i], *dipe_get_pairing(param)); + element_random(y[i]); + } + + dipe_master_keygen(param, 5, &pk, &msk); + dipe_keygen(param, msk, "1234567890abcdef", y, &sk); + + element_t ptxt, ptxtp; + element_init_GT(ptxt, *dipe_get_pairing(param)); + element_init_GT(ptxtp, *dipe_get_pairing(param)); + + element_random(ptxt); + + dipe_encrypt(param, pk, y, ptxt, &ctxt); + dipe_decrypt(param, sk, "1234567890abcdef", y, ctxt, ptxtp); + + EXPECT_NE(element_cmp(ptxt, ptxtp), 0); + + for (size_t i = 0; i < 5; ++i) { + element_clear(y[i]); + } + + element_clear(ptxt); + element_clear(ptxtp); + + dipe_free_master_secretkey(msk); + dipe_free_master_publickey(pk); + dipe_free_secretkey(sk); + dipe_free_ctxt(ctxt); +} + +TEST(DipeTest, DipeDecryptSuccess) { + dipe_ctxt_t ctxt; + dipe_master_publickey_t pk; + dipe_master_secretkey_t msk; + dipe_secretkey_t sk; + + element_t y[5]; + for (size_t i = 0; i < 5; ++i) { + element_init_Zr(y[i], *dipe_get_pairing(param)); + element_set0(y[i]); + } + + dipe_master_keygen(param, 5, &pk, &msk); + dipe_keygen(param, msk, "1234567890abcdef", y, &sk); + + element_t ptxt, ptxtp; + element_init_GT(ptxt, *dipe_get_pairing(param)); + element_init_GT(ptxtp, *dipe_get_pairing(param)); + + element_random(ptxt); + + dipe_encrypt(param, pk, y, ptxt, &ctxt); + dipe_decrypt(param, sk, "1234567890abcdef", y, ctxt, ptxtp); + element_printf("%B\n", ptxt); + element_printf("%B\n", ptxtp); + + EXPECT_EQ(element_cmp(ptxt, ptxtp), 0); + + for (size_t i = 0; i < 5; ++i) { + element_clear(y[i]); + } + + element_clear(ptxt); + element_clear(ptxtp); + + dipe_free_master_secretkey(msk); + dipe_free_master_publickey(pk); + dipe_free_secretkey(sk); + dipe_free_ctxt(ctxt); +} + + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + + dipe_init(fopen("../tests/a.param", "r"), ¶m); + + int result = RUN_ALL_TESTS(); + dipe_free_param(param); + return result; +} + diff --git a/tests/testPBC.cpp b/tests/testPBC.cpp new file mode 100644 index 0000000..826ec1b --- /dev/null +++ b/tests/testPBC.cpp @@ -0,0 +1,71 @@ +#include +#include + +#include "DIPE.h" + +static pairing_t pairing; + + +/* PBC is using multiplicative notion and ONE is indeed the neutral + * element wrt multiplication. + */ +TEST(PbcTest, PbcOneTest) { + element_t g1; + element_t z; + element_t g1z; + + element_init_G1(g1, pairing); + element_init_Zr(z, pairing); + element_init_G1(g1z, pairing); + + element_set1(g1); + element_random(z); + element_pow_zn(g1z, g1, z); + + EXPECT_EQ(element_cmp(g1, g1z), 0); + + element_clear(g1); + element_clear(z); + element_clear(g1z); +} + +TEST(PbcTest, PbcFromHash) { + char test1[] = "pbctest1"; + char test2[] = "pbctest2"; + element_t a, b; + + element_init_G2(a, pairing); + element_init_G2(b, pairing); + + element_from_hash(a, test1, 8); + element_from_hash(b, test1, 8); + EXPECT_EQ(element_cmp(a, b), 0); + + element_from_hash(a, test1, 8); + element_from_hash(b, test2, 8); + EXPECT_NE(element_cmp(a, b), 0); + + element_clear(a); + element_clear(b); +} + +int main(int argc, char **argv) { + char buffer[2<<16]; + ::testing::InitGoogleTest(&argc, argv); + + FILE *fp; + fp = fopen("../tests/a.param", "r"); + if (fp == NULL) { + perror("Reading Pairing Parameters"); + return 1; + } + size_t count = fread(buffer, 1, 2<<16, fp); + + pairing_init_set_buf(pairing, buffer, 2<<16); + + + int result = RUN_ALL_TESTS(); + pairing_clear(pairing); + return result; +} +