This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
cryptic/cryptic/maths/quadratic_residues_group.c

529 lines
17 KiB
C

/* Cryptic -- Cryptographic tools and protocols
* Copyright (C) 2009 Mikaël Ates <mates@entrouvert.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <glib.h>
#include <glib-object.h>
#include <openssl/bn.h>
#include "../errors.h"
#include "../utils.h"
#include "quadratic_residues_group.h"
/*****************************************************************************/
/* private methods */
/*****************************************************************************/
static GObjectClass *parent_class = NULL;
/*****************************************************************************/
/* overridden parent class methods */
/*****************************************************************************/
static void
dispose(GObject *object)
{
CrypticQRG *qrg = CRYPTIC_QRGROUP(object);
cryptic_release_bn(qrg->pp);
cryptic_release_bn(qrg->p);
cryptic_release_bn(qrg->qq);
cryptic_release_bn(qrg->q);
cryptic_release_bn(qrg->n);
cryptic_release_bn(qrg->order);
cryptic_release_bn(qrg->phi);
cryptic_release_bn(qrg->two);
cryptic_release_bn(qrg->base);
G_OBJECT_CLASS(parent_class)->dispose(G_OBJECT(qrg));
}
/*****************************************************************************/
/* instance and class init functions */
/*****************************************************************************/
static void
instance_init(CrypticQRG *qrg)
{
qrg->pp = NULL;
qrg->p = NULL;
qrg->qq = NULL;
qrg->q = NULL;
qrg->n = NULL;
qrg->order = NULL;
qrg->phi = NULL;
qrg->two = NULL;
qrg->base = NULL;
}
static void
class_init(CrypticQRGClass *klass)
{
parent_class = g_type_class_peek_parent(klass);
G_OBJECT_CLASS(klass)->dispose = dispose;
}
/*****************************************************************************/
/* public methods */
/*****************************************************************************/
GType
cryptic_qrg_get_type()
{
static GType this_type = 0;
if (!this_type) {
static const GTypeInfo this_info = {
sizeof (CrypticQRGClass),
NULL,
NULL,
(GClassInitFunc) class_init,
NULL,
NULL,
sizeof(CrypticQRG),
0,
(GInstanceInitFunc) instance_init,
NULL
};
this_type = g_type_register_static(G_TYPE_OBJECT,
"CrypticQRG", &this_info, 0);
}
return this_type;
}
/**
* cryptic_qrg_new
* @lg_modulus: bases of the DL representation.
*
* Creates a new #CrypticQRG.
*
* Return value: a newly created #CrypticQRG object; or NULL if an error occured
*
**/
CrypticQRG*
//cryptic_qrg_new(int lg_modulus, BN_GENCB *cb)
cryptic_qrg_new(int lg_modulus)
{
int rc = CRYPTIC_ERROR_UNDEFINED;
BIGNUM *tmp1 = NULL, *tmp2 = NULL, *gcd = NULL;
BN_CTX *ctx = NULL;
BN_MONT_CTX *mont = NULL;
goto_cleanup_if_fail_with_rc_with_warning(lg_modulus >= CRYPTIC_MATHS_QR_GROUP_TEST_MODULUS_SIZE,
CRYPTIC_QRG_MODULUS_SIZE_TOO_SMALL);
BN_GENCB *cb = NULL;
CrypticQRG *qrg;
qrg = g_object_new(CRYPTIC_TYPE_QRGROUP, NULL);
goto_cleanup_if_fail_with_rc_with_warning_openssl(tmp1 = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(tmp2 = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(gcd = BN_new());
cryptic_release_bn(qrg->pp);
cryptic_release_bn(qrg->p);
cryptic_release_bn(qrg->qq);
cryptic_release_bn(qrg->q);
cryptic_release_bn(qrg->n);
cryptic_release_bn(qrg->order);
cryptic_release_bn(qrg->phi);
cryptic_release_bn(qrg->two);
cryptic_release_bn(qrg->base);
goto_cleanup_if_fail_with_rc_with_warning_openssl(qrg->p = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(qrg->pp = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(qrg->q = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(qrg->qq = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(qrg->n = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(qrg->order = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(qrg->phi = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(qrg->base = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(qrg->two = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_set_word(qrg->two,2) == 1);
goto_cleanup_if_fail_with_rc_with_warning_openssl(ctx = BN_CTX_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(mont=BN_MONT_CTX_new());
qrg->lg_modulus = lg_modulus;
int s=0;
s = (qrg->lg_modulus/2);
/************************************************************
* Find a safe prime q = 2*qq +1 with qq prime
*************************************************************/
int found=0,found2=0;
while(!found2){
found=0;
while(!found){
BN_generate_prime_ex(qrg->q,s,1,NULL,NULL,cb);
/* Redundant check (already cleanup by safe prime generation) */
if(BN_is_prime_ex(qrg->q,BN_prime_checks,ctx, cb)){
found=1;
}
}
/* div by 2 of an even number give the same result as if one is substracted before */
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_div(qrg->qq,NULL,qrg->q,qrg->two,ctx) == 1);
/* Redundant check (already cleanup by safe prime generation) */
if(BN_is_prime_ex(qrg->qq,BN_prime_checks,ctx, cb)){
found2=1;
}
}
/************************************************************
* Find a safe prime p = 2*pp +1 with pp prime
*************************************************************/
found=0,found2=0;
while(!found2){
found=0;
while(!found){
BN_generate_prime_ex(qrg->p,s,1,NULL,NULL,cb);
/* Redundant check (already cleanup by safe prime generation) */
if(BN_is_prime_ex(qrg->p,BN_prime_checks,ctx, cb)){
found=1;
}
}
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_div(qrg->pp,NULL,qrg->p,qrg->two,ctx) == 1);
/* Redundant check (already cleanup by safe prime generation) */
if(BN_is_prime_ex(qrg->pp,BN_prime_checks,ctx, cb)){
found2=1;
}
}
/************************************************************
* n = pq -> Z_n^* multiplicative groupe with generator
*************************************************************/
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mul(qrg->n,qrg->p,qrg->q,ctx) == 1);
/************************************************************
* order = ppqq -> |Z_n^*|
*************************************************************/
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mul(qrg->order,qrg->pp,qrg->qq,ctx) == 1);
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_sub(tmp1,qrg->p,BN_value_one()) == 1);
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_sub(tmp2,qrg->q,BN_value_one()) == 1);
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mul(qrg->phi,tmp1,tmp2,ctx) == 1);
/************************************************************
* random r of size n
* qr = r^2 mod n
* qr != 1 and coprime(qr-1,n)
*************************************************************/
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_MONT_CTX_set(mont,qrg->n,ctx));
do{
cryptic_check_good_rc(cryptic_find_random_with_range_value(tmp1,qrg->n));
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_exp_mont(qrg->base,tmp1,qrg->two,qrg->n,ctx,mont));
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_sub(tmp1,qrg->base,BN_value_one()));
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_gcd(gcd, tmp1, qrg->n, ctx) == 1);
}while (BN_ucmp(qrg->base, BN_value_one()) == 0 || BN_ucmp(gcd, BN_value_one()) != 0);
rc = CRYPTIC_NO_ERROR;
cleanup:
cryptic_release_ctx(ctx);
cryptic_release_mont(mont);
cryptic_release_bn(tmp1);
cryptic_release_bn(tmp2);
cryptic_release_bn(gcd);
if(rc == CRYPTIC_NO_ERROR) {return qrg;}
else{
cryptic_release_gobject(qrg);
return NULL;
}
}
/**
* cryptic_qrg_new_load:
* @p: A safe prime
* @n: Modulus
*
* Build a group of quadratic residues from a modulus and a safe prime.
*
* Return value: #CrypticQRG if successful, an error code otherwise.
*
*/
CrypticQRG*
//cryptic_qrg_new_load(BIGNUM *p, BIGNUM *n, BN_GENCB *cb)
cryptic_qrg_new_load(BIGNUM *p, BIGNUM *n, BIGNUM *base)
{
int rc = CRYPTIC_ERROR_UNDEFINED;
BIGNUM *tmp1 = NULL, *tmp2 = NULL;
BN_CTX *ctx = NULL;
goto_cleanup_if_fail_with_rc_with_warning(p != NULL,
CRYPTIC_QRG_UNABLE_TO_LOAD_QRG_MINIMAL);
goto_cleanup_if_fail_with_rc_with_warning(n != NULL,
CRYPTIC_QRG_UNABLE_TO_LOAD_QRG_MINIMAL);
goto_cleanup_if_fail_with_rc_with_warning(base != NULL,
CRYPTIC_QRG_UNABLE_TO_LOAD_QRG_MINIMAL);
BN_GENCB *cb = NULL;
CrypticQRG *qrg;
qrg = g_object_new(CRYPTIC_TYPE_QRGROUP, NULL);
goto_cleanup_if_fail_with_rc_with_warning_openssl(tmp1 = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(tmp2 = BN_new());
cryptic_release_bn(qrg->pp);
cryptic_release_bn(qrg->p);
cryptic_release_bn(qrg->qq);
cryptic_release_bn(qrg->q);
cryptic_release_bn(qrg->n);
cryptic_release_bn(qrg->order);
cryptic_release_bn(qrg->phi);
cryptic_release_bn(qrg->two);
cryptic_release_bn(qrg->base);
goto_cleanup_if_fail_with_rc_with_warning_openssl(qrg->p = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(qrg->pp = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(qrg->q = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(qrg->qq = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(qrg->n = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(qrg->order = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(qrg->phi = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(qrg->base = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(qrg->two = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_set_word(qrg->two,2) == 1);
goto_cleanup_if_fail_with_rc_with_warning_openssl(ctx = BN_CTX_new());
goto_cleanup_if_fail_with_rc_with_warning(BN_is_prime_ex(p,BN_prime_checks, ctx, cb),
CRYPTIC_MATHS_NUMBER_NOT_PRIME);
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_copy(qrg->p,p));
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_sub(qrg->pp, qrg->p, BN_value_one()) == 1);
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_div(qrg->pp, NULL, qrg->pp, qrg->two, ctx) == 1);
goto_cleanup_if_fail_with_rc_with_warning(BN_is_prime_ex(qrg->pp, BN_prime_checks, ctx, cb),
CRYPTIC_MATHS_NUMBER_NOT_PRIME);
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_copy(qrg->n,n));
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_div(qrg->q, NULL, qrg->n, qrg->p, ctx) == 1);
goto_cleanup_if_fail_with_rc_with_warning(BN_is_prime_ex(qrg->q,BN_prime_checks, ctx, cb),
CRYPTIC_MATHS_NUMBER_NOT_PRIME);
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_sub(qrg->qq,qrg->q,BN_value_one()) == 1);
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_div(qrg->qq,NULL,qrg->qq,qrg->two,ctx) == 1);
goto_cleanup_if_fail_with_rc_with_warning(BN_is_prime_ex(qrg->qq,BN_prime_checks,ctx, cb),
CRYPTIC_MATHS_NUMBER_NOT_PRIME);
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_copy(qrg->base,base));
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mul(qrg->order,qrg->pp,qrg->qq,ctx) == 1);
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_sub(tmp1,qrg->p,BN_value_one()) == 1);
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_sub(tmp2,qrg->q,BN_value_one()) == 1);
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mul(qrg->phi,tmp1,tmp2,ctx) == 1);
rc = CRYPTIC_NO_ERROR;
cleanup:
cryptic_release_ctx(ctx);
cryptic_release_bn(tmp1);
cryptic_release_bn(tmp2);
if(rc == CRYPTIC_NO_ERROR) {return qrg;}
else{
cryptic_release_gobject(qrg);
return NULL;
}
}
/**
* cryptic_qrg_verif_generator:
*
* Verify the group of quadratic residues.
*
* Here we test that the base is in QRn with the Legendre symbol
* (a/p) = 0 if p/a, A, 1 if a in QRp, -1 if a in QRp
* a in QRn in QRp in QRq
* (a/p) = a^((p-1)/2) mod p
*
* Return value: 1 if the group is ok, an error code otherwise.
*
*/
/*int
cryptic_qrg_verif_generator(CrypticQRG *qrg)
{
int rc = CRYPTIC_ERROR_UNDEFINED;
if( (cryptic_qrg_check_qr(qrg->base,qrg->p)<0) || (cryptic_qrg_check_qr(qrg->base,qrg->q)<0)){
return(CRYPTIC_MATHS_QR_GROUP_NOT_A_QR);
}
return 1;
}*/
int
cryptic_qrg_check_qr(BIGNUM *qr, BIGNUM *modulus)
{
int rc = CRYPTIC_ERROR_UNDEFINED;
BIGNUM *tmp1 = NULL, *two = NULL;
BN_CTX *ctx = NULL;
BN_MONT_CTX *mont = NULL;
goto_cleanup_if_fail_with_rc_with_warning(qr != NULL,
CRYPTIC_MATHS_QR_GROUP_NO_QR_TO_VERIFY);
goto_cleanup_if_fail_with_rc_with_warning(modulus != NULL,
CRYPTIC_MATHS_QR_GROUP_MODULUS_MISSING);
goto_cleanup_if_fail_with_rc_with_warning(BN_ucmp(qr, BN_value_one()) != 0,
CRYPTIC_MATHS_QR_GROUP_NOT_A_QR);
goto_cleanup_if_fail_with_rc_with_warning_openssl(tmp1 = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(two = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_set_word(two,2) == 1);
goto_cleanup_if_fail_with_rc_with_warning_openssl(ctx = BN_CTX_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(mont=BN_MONT_CTX_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_MONT_CTX_set(mont,modulus,ctx));
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_sub(tmp1,modulus,BN_value_one()));
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_div(tmp1,NULL,tmp1,two,ctx) == 1);
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_exp_mont(tmp1,qr,tmp1,modulus,ctx,mont));
goto_cleanup_if_fail_with_rc_with_warning(BN_ucmp(tmp1, BN_value_one()) == 0,
CRYPTIC_MATHS_QR_GROUP_NOT_A_QR);
rc = 1;
cleanup:
cryptic_release_ctx(ctx);
cryptic_release_mont(mont);
cryptic_release_bn(tmp1);
cryptic_release_bn(two);
return rc;
}
/**
* cryptic_qrg_pick_base:
* @out_base: Contain the base picked.
*
* Pick a base.
*
* Return value: CRYPTIC_NO_ERROR if successful, an error code otherwise.
*
*/
int
cryptic_qrg_pick_base(CrypticQRG *qrg, BIGNUM *out_base)
{
int rc = CRYPTIC_ERROR_UNDEFINED;
BIGNUM *rand = NULL;
BN_CTX *ctx = NULL;
BN_MONT_CTX *mont = NULL;
goto_cleanup_if_fail_with_rc_with_warning(out_base != NULL,
CRYPTIC_MATHS_QR_GROUP_BASE_UNALLOCATED);
goto_cleanup_if_fail_with_rc_with_warning_openssl(rand = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(ctx = BN_CTX_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(mont=BN_MONT_CTX_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_MONT_CTX_set(mont,qrg->n,ctx));
cryptic_check_good_rc(cryptic_find_random_with_range_value(rand,qrg->order));
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_exp_mont(out_base,qrg->base,rand,qrg->n,ctx,mont));
if( (cryptic_qrg_check_qr(out_base,qrg->p)<0) || (cryptic_qrg_check_qr(out_base,qrg->q)<0)){
return(CRYPTIC_MATHS_QR_GROUP_NOT_A_QR);
}
rc = CRYPTIC_NO_ERROR;
cleanup:
cryptic_release_ctx(ctx);
cryptic_release_mont(mont);
cryptic_release_bn(rand);
return rc;
}
/**
* cryptic_qrg_pick_k_bases:
* @out_bases: Contain the bases picked.
* @nb_bases: Number of bases to pick.
*
* Pick nb_bases bases.
*
* Return value: CRYPTIC_NO_ERROR if successful, an error code otherwise.
*
*/
int
cryptic_qrg_pick_k_bases(CrypticQRG *qrg, BIGNUM **out_bases, int nb_bases)
{
int rc = CRYPTIC_ERROR_UNDEFINED;
cryptic_return_val_if_fail(out_bases != NULL,CRYPTIC_MATHS_QR_GROUP_BASE_UNALLOCATED);
int i;
for(i=0;i<nb_bases;i++){
cryptic_return_val_if_fail(out_bases[i] != NULL,CRYPTIC_MATHS_QR_GROUP_BASE_UNALLOCATED);
}
for(i=0;i<nb_bases;i++){
cryptic_return_val_if_fail(cryptic_qrg_pick_base(qrg,out_bases[i]) == 0,
CRYPTIC_MATHS_QR_GROUP_PICKING_BASE_FAILED);
}
return(CRYPTIC_NO_ERROR);
}
/* Getters */
BIGNUM*
cryptic_qrg_get_p(CrypticQRG *qrg)
{
cryptic_return_null_if_fail(qrg->p);
return qrg->p;
}
BIGNUM*
cryptic_qrg_get_pp(CrypticQRG *qrg)
{
cryptic_return_null_if_fail(qrg->pp);
return qrg->pp;
}
BIGNUM*
cryptic_qrg_get_q(CrypticQRG *qrg)
{
cryptic_return_null_if_fail(qrg->q);
return qrg->q;
}
BIGNUM*
cryptic_qrg_get_qq(CrypticQRG *qrg)
{
cryptic_return_null_if_fail(qrg->qq);
return qrg->qq;
}
BIGNUM*
cryptic_qrg_get_order(CrypticQRG *qrg)
{
cryptic_return_null_if_fail(qrg->order);
return qrg->order;
}
BIGNUM*
cryptic_qrg_get_phi(CrypticQRG *qrg)
{
cryptic_return_null_if_fail(qrg->phi);
return qrg->phi;
}
BIGNUM*
cryptic_qrg_get_n(CrypticQRG *qrg)
{
cryptic_return_null_if_fail(qrg->n);
return qrg->n;
}