282 lines
9.1 KiB
C
Executable File
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;
|
|
}
|