00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <fstream>
00019 #include <openssl/pem.h>
00020 #include "RSA.h"
00021 #include "CODEX_Exceptions/BignumExceptions.h"
00022 #include "CODEX_Exceptions/FileExceptions.h"
00023
00024 #include "timing.h"
00025
00026 using namespace CODEX_Ciphers;
00027 using namespace CODEX_Exceptions;
00028 using CODEX_ASN1::BigNumber;
00029 using CODEX_ASN1::SecureBigNumber;
00030
00031 RSAPrivateKey::RSAPrivateKey() :
00032 CODEX_ASN1::Base( false )
00033 {
00034 }
00035
00036 RSAPrivateKey::RSAPrivateKey( BIGNUM * p,
00037 BIGNUM * q,
00038 BIGNUM * d,
00039 BIGNUM * n,
00040 BIGNUM * phi ) :
00041 CODEX_ASN1::Base( true ),
00042 m_p( p ),
00043 m_q( q ),
00044 m_d( d ),
00045 m_n( n ),
00046 m_phi( phi )
00047 {
00048 BN_CTX * ctx = 0;
00049 BIGNUM * temp1 = 0;
00050 BIGNUM * temp2 = 0;
00051 bool ownN = false;
00052 bool ownPhi = false;
00053 try
00054 {
00055 if ( 0 == n )
00056 {
00057 if ( 0 == ctx )
00058 {
00059 ctx = BN_CTX_new();
00060 if ( 0 == ctx )
00061 {
00062 throw BignumContextException( __FILE__ , __LINE__ );
00063 }
00064 }
00065 n = BN_new();
00066 if ( 0 == n )
00067 {
00068 throw BignumNullException( __FILE__ , __LINE__ );
00069 }
00070 ownN = true;
00071 if ( ! BN_mul( n, p, q, ctx ) )
00072 {
00073 throw BignumMulException( __FILE__ , __LINE__ );
00074 }
00075 m_n = CODEX_ASN1::SecureBigNumber( n );
00076 }
00077 if ( 0 == phi )
00078 {
00079 if ( 0 == ctx )
00080 {
00081 ctx = BN_CTX_new();
00082 if ( 0 == ctx )
00083 {
00084 throw BignumContextException( __FILE__ , __LINE__ );
00085 }
00086 }
00087 phi = BN_new();
00088 if ( 0 == phi )
00089 {
00090 throw BignumNullException( __FILE__ , __LINE__ );
00091 }
00092 ownPhi = true;
00093 temp1 = BN_new();
00094 if ( 0 == temp1 )
00095 {
00096 throw BignumNullException( __FILE__ , __LINE__ );
00097 }
00098 temp2 = BN_new();
00099 if ( 0 == temp2 )
00100 {
00101 throw BignumNullException( __FILE__ , __LINE__ );
00102 }
00103 if ( ! BN_sub( temp1, p, BN_value_one() ) )
00104 {
00105 throw BignumSubException( __FILE__ , __LINE__ );
00106 }
00107 if ( ! BN_sub( temp2, q, BN_value_one() ) )
00108 {
00109 throw BignumSubException( __FILE__ , __LINE__ );
00110 }
00111 if ( ! BN_mul( phi, temp1, temp2, ctx ) )
00112 {
00113 throw BignumMulException( __FILE__ , __LINE__ );
00114 }
00115 m_phi = CODEX_ASN1::SecureBigNumber( phi );
00116 }
00117 }
00118 catch ( ... )
00119 {
00120 if ( 0 != ctx ) BN_CTX_free( ctx );
00121 if ( 0 != temp1 ) BN_clear_free( temp1 );
00122 if ( 0 != temp2 ) BN_clear_free( temp2 );
00123 if ( ownN ) BN_clear_free( n );
00124 if ( ownPhi ) BN_clear_free( phi );
00125 throw;
00126 }
00127 if ( 0 != ctx ) BN_CTX_free( ctx );
00128 if ( 0 != temp1 ) BN_clear_free( temp1 );
00129 if ( 0 != temp2 ) BN_clear_free( temp2 );
00130 }
00131
00132 RSAPrivateKey::RSAPrivateKey( const CODEX_ASN1::BigNumber& p,
00133 const CODEX_ASN1::BigNumber& q,
00134 const CODEX_ASN1::BigNumber& d ) :
00135 CODEX_ASN1::Base( true ),
00136 m_p( p ),
00137 m_q( q ),
00138 m_d( d )
00139 {
00140 BN_CTX * ctx = 0;
00141 BIGNUM * temp1 = 0;
00142 BIGNUM * temp2 = 0;
00143 BIGNUM * nbn = 0;
00144 BIGNUM * phibn = 0;
00145 const BIGNUM * pbn = p.value();
00146 const BIGNUM * qbn = q.value();
00147
00148 try
00149 {
00150 ctx = BN_CTX_new();
00151 if ( 0 == ctx )
00152 {
00153 throw BignumContextException( __FILE__ , __LINE__ );
00154 }
00155 nbn = BN_new();
00156 if ( 0 == nbn )
00157 {
00158 throw BignumNullException( __FILE__ , __LINE__ );
00159 }
00160 if ( ! BN_mul( nbn, pbn, qbn, ctx ) )
00161 {
00162 throw BignumMulException( __FILE__ , __LINE__ );
00163 }
00164 m_n = CODEX_ASN1::SecureBigNumber( nbn );
00165
00166 phibn = BN_new();
00167 if ( 0 == phibn )
00168 {
00169 throw BignumNullException( __FILE__ , __LINE__ );
00170 }
00171 temp1 = BN_new();
00172 if ( 0 == temp1 )
00173 {
00174 throw BignumNullException( __FILE__ , __LINE__ );
00175 }
00176 temp2 = BN_new();
00177 if ( 0 == temp2 )
00178 {
00179 throw BignumNullException( __FILE__ , __LINE__ );
00180 }
00181 if ( ! BN_sub( temp1, pbn, BN_value_one() ) )
00182 {
00183 throw BignumSubException( __FILE__ , __LINE__ );
00184 }
00185 if ( ! BN_sub( temp2, qbn, BN_value_one() ) )
00186 {
00187 throw BignumSubException( __FILE__ , __LINE__ );
00188 }
00189 if ( ! BN_mul( phibn, temp1, temp2, ctx ) )
00190 {
00191 throw BignumMulException( __FILE__ , __LINE__ );
00192 }
00193 m_phi = CODEX_ASN1::SecureBigNumber( phibn );
00194 }
00195 catch ( ... )
00196 {
00197 if ( 0 != ctx ) BN_CTX_free( ctx );
00198 if ( 0 != temp1 ) BN_clear_free( temp1 );
00199 if ( 0 != temp2 ) BN_clear_free( temp2 );
00200 if ( 0 != nbn ) BN_free( nbn );
00201 if ( 0 != phibn ) BN_clear_free( phibn );
00202 throw;
00203 }
00204 if ( 0 != ctx ) BN_CTX_free( ctx );
00205 if ( 0 != temp1 ) BN_clear_free( temp1 );
00206 if ( 0 != temp2 ) BN_clear_free( temp2 );
00207 }
00208
00209 RSAPrivateKey::RSAPrivateKey( const RSAPrivateKey& aKey ) :
00210 CODEX_ASN1::Base( aKey.m_initialized ),
00211 m_p( aKey.m_p ),
00212 m_q( aKey.m_q ),
00213 m_d( aKey.m_d ),
00214 m_n( aKey.m_n ),
00215 m_phi( aKey.m_phi )
00216 {
00217 }
00218
00219 RSAPrivateKey::~RSAPrivateKey()
00220 {
00221 }
00222
00223 void
00224 RSAPrivateKey::operator=( const RSAPrivateKey& aKey )
00225 {
00226 m_initialized = aKey.m_initialized;
00227 m_p = aKey.m_p;
00228 m_q = aKey.m_q;
00229 m_d = aKey.m_d;
00230 m_n = aKey.m_n;
00231 m_phi = aKey.m_phi;
00232 }
00233
00234 BIGNUM *
00235 RSAPrivateKey::decrypt( const RSACipherText& cipherText ) const
00236 {
00237 return exponentiate( cipherText.value() );
00238 }
00239
00240 RSASignature*
00241 RSAPrivateKey::sign( const BIGNUM * message ) const
00242 {
00243 return new RSASignature( exponentiate( message ) );
00244 }
00245
00246 BIGNUM *
00247 RSAPrivateKey::exponentiate( const BIGNUM * aBN ) const
00248 {
00249 if ( 0 == aBN )
00250 {
00251 throw BignumNullException( __FILE__ , __LINE__ );
00252 }
00253
00254 #ifdef TIMING
00255 SignTimer.start();
00256 #endif
00257
00258 BN_CTX * ctx = 0;
00259 BIGNUM * retVal = 0;
00260
00261 try
00262 {
00263 ctx = BN_CTX_new();
00264 if ( 0 == ctx )
00265 {
00266 throw BignumContextException( __FILE__ , __LINE__ );
00267 }
00268
00269 retVal = BN_new();
00270 if ( 0 == retVal )
00271 {
00272 throw BignumNullException( __FILE__ , __LINE__ );
00273 }
00274 if ( ! BN_mod_exp( retVal, aBN, d().value(), n().value(), ctx ) )
00275 {
00276 throw BignumModExpException( __FILE__ , __LINE__ );
00277 }
00278 }
00279 catch ( ... )
00280 {
00281 if ( 0 != ctx ) BN_CTX_free( ctx );
00282 if ( 0 != retVal ) BN_free( retVal );
00283 throw;
00284 }
00285
00286 if ( 0 != ctx ) BN_CTX_free( ctx );
00287
00288 #ifdef TIMING
00289 SignTimer.stop();
00290 #endif
00291
00292 return retVal;
00293 }
00294
00295 int
00296 RSAPrivateKey::marshal( unsigned char ** pp ) const
00297 {
00298 int r=0;
00299 int ret=0;
00300 unsigned char * p;
00301
00302 ret += m_p.marshal(0);
00303 ret += m_q.marshal(0);
00304 ret += m_d.marshal(0);
00305 ret += m_n.marshal(0);
00306 ret += m_phi.marshal(0);
00307 M_ASN1_I2D_seq_total();
00308 m_p.marshal(&p);
00309 m_q.marshal(&p);
00310 m_d.marshal(&p);
00311 m_n.marshal(&p);
00312 m_phi.marshal(&p);
00313 M_ASN1_I2D_finish();
00314 }
00315
00316 void*
00317 RSAPrivateKey::unmarshal( void* bogus, unsigned char ** pp, long length )
00318 {
00319 if ( m_initialized )
00320 {
00321 return 0;
00322 }
00323 if ( (0 == pp) || (0 == *pp) )
00324 {
00325 return 0;
00326 }
00327
00328 ASN1_CTX c;
00329 c.pp = pp;
00330 c.q = *pp;
00331 c.error = ERR_R_NESTED_ASN1_ERROR;
00332 int i;
00333
00334 M_ASN1_D2I_Init();
00335 M_ASN1_D2I_start_sequence();
00336 M_ASN1_D2I_get(i, m_p.unmarshal);
00337 M_ASN1_D2I_get(i, m_q.unmarshal);
00338 M_ASN1_D2I_get(i, m_d.unmarshal);
00339 M_ASN1_D2I_get(i, m_n.unmarshal);
00340 M_ASN1_D2I_get(i, m_phi.unmarshal);
00341 if ( !asn1_Finish(&c) )
00342 {
00343 return 0;
00344 }
00345 *pp=c.p;
00346 m_initialized = true;
00347 return this;
00348 err:
00349 return 0;
00350 }
00351
00352 void
00353 RSAPrivateKey::toFile(const char* fname) const
00354 {
00355 int length = marshal(0);
00356 if ( 0 == length ) return;
00357 unsigned char* buff = new unsigned char[length];
00358 unsigned char* p = buff;
00359 marshal(&p);
00360 ofstream os(fname);
00361 if ( ! os.is_open() )
00362 {
00363 delete [] buff;
00364 throw FileCannotCreateException( __FILE__ , __LINE__ , fname );
00365 }
00366 for ( int i = 0 ; i < length ; ++i )
00367 {
00368 os << buff[i];
00369 }
00370 os.close();
00371 delete [] buff;
00372 }
00373
00375 void*
00376 RSAPrivateKey::fromFile(const char* fname)
00377 {
00378 ifstream is(fname);
00379 if ( ! is.is_open() )
00380 {
00381 throw FileCannotOpenException( __FILE__ , __LINE__ , fname );
00382 }
00383 string s;
00384 char ch;
00385 while ( is.get(ch) )
00386 {
00387 s.push_back(ch);
00388 }
00389
00390
00391 unsigned int length = s.length();
00392 unsigned char* p = new unsigned char[ length ];
00393 unsigned char* pOrig = p;
00394
00395 for ( unsigned int i = 0 ; i < length ; ++i )
00396 {
00397 p[i] = s.data()[i];
00398 }
00399 void* retVal = unmarshal(0,&p,length);
00400 delete [] pOrig;
00401 return retVal;
00402 }
00403
00404 void
00405 RSAPrivateKey::fromPEMFile(const char* fname, const char* phrase)
00406 {
00407 FILE* fp = 0;
00408 RSA * key = 0;
00409 BIGNUM * phibn = 0;
00410 BIGNUM * temp1 = 0;
00411 BIGNUM * temp2 = 0;
00412 BN_CTX * ctx = 0;
00413
00414 try
00415 {
00416 fp = fopen( fname, "r" );
00417 if ( 0 == fp )
00418 {
00419 throw FileCannotOpenException( __FILE__ , __LINE__ , fname );
00420 }
00421 if ( ! PEM_read_RSAPrivateKey( fp, &key, 0, (void*)phrase ) )
00422 {
00423 throw FileCannotOpenException( __FILE__ , __LINE__ , fname );
00424 }
00425 fclose( fp );
00426 fp = 0;
00427 m_p = CODEX_ASN1::SecureBigNumber( BN_dup( key->p ) );
00428 m_q = CODEX_ASN1::SecureBigNumber( BN_dup( key->q ) );
00429 m_d = CODEX_ASN1::SecureBigNumber( BN_dup( key->d ) );
00430 m_n = CODEX_ASN1::SecureBigNumber( BN_dup( key->n ) );
00431
00432 ctx = BN_CTX_new();
00433 if ( 0 == ctx )
00434 {
00435 throw BignumContextException( __FILE__ , __LINE__ );
00436 }
00437 phibn = BN_new();
00438 if ( 0 == phibn )
00439 {
00440 throw BignumNullException( __FILE__ , __LINE__ );
00441 }
00442 temp1 = BN_new();
00443 if ( 0 == temp1 )
00444 {
00445 throw BignumNullException( __FILE__ , __LINE__ );
00446 }
00447 temp2 = BN_new();
00448 if ( 0 == temp2 )
00449 {
00450 throw BignumNullException( __FILE__ , __LINE__ );
00451 }
00452 if ( ! BN_sub( temp1, key->p, BN_value_one() ) )
00453 {
00454 throw BignumSubException( __FILE__ , __LINE__ );
00455 }
00456 if ( ! BN_sub( temp2, key->q, BN_value_one() ) )
00457 {
00458 throw BignumSubException( __FILE__ , __LINE__ );
00459 }
00460 if ( ! BN_mul( phibn, temp1, temp2, ctx ) )
00461 {
00462 throw BignumMulException( __FILE__ , __LINE__ );
00463 }
00464 m_phi = CODEX_ASN1::SecureBigNumber( phibn );
00465
00466 m_initialized = true;
00467
00468 RSA_free( key ); key = 0;
00469 BN_CTX_free( ctx ); ctx = 0;
00470 BN_clear_free(temp1); temp1 = 0;
00471 BN_clear_free(temp2); temp2 = 0;
00472 }
00473 catch ( ... )
00474 {
00475 if ( 0 != fp ) fclose(fp);
00476 if ( 0 != key ) RSA_free( key );
00477 if ( 0 != ctx ) BN_CTX_free( ctx );
00478 if ( 0 != phibn ) BN_clear_free( phibn );
00479 if ( 0 != temp1 ) BN_clear_free( temp1 );
00480 if ( 0 != temp2 ) BN_clear_free( temp2 );
00481 throw;
00482 }
00483 }