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/group_prime_order.c

282 lines
9.1 KiB
C
Executable File

/* 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 "group_prime_order.h"
/*****************************************************************************/
/* private methods */
/*****************************************************************************/
static GObjectClass *parent_class = NULL;
/*****************************************************************************/
/* overridden parent class methods */
/*****************************************************************************/
static void
dispose(GObject *object)
{
CrypticPrimeOrderGroup *group = CRYPTIC_GROUPSPRIMEORDER(object);
cryptic_release_bn(group->p);
cryptic_release_bn(group->pp);
cryptic_release_bn(group->generator);
cryptic_release_bn(group->order);
int i;
if(group->bases){
for(i=group->nb_bases-1; i = 0; i--){
cryptic_release_bn(group->bases[i]);
}
}
cryptic_release(group->bases);
G_OBJECT_CLASS(parent_class)->dispose(G_OBJECT(group));
}
/*****************************************************************************/
/* instance and class init functions */
/*****************************************************************************/
static void
instance_init(CrypticPrimeOrderGroup *group)
{
group->p = NULL;
group->pp = NULL;
group->generator = NULL;
group->order = NULL;
group->bases = NULL;
}
static void
class_init(CrypticPrimeOrderGroupClass *klass)
{
parent_class = g_type_class_peek_parent(klass);
G_OBJECT_CLASS(klass)->dispose = dispose;
}
/*****************************************************************************/
/* public methods */
/*****************************************************************************/
GType
cryptic_prime_order_group_get_type()
{
static GType this_type = 0;
if (!this_type) {
static const GTypeInfo this_info = {
sizeof (CrypticPrimeOrderGroupClass),
NULL,
NULL,
(GClassInitFunc) class_init,
NULL,
NULL,
sizeof(CrypticPrimeOrderGroup),
0,
(GInstanceInitFunc) instance_init,
NULL
};
this_type = g_type_register_static(G_TYPE_OBJECT,
"CrypticPrimeOrderGroup", &this_info, 0);
}
return this_type;
}
/**
* cryptic_prime_order_group_new
* @lg_modulus: length of the modulus of the group.
*
* Creates a new #CrypticPrimeOrderGroup.
* p prime, modulus of the group Zp^*.
* p is a safe prime, the order q is prime.
* cf. Handbook of Applied Cryptography : 11.78 p459
* a in Zp^* ; g = a^(p-1/q) mod p ; h = g^2,3,... mod p
* q | p-1 ; q -| p-1/q ; g^q = h^q = 1 mod p
* Or cf. 2.132.iv p70;
* a generator of Zp^* if a^(phi(p)/y) not 1 mod p for each prime divisor y of phi(p) (Handbook of Crypto Fact 2.132(iv))
* p = 2pp+1 => phi(p)=2pp y1=pp y2=2
* a^pp not 1 mod p and a^2 not 1 mod p
*
* Return value: a newly created #CrypticPrimeOrderGroup object; or NULL if an error
* occured
**/
CrypticPrimeOrderGroup*
//cryptic_prime_order_group_new(int lg_modulus, BN_GENCB *cb)
cryptic_prime_order_group_new(int lg_modulus)
{
int rc = CRYPTIC_ERROR_UNDEFINED;
int found=0,found2=0;
BIGNUM *two = NULL, *gcd = NULL, *tmp1 = NULL;
BN_CTX *ctx = NULL;
CrypticPrimeOrderGroup *group;
group = g_object_new(CRYPTIC_TYPE_GROUPSPRIMEORDER, NULL);
BN_GENCB *cb = NULL;
goto_cleanup_if_fail_with_rc_with_warning_openssl(gcd = BN_new());
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);
cryptic_release_bn(group->p);
cryptic_release_bn(group->pp);
cryptic_release_bn(group->generator);
cryptic_release_bn(group->order);
goto_cleanup_if_fail_with_rc_with_warning_openssl(group->p = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(group->pp = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(group->order = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(group->generator = BN_new());
goto_cleanup_if_fail_with_rc_with_warning_openssl(ctx = BN_CTX_new());
/* TODO: p = bq + 1 with b != 2 */
while(!found2){
found=0;
while(!found){
BN_generate_prime_ex(group->p,lg_modulus,1,NULL,NULL,cb);
/* Redundant check (already cleanup by safe prime generation) */
if(BN_is_prime_ex(group->p,BN_prime_checks,ctx, cb)){
found=1;
}
}
/* pp = (p-1)/2 */
/* div approx makes minus one useless */
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_div(group->pp,NULL,group->p,two,ctx) == 1);
//assert(BN_div(group->pp,NULL,group->p,two,ctx) == 1);
/* Redundant check (already cleanup by safe prime generation) */
if(BN_is_prime_ex(group->pp,BN_prime_checks,ctx, cb)){
found2=1;
}
}
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_sub(group->order,group->p,BN_value_one()) == 1);
/* Generator picking */
found=0;
while(!found){
cryptic_check_good_rc(cryptic_find_random_with_range_value(group->generator,group->p));
/* Check if a in Zp^* */
/* a in Zp^* if gcd(a,p) = 1 with p prime*/
/* Fermat theorem: if gcd(a,p) = 1 with p prime, a^phi(p)=a^(p-1) = 1 mod p*/
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_gcd(gcd, group->p, group->generator, ctx) == 1);
if (BN_ucmp(gcd, BN_value_one()) == 0 && BN_ucmp(group->generator, BN_value_one()) != 0) {found = 1;}
}
/* g^2 and g^p' mod p must be != 1*/
/* The group generated by p (safe prime) means that any member of the group is a generator */
rc = CRYPTIC_NO_ERROR;
cleanup:
cryptic_release_ctx(ctx);
cryptic_release_bn(tmp1);
cryptic_release_bn(gcd);
cryptic_release_bn(two);
if(rc == CRYPTIC_NO_ERROR) {return group;}
else{
cryptic_release_gobject(group);
return NULL;
}
}
/**
* cryptic_prime_order_group_more_bases:
* @nb: number of new bases to pick.
*
* Pick nb ganarators in the prime order group.
*
* Return value: #CRYPTIC_NO_ERROR if successful, an error code otherwise.
*/
int
cryptic_prime_order_group_more_bases(CrypticPrimeOrderGroup *group, int nb)
{
int rc = CRYPTIC_ERROR_UNDEFINED;
int i;
BIGNUM *tmp1 = NULL;
BN_CTX *ctx = NULL;
BN_MONT_CTX *mont = NULL;
goto_cleanup_if_fail_with_rc_with_warning_openssl(tmp1 = 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, group->p, ctx));
if(group->nb_bases == 0) {
cryptic_release(group->bases);
group->bases = g_malloc0(nb * sizeof (**group->bases));
if(group->bases == NULL){
rc = CRYPTIC_MEMORY_ALLOCATION_FAILURE;
goto cleanup;
}
for (i=0;i<nb;i++){
group->bases[i] = NULL;
goto_cleanup_if_fail_with_rc_with_warning_openssl(group->bases[i] = BN_new());
int found=0;
while(!found){
cryptic_check_good_rc(cryptic_find_random_with_range_value(tmp1,group->p));
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_exp_mont(group->bases[i],group->generator,tmp1,group->p,ctx,mont));
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_exp_mont(tmp1,group->bases[i],group->pp,group->p,ctx,mont));
if(BN_ucmp(tmp1,BN_value_one()) == 0){ /* g^q = 1 mod p */
found=1;
group->nb_bases++;
}
}
}
}else{
BIGNUM **tmp = NULL;
tmp = group->bases;
group->bases = g_realloc(group->bases,(group->nb_bases+nb) * sizeof (**group->bases));
if(group->bases == NULL){
group->bases = tmp;
tmp = NULL;
rc = CRYPTIC_MEMORY_ALLOCATION_FAILURE;
goto cleanup;
}
for (i=0;i<nb;i++){
group->bases[group->nb_bases] = NULL;
goto_cleanup_if_fail_with_rc_with_warning_openssl(group->bases[group->nb_bases] = BN_new());
int found=0;
while(!found){
cryptic_check_good_rc(cryptic_find_random_with_range_value(tmp1,group->p));
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_exp_mont(group->bases[group->nb_bases],group->generator,tmp1,group->p,ctx,mont));
goto_cleanup_if_fail_with_rc_with_warning_openssl(BN_mod_exp_mont(tmp1,group->bases[group->nb_bases],group->pp,group->p,ctx,mont));
if(BN_ucmp(tmp1,BN_value_one()) == 0){ /* g^q = 1 mod p */
found=1;
group->nb_bases++;
}
}
}
}
rc = CRYPTIC_NO_ERROR;
cleanup:
cryptic_release_ctx(ctx);
cryptic_release_mont(mont);
cryptic_release_bn(tmp1);
return rc;
}