Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

ElGamalPublicKey.cc

00001 /*
00002  * Copyright 2003 Michael A. Marsh, Cornell University. All rights reserved.
00003  * This software is released under the modified BSD license.
00004  * See the file LICENSE in the top-level directory for details.
00005  */
00006 //
00007 // $Id: ElGamalPublicKey.cc,v 1.4 2004/05/19 15:56:47 mmarsh Exp $
00008 //
00009 // $Log: ElGamalPublicKey.cc,v $
00010 // Revision 1.4  2004/05/19 15:56:47  mmarsh
00011 // *** empty log message ***
00012 //
00013 // Revision 1.3  2003/11/04 22:31:47  mmarsh
00014 // *** empty log message ***
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    // We don't throw exceptions here because we don't necessarily need
00067    // these members.  The methods that construct them on the fly will
00068    // throw exceptions when appropriate.
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    // We don't throw exceptions here because we don't necessarily need
00101    // these members.  The methods that construct them on the fly will
00102    // throw exceptions when appropriate.
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       // Now we need to create the Schnorr signature.
00241       //
00242 
00243       // First, choose a random exponent for the signature.
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() ) ); // s=0,1 are detectable
00260 
00261       ctx = BN_CTX_new();
00262       if ( 0 == ctx )
00263       {
00264          throw BignumContextException( __FILE__ , __LINE__ );
00265       }
00266 
00267       // Now compute the exponentiation.
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       // We need to hash the various pieces together.
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       // Given the hash, the random signature exponent, and the random
00308       // encryption exponent, calculate the mixed exponent.
00309       h = BN_new(); // re-use h
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       // Clean up temporary variables.
00331       if ( ownK ) BN_clear_free( k );
00332       BN_clear_free( s );
00333       BN_clear_free( h );
00334       BN_CTX_free( ctx );
00335 
00336       // Create the object to be returned.
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() ) ); // k=0,1 are detectable
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          // Multiplying the plaintext by its Jacobi symbol puts it in
00395          // the order-q subgroup of (Z_p)*
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        * g^m == y^r r^s mod p
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: // needed by ASN.1 macros
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    //basic_string<unsigned char> s;
00604    //is >> s;
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    //unsigned char* p = (unsigned char*)s.data();
00613    void* retVal = unmarshal(0,&p,length);
00614    delete [] pOrig;
00615    return retVal;
00616 }

Generated on Fri May 6 17:39:11 2005 for COrnell Data EXchange (CODEX) by  doxygen 1.4.1