00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <fstream>
00019 #include "ElGamal.h"
00020 #include "jacobi.h"
00021 #include "CODEX_Exceptions/BignumExceptions.h"
00022 #include "CODEX_Exceptions/FileExceptions.h"
00023
00024 using namespace CODEX_Ciphers;
00025 using namespace CODEX_Exceptions;
00026
00027 ElGamalPublicKey::ElGamalPublicKey() :
00028 CODEX_ASN1::Base( false ),
00029 m_p1( 0 ),
00030 m_q( 0 )
00031 {
00032 }
00033
00034 ElGamalPublicKey::ElGamalPublicKey( BIGNUM * p,
00035 BIGNUM * g,
00036 BIGNUM * y ) :
00037 CODEX_ASN1::Base( true ),
00038 m_p( p ),
00039 m_g( g ),
00040 m_y( y ),
00041 m_p1( 0 ),
00042 m_q( 0 )
00043 {
00044 }
00045
00046 ElGamalPublicKey::ElGamalPublicKey( const CODEX_ASN1::BigNumber& p,
00047 const CODEX_ASN1::BigNumber& g,
00048 const CODEX_ASN1::BigNumber& y ) :
00049 CODEX_ASN1::Base( true ),
00050 m_p( p ),
00051 m_g( g ),
00052 m_y( y ),
00053 m_p1( 0 ),
00054 m_q( 0 )
00055 {
00056 }
00057
00058 ElGamalPublicKey::ElGamalPublicKey( const ElGamalPublicKey& aKey ) :
00059 CODEX_ASN1::Base( aKey.m_initialized ),
00060 m_p( aKey.m_p ),
00061 m_g( aKey.m_g ),
00062 m_y( aKey.m_y ),
00063 m_p1( 0 ),
00064 m_q( 0 )
00065 {
00066
00067
00068
00069 if ( 0 != aKey.m_p1 )
00070 {
00071 m_p1 = BN_dup( aKey.m_p1 );
00072 }
00073 if ( 0 != aKey.m_q )
00074 {
00075 m_q = BN_dup( aKey.m_q );
00076 }
00077 }
00078
00079 ElGamalPublicKey::~ElGamalPublicKey()
00080 {
00081 if ( 0 != m_p1 )
00082 {
00083 BN_free( m_p1 );
00084 }
00085 if ( 0 != m_q )
00086 {
00087 BN_free( m_q );
00088 }
00089 }
00090
00091 void
00092 ElGamalPublicKey::operator=( const ElGamalPublicKey& aKey )
00093 {
00094 m_initialized = aKey.m_initialized;
00095 m_p = aKey.m_p;
00096 m_g = aKey.m_g;
00097 m_y = aKey.m_y;
00098 m_p1 = 0;
00099 m_q = 0;
00100
00101
00102
00103 if ( 0 != aKey.m_p1 )
00104 {
00105 m_p1 = BN_dup( aKey.m_p1 );
00106 }
00107 if ( 0 != aKey.m_q )
00108 {
00109 m_q = BN_dup( aKey.m_q );
00110 }
00111 }
00112
00113 const BIGNUM *
00114 ElGamalPublicKey::p1() const
00115 {
00116 if ( 0 == m_p1 )
00117 {
00118 m_p1 = BN_new();
00119 if ( 0 == m_p1 )
00120 {
00121 throw BignumNullException( __FILE__ , __LINE__ );
00122 }
00123 if ( ! BN_sub( m_p1 , m_p.value() , BN_value_one() ) )
00124 {
00125 BN_free(m_p1);
00126 m_p1 = 0;
00127 throw BignumSubException( __FILE__ , __LINE__ );
00128 }
00129 }
00130 return m_p1;
00131 }
00132
00133 const BIGNUM *
00134 ElGamalPublicKey::q() const
00135 {
00136 if ( 0 == m_q )
00137 {
00138 m_q = BN_new();
00139 if ( 0 == m_q )
00140 {
00141 throw BignumNullException( __FILE__ , __LINE__ );
00142 }
00143 if ( ! BN_rshift1( m_q , (BIGNUM*)p1() ) )
00144 {
00145 BN_free(m_q);
00146 m_q = 0;
00147 throw BignumRshiftException( __FILE__ , __LINE__ );
00148 }
00149 }
00150 return m_q;
00151 }
00152
00154 ElGamalCipherText*
00155 ElGamalPublicKey::encrypt( const BIGNUM * message, BIGNUM * k ) const
00156 {
00157 BIGNUM * c1 = 0;
00158 BIGNUM * c2 = 0;
00159 bool ownK = false;
00160 try
00161 {
00162 c1 = BN_new();
00163 if ( 0 == c1 )
00164 {
00165 throw BignumNullException( __FILE__ , __LINE__ );
00166 }
00167
00168 c2 = BN_new();
00169 if ( 0 == c2 )
00170 {
00171 throw BignumNullException( __FILE__ , __LINE__ );
00172 }
00173
00174 if ( 0 == k )
00175 {
00176 ownK = true;
00177 k = BN_new();
00178 if ( 0 == k )
00179 {
00180 throw BignumNullException( __FILE__ , __LINE__ );
00181 }
00182 }
00183
00184 encryptVals( message, k, c1, c2 );
00185 if ( ownK ) BN_clear_free( k );
00186 return new ElGamalCipherText( c1, c2 );
00187 }
00188 catch ( ... )
00189 {
00190 if ( 0 != c1 ) BN_free( c1 );
00191 if ( 0 != c2 ) BN_free( c2 );
00192 if ( ownK && k ) BN_clear_free( k );
00193 throw;
00194 }
00195 }
00196
00197 ElGamalSchnorrCipherText*
00198 ElGamalPublicKey::encryptS( const BIGNUM * message,
00199 const CODEX_ASN1::Base& id,
00200 const HashFunction& hashFunc,
00201 BIGNUM * k ) const
00202 {
00203 BIGNUM * c1 = 0;
00204 BIGNUM * c2 = 0;
00205 BIGNUM * h = 0;
00206 BIGNUM * z = 0;
00207 BIGNUM * s = 0;
00208 BIGNUM * gs = 0;
00209 BN_CTX * ctx = 0;
00210 unsigned char* buff = 0;
00211 CODEX_ASN1::ustring* str = 0;
00212 bool ownK = false;
00213 try
00214 {
00215 c1 = BN_new();
00216 if ( 0 == c1 )
00217 {
00218 throw BignumNullException( __FILE__ , __LINE__ );
00219 }
00220
00221 c2 = BN_new();
00222 if ( 0 == c2 )
00223 {
00224 throw BignumNullException( __FILE__ , __LINE__ );
00225 }
00226
00227 if ( 0 == k )
00228 {
00229 ownK = true;
00230 k = BN_new();
00231 if ( 0 == k )
00232 {
00233 throw BignumNullException( __FILE__ , __LINE__ );
00234 }
00235 }
00236
00237 encryptVals( message, k, c1, c2 );
00238
00240
00241
00242
00243
00244 CODEX_ASN1::BigNumber c1X( c1 ); c1 = 0;
00245 CODEX_ASN1::BigNumber c2X( c2 ); c2 = 0;
00246
00247 s = BN_new();
00248 if ( 0 == s )
00249 {
00250 throw BignumNullException( __FILE__ , __LINE__ );
00251 }
00252 do
00253 {
00254 if ( ! BN_rand_range( s, (BIGNUM*)q() ) )
00255 {
00256 throw BignumRandRangeException( __FILE__ , __LINE__ );
00257 }
00258 }
00259 while ( 0 >= BN_cmp( s, BN_value_one() ) );
00260
00261 ctx = BN_CTX_new();
00262 if ( 0 == ctx )
00263 {
00264 throw BignumContextException( __FILE__ , __LINE__ );
00265 }
00266
00267
00268 gs = BN_new();
00269 if ( 0 == gs )
00270 {
00271 throw BignumNullException( __FILE__ , __LINE__ );
00272 }
00273 if ( ! BN_mod_exp( gs, m_g.value(), s, m_p.value(), ctx ) )
00274 {
00275 throw BignumModExpException( __FILE__ , __LINE__ );
00276 }
00277 CODEX_ASN1::BigNumber gsX( gs ); gs = 0;
00278
00279
00280 int length = gsX.marshal(0);
00281 length += c1X.marshal(0);
00282 length += c2X.marshal(0);
00283 length += id.marshal(0);
00284 buff = new unsigned char[length];
00285 unsigned char* pBuff = buff;
00286 gsX.marshal(&pBuff);
00287 c1X.marshal(&pBuff);
00288 c2X.marshal(&pBuff);
00289 id.marshal(&pBuff);
00290 str = hashFunc( CODEX_ASN1::ustring(buff,length) );
00291 delete [] buff;
00292 buff = 0;
00293
00294 h = BN_new();
00295 if ( 0 == h )
00296 {
00297 throw BignumNullException( __FILE__ , __LINE__ );
00298 }
00299 if ( 0 == BN_bin2bn( str->data(), str->length(), h ) )
00300 {
00301 throw BignumBin2BNException( __FILE__ , __LINE__ );
00302 }
00303 delete str;
00304 str = 0;
00305 CODEX_ASN1::BigNumber hX( h ); h = 0;
00306
00307
00308
00309 h = BN_new();
00310 if ( 0 == h )
00311 {
00312 throw BignumNullException( __FILE__ , __LINE__ );
00313 }
00314 if ( ! BN_mul( h, hX.value(), k, ctx ) )
00315 {
00316 throw BignumMulException( __FILE__ , __LINE__ );
00317 }
00318
00319 z = BN_new();
00320 if ( 0 == z )
00321 {
00322 throw BignumNullException( __FILE__ , __LINE__ );
00323 }
00324 if ( ! BN_add( z, s, h ) )
00325 {
00326 throw BignumAddException( __FILE__ , __LINE__ );
00327 }
00328 CODEX_ASN1::BigNumber zX( z ); z = 0;
00329
00330
00331 if ( ownK ) BN_clear_free( k );
00332 BN_clear_free( s );
00333 BN_clear_free( h );
00334 BN_CTX_free( ctx );
00335
00336
00337 return new ElGamalSchnorrCipherText( c1X, c2X, hX, zX );
00338 }
00339 catch ( ... )
00340 {
00341 if ( 0 != c1 ) BN_free( c1 );
00342 if ( 0 != c2 ) BN_free( c2 );
00343 if ( ownK && k ) BN_clear_free( k );
00344 if ( 0 != h ) BN_clear_free( h );
00345 if ( 0 != z ) BN_free( z );
00346 if ( 0 != s ) BN_clear_free( s );
00347 if ( 0 != gs ) BN_free( gs );
00348 if ( 0 != ctx ) BN_CTX_free( ctx );
00349 throw;
00350 }
00351 }
00352
00353 void
00354 ElGamalPublicKey::encryptVals( const BIGNUM * message ,
00355 BIGNUM * k ,
00356 BIGNUM * c1 ,
00357 BIGNUM * c2 ) const
00358 {
00359 if ( 0 == message )
00360 {
00361 throw BignumNullException( __FILE__ , __LINE__ );
00362 }
00363
00364 do
00365 {
00366 if ( ! BN_rand_range( k, (BIGNUM*)q() ) )
00367 {
00368 throw BignumRandRangeException( __FILE__ , __LINE__ );
00369 }
00370 }
00371 while ( 0 >= BN_cmp( k, BN_value_one() ) );
00372
00373 BN_CTX * ctx = 0;
00374 BIGNUM * temp = 0;
00375 try
00376 {
00377 ctx = BN_CTX_new();
00378 if ( 0 == ctx )
00379 {
00380 throw BignumContextException( __FILE__ , __LINE__ );
00381 }
00382
00383 if ( ! BN_mod_exp(c1,m_g.value(),k,m_p.value(),ctx) )
00384 {
00385 throw BignumModExpException( __FILE__ , __LINE__ );
00386 }
00387 try
00388 {
00389 if ( ! BN_mod_exp(c2,m_y.value(),k,m_p.value(),ctx) )
00390 {
00391 throw BignumModExpException( __FILE__ , __LINE__ );
00392 }
00393
00394
00395
00396 temp = jacobi( message, m_p.value() );
00397 if ( 0 == temp )
00398 {
00399 throw BignumNullException( __FILE__ , __LINE__ );
00400 }
00401 if ( ! BN_mod_mul(temp,temp,message,m_p.value(),ctx) )
00402 {
00403 throw BignumModMulException( __FILE__ , __LINE__ );
00404 }
00405 if ( ! BN_mod_mul(c2,temp,c2,m_p.value(),ctx) )
00406 {
00407 throw BignumModMulException( __FILE__ , __LINE__ );
00408 }
00409 BN_clear_free(temp);
00410 temp = 0;
00411 }
00412 catch ( ... )
00413 {
00414 BN_clear( c2 );
00415 throw;
00416 }
00417 BN_CTX_free(ctx);
00418 }
00419 catch ( ... )
00420 {
00421 if ( 0 != ctx ) BN_CTX_free( ctx );
00422 if ( 0 != temp ) BN_clear_free( temp );
00423 throw;
00424 }
00425 }
00426
00427 bool
00428 ElGamalPublicKey::verifySignature( const ElGamalSignature& signature,
00429 const BIGNUM * message ) const
00430 {
00431 if ( 0 == message )
00432 {
00433 throw BignumNullException( __FILE__ , __LINE__ );
00434 }
00435
00436 BN_CTX * ctx = 0;
00437 BIGNUM * gm = 0;
00438 BIGNUM * temp1 = 0;
00439 BIGNUM * temp2 = 0;
00440
00441 try
00442 {
00443
00444
00445
00446 ctx = BN_CTX_new();
00447 if ( 0 == ctx )
00448 {
00449 throw BignumContextException( __FILE__ , __LINE__ );
00450 }
00451
00452 gm = BN_new();
00453 if ( 0 == gm )
00454 {
00455 throw BignumNullException( __FILE__ , __LINE__ );
00456 }
00457 if ( ! BN_mod_exp( gm, m_g.value(), message, m_p.value(), ctx ) )
00458 {
00459 throw BignumModExpException( __FILE__ , __LINE__ );
00460 }
00461
00462 temp1 = BN_new();
00463 if ( 0 == temp1 )
00464 {
00465 throw BignumNullException( __FILE__ , __LINE__ );
00466 }
00467 if ( ! BN_mod_exp( temp1,
00468 m_y.value(),
00469 signature.r().value(),
00470 m_p.value(),
00471 ctx ) )
00472 {
00473 throw BignumModExpException( __FILE__ , __LINE__ );
00474 }
00475
00476 temp2 = BN_new();
00477 if ( 0 == temp2 )
00478 {
00479 throw BignumNullException( __FILE__ , __LINE__ );
00480 }
00481 if ( ! BN_mod_exp( temp2,
00482 signature.r().value(),
00483 signature.s().value(),
00484 m_p.value(),
00485 ctx ) )
00486 {
00487 throw BignumModExpException( __FILE__ , __LINE__ );
00488 }
00489
00490 if ( ! BN_mod_mul(temp1,temp1,temp2,m_p.value(),ctx) )
00491 {
00492 throw BignumModMulException( __FILE__ , __LINE__ );
00493 }
00494
00495 bool retVal = ( 0 == BN_cmp(gm,temp1) );
00496
00497 BN_CTX_free(ctx);
00498 BN_free(gm);
00499 BN_free(temp1);
00500 BN_free(temp2);
00501
00502 return retVal;
00503 }
00504 catch ( ... )
00505 {
00506 if ( 0 != ctx ) BN_CTX_free( ctx );
00507 if ( 0 != gm ) BN_free(gm);
00508 if ( 0 != temp1 ) BN_free( temp1 );
00509 if ( 0 != temp2 ) BN_free( temp2 );
00510 throw;
00511 }
00512 }
00513
00514 int
00515 ElGamalPublicKey::marshal( unsigned char ** pp ) const
00516 {
00517 int r=0;
00518 int ret=0;
00519 unsigned char * p;
00520
00521 ret += m_p.marshal(0);
00522 ret += m_g.marshal(0);
00523 ret += m_y.marshal(0);
00524 M_ASN1_I2D_seq_total();
00525 m_p.marshal(&p);
00526 m_g.marshal(&p);
00527 m_y.marshal(&p);
00528 M_ASN1_I2D_finish();
00529 }
00530
00531 void*
00532 ElGamalPublicKey::unmarshal( void* bogus,
00533 unsigned char ** pp,
00534 long length )
00535 {
00536 if ( m_initialized )
00537 {
00538 return 0;
00539 }
00540 if ( (0 == pp) || (0 == *pp) )
00541 {
00542 return 0;
00543 }
00544
00545 ASN1_CTX c;
00546 c.pp = pp;
00547 c.q = *pp;
00548 c.error = ERR_R_NESTED_ASN1_ERROR;
00549 int i;
00550
00551 M_ASN1_D2I_Init();
00552 M_ASN1_D2I_start_sequence();
00553 M_ASN1_D2I_get(i, m_p.unmarshal);
00554 M_ASN1_D2I_get(i, m_g.unmarshal);
00555 M_ASN1_D2I_get(i, m_y.unmarshal);
00556 if ( !asn1_Finish(&c) )
00557 {
00558 return 0;
00559 }
00560 *pp=c.p;
00561 m_initialized = true;
00562 return this;
00563 err:
00564 return 0;
00565 }
00566
00567 void
00568 ElGamalPublicKey::toFile(const char* fname) const
00569 {
00570 int length = marshal(0);
00571 if ( 0 == length ) return;
00572 unsigned char* buff = new unsigned char[length];
00573 unsigned char* p = buff;
00574 marshal(&p);
00575 ofstream os(fname);
00576 if ( ! os.is_open() )
00577 {
00578 delete [] buff;
00579 throw FileCannotCreateException( __FILE__ , __LINE__ , fname );
00580 }
00581 for ( int i = 0 ; i < length ; ++i )
00582 {
00583 os << buff[i];
00584 }
00585 os.close();
00586 delete [] buff;
00587 }
00588
00589 void*
00590 ElGamalPublicKey::fromFile(const char* fname)
00591 {
00592 ifstream is(fname);
00593 if ( ! is.is_open() )
00594 {
00595 throw FileCannotOpenException( __FILE__ , __LINE__ , fname );
00596 }
00597 string s;
00598 char ch;
00599 while ( is.get(ch) )
00600 {
00601 s.push_back(ch);
00602 }
00603
00604
00605 unsigned int length = s.length();
00606 unsigned char* p = new unsigned char[ length ];
00607 unsigned char* pOrig = p;
00608 for ( unsigned int i = 0 ; i < length ; ++i )
00609 {
00610 p[i] = s.data()[i];
00611 }
00612
00613 void* retVal = unmarshal(0,&p,length);
00614 delete [] pOrig;
00615 return retVal;
00616 }