int32_t test(int32_t M,int32_t N,int32_t datasize) { int ok = 1, i; uint8_t * secret = malloc(datasize); uint8_t *shares[255]; uint8_t *recomb = malloc(datasize); uint8_t sharenrs[255],newsharenrs[255];// = (uint8_t *)strdup("0124z89abehtr"); gfshare_ctx *G; gfshare_fill_rand = gfshare_bad_idea_but_fill_rand_using_random; for (i=0; i<N; i++) { sharenrs[i] = i+1; shares[i] = malloc(datasize); } /* Stage 1, make a secret */ for( i = 0; i < datasize; ++i ) secret[i] = (rand() & 0xff00) >> 8; /* Stage 2, split it N ways with a threshold of M */ G = gfshare_ctx_init_enc( sharenrs, N, M, datasize ); gfshare_ctx_enc_setsecret( G, secret ); for (i=0; i<N; i++) gfshare_ctx_enc_getshare( G, i, shares[i] ); gfshare_ctx_free( G ); /* Prep the decode shape */ G = gfshare_ctx_init_dec( sharenrs, N, datasize ); memset(newsharenrs,0,N); int32_t j,r; for (i=0; i<M; i++) { r = rand() % N; while ( (j= sharenrs[r]) == 0 || newsharenrs[r] != 0 ) r = rand() % N; newsharenrs[r] = j; sharenrs[r] = 0; } for (i=0; i<N; i++) { if ( newsharenrs[i] != 0 ) gfshare_ctx_dec_giveshare( G, i, shares[i] ); //newsharenrs[i] = sharenrs[i]; } /* Stage 3, attempt a recombination with shares 1 and 2 */ //sharenrs[2] = 0; gfshare_ctx_dec_newshares( G, newsharenrs ); gfshare_ctx_dec_extract( G, recomb ); for( i = 0; i < datasize; ++i ) if( secret[i] != recomb[i] ) ok = 0; printf("M.%-3d N.%-3d ok.%d datalen.%d\n",M,N,ok,datasize); free(recomb), free(secret); for (i=0; i<N; i++) free(shares[i]); return ok!=1; }
pph_context* pph_init_context(uint8 threshold, uint8 partial_bytes) { pph_context *context; // this is a specific initialization constant unsigned char share_numbers[MAX_NUMBER_OF_SHARES]; unsigned int i; // 1) CHECK ARGUMENT SANITY // threshold if(threshold == 0 || threshold > MAX_NUMBER_OF_SHARES) { return NULL; } if(partial_bytes > DIGEST_LENGTH) { return NULL; } // 2)INITIALIZE DATA STRUCTURES context = malloc(sizeof(*context)); if(context == NULL) { return NULL; } context->threshold=threshold; // initialize the partial bytes offset, this will be used to limit the // length of the shares, and the length of the digest to xor/encrypt. context->partial_bytes=partial_bytes; // 3) generate random secret, we generate a random byte stream and append // half of the 16 byte hash to the end of it, we have chosen to use // only four hash bytes in order to have more random bytes. context->secret = generate_pph_secret( SIGNATURE_RANDOM_BYTE_LENGTH-partial_bytes, SIGNATURE_HASH_BYTE_LENGTH); if(context->secret == NULL) { free(context); return NULL; } // 4) Initialize the rest of the values. context->available_shares = (uint8)MAX_NUMBER_OF_SHARES; // since this is a new context, it should be unlocked. context->is_unlocked = true; // We are using the secret to encrypt thresholdless accounts, so we set the // AES key to be the same as the secret. context->AES_key = context->secret; // initialize the rest context->next_entry=1; context->account_data=NULL; // 5) Initialize share context for(i=0;i<MAX_NUMBER_OF_SHARES;i++) { share_numbers[i]=(unsigned char)i+1; } // Update the share context, the size of the shares is reduced by the number // or partial bytes. context->share_context = NULL; context->share_context = gfshare_ctx_init_enc( share_numbers, MAX_NUMBER_OF_SHARES-1, context->threshold, SHARE_LENGTH-partial_bytes); if(context->share_context == NULL) { free(context->secret); free(context); return NULL; } gfshare_ctx_enc_setsecret(context->share_context, context->secret); // finish, return our product return context; }
PPH_ERROR pph_unlock_password_data(pph_context *ctx,unsigned int username_count, const uint8 *usernames[], unsigned int username_lengths[], const uint8 *passwords[]){ uint8 share_numbers[MAX_NUMBER_OF_SHARES]; gfshare_ctx *G; unsigned int i; uint8 secret[SHARE_LENGTH]; uint8 salted_password[MAX_USERNAME_LENGTH+MAX_SALT_LENGTH]; uint8 estimated_digest[DIGEST_LENGTH]; uint8 estimated_share[SHARE_LENGTH]; pph_entry *entry; pph_account_node *current_user; //sanitize the data. if(ctx == NULL || usernames == NULL || passwords == NULL || username_lengths == NULL){ return PPH_BAD_PTR; } if(username_count < ctx->threshold){ return PPH_ACCOUNT_IS_INVALID; } // initialize the share numbers for(i=0;i<MAX_NUMBER_OF_SHARES;i++){ share_numbers[i] = 0; } // initialize a recombination context G = gfshare_ctx_init_dec( share_numbers, MAX_NUMBER_OF_SHARES-1, SHARE_LENGTH-ctx->partial_bytes); // traverse our possible users current_user=ctx->account_data; while(current_user!=NULL){ // check if each of the provided users is inside the context. We traverse // our user list inside the while, and compare against the provided users // inside this for loop. for(i = 0; i<username_count;i++){ //compare the proposed against existing users. if(username_lengths[i] == current_user->account.username_length && (!memcmp(usernames[i],current_user->account.username, current_user->account.username_length))){ // this is an existing user entry = current_user->account.entries; // check if he is a threshold account. if(entry->share_number != 0){ // if he is a threshold account, we must attempt to reconstruct the // shares using their information, traverse his entries while(entry!=NULL){ // calulate the digest given the password. memcpy(salted_password,entry->salt,entry->salt_length); memcpy(salted_password+entry->salt_length, passwords[i], entry->password_length); _calculate_digest(estimated_digest,salted_password, MAX_SALT_LENGTH + current_user->account.entries->password_length); // xor the obtained digest with the polyhashed value to obtain // our share. _xor_share_with_digest(estimated_share,entry->polyhashed_value, estimated_digest,SHARE_LENGTH-ctx->partial_bytes); // give share to the recombinator. share_numbers[entry->share_number] = entry->share_number+1; gfshare_ctx_dec_giveshare(G, entry->share_number,estimated_share); // move to the next entry. entry = entry->next; } } } } current_user = current_user->next; } // now we attempt to recombine the secret, we have given him all of the // obtained shares. gfshare_ctx_dec_newshares(G, share_numbers); gfshare_ctx_dec_extract(G, secret); // verify that we got a proper secret back. if(check_pph_secret(secret, SIGNATURE_RANDOM_BYTE_LENGTH-ctx->partial_bytes, SIGNATURE_HASH_BYTE_LENGTH) != PPH_ERROR_OK){ return PPH_ACCOUNT_IS_INVALID; } // else, we have a correct secret and we will copy it back to the provided // context. if(ctx->secret == NULL){ ctx->secret = calloc(sizeof(ctx->secret),SHARE_LENGTH-ctx->partial_bytes); } memcpy(ctx->secret,secret,SHARE_LENGTH-ctx->partial_bytes); // if the share context is not initialized, initialize one with the // information we have about our context. if(ctx->share_context == NULL){ for(i=0;i<MAX_NUMBER_OF_SHARES;i++){ share_numbers[i]=(unsigned char)i+1; } ctx->share_context = gfshare_ctx_init_enc( share_numbers, MAX_NUMBER_OF_SHARES-1, ctx->threshold, SHARE_LENGTH-ctx->partial_bytes); } // we have an initialized share context, we set the recombined secret to it // and set the unlock flag to one so it is ready to use. gfshare_ctx_enc_setsecret(ctx->share_context, ctx->secret); ctx->is_unlocked = true; ctx->AES_key = ctx->secret; return PPH_ERROR_OK; }