XrdCryptosslRSA.cc

Go to the documentation of this file.
00001 // $Id: XrdCryptosslRSA.cc 30949 2009-11-02 16:37:58Z ganis $
00002 
00003 const char *XrdCryptosslRSACVSID = "$Id: XrdCryptosslRSA.cc 30949 2009-11-02 16:37:58Z ganis $";
00004 /******************************************************************************/
00005 /*                                                                            */
00006 /*                   X r d C r y p t o S s l R S A . c c                      */
00007 /*                                                                            */
00008 /* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University  */
00009 /*       All Rights Reserved. See XrdInfo.cc for complete License Terms       */
00010 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
00011 /*              DE-AC03-76-SFO0515 with the Department of Energy              */
00012 /******************************************************************************/
00013 
00014 /* ************************************************************************** */
00015 /*                                                                            */
00016 /* OpenSSL implementation of XrdCryptoRSA                                     */
00017 /*                                                                            */
00018 /* ************************************************************************** */
00019 
00020 #include <XrdSut/XrdSutRndm.hh>
00021 #include <XrdCrypto/XrdCryptosslTrace.hh>
00022 #include <XrdCrypto/XrdCryptosslRSA.hh>
00023 
00024 #include <string.h>
00025 
00026 #include <openssl/bio.h>
00027 #include <openssl/err.h>
00028 #include <openssl/pem.h>
00029 
00030 //_____________________________________________________________________________
00031 XrdCryptosslRSA::XrdCryptosslRSA(int bits, int exp)
00032 {
00033    // Constructor
00034    // Generate a RSA asymmetric key pair
00035    // Length will be 'bits' bits (min 512, default 1024), public
00036    // exponent `pubex` (default 65537).
00037    EPNAME("RSA::XrdCryptosslRSA");
00038 
00039    publen = -1;
00040    prilen = -1;
00041 
00042    // Create container, first
00043    if (!(fEVP = EVP_PKEY_new())) {
00044       DEBUG("cannot allocate new public key container");
00045       return;
00046    }
00047 
00048    // Minimum is XrdCryptoMinRSABits
00049    bits = (bits >= XrdCryptoMinRSABits) ? bits : XrdCryptoMinRSABits;
00050 
00051    // If pubex is not odd, use default
00052    if (!(exp & 1<<1))
00053       exp = XrdCryptoDefRSAExp;   // 65537 (0x10001)
00054 
00055    DEBUG("bits: "<<bits<<", exp:"<<exp);
00056 
00057    // Try Key Generation
00058    RSA *fRSA = RSA_generate_key(bits,exp,0,0);
00059 
00060    // Update status flag
00061    if (fRSA) {
00062       if (RSA_check_key(fRSA) != 0) {
00063          status = kComplete;
00064          DEBUG("basic length: "<<RSA_size(fRSA)<<" bytes");
00065          // Set the key
00066          EVP_PKEY_set1_RSA(fEVP, fRSA);
00067       } else {
00068          DEBUG("WARNING: generated key is invalid");
00069          // Generated an invalid key: cleanup
00070          RSA_free(fRSA);
00071       }
00072    }
00073 }
00074 
00075 //_____________________________________________________________________________
00076 XrdCryptosslRSA::XrdCryptosslRSA(const char *pub, int lpub)
00077 {
00078    // Constructor
00079    // Allocate a RSA key pair and fill the public part importing 
00080    // from string representation (pub) to internal representation.
00081    // If lpub>0 use the first lpub bytes; otherwise use strlen(pub)
00082    // bytes.
00083 
00084    fEVP = 0;
00085    publen = -1;
00086    prilen = -1;
00087 
00088    // Import key
00089    ImportPublic(pub,lpub);
00090 }
00091 
00092 //_____________________________________________________________________________
00093 XrdCryptosslRSA::XrdCryptosslRSA(EVP_PKEY *key, bool check)
00094 {
00095    // Constructor to import existing key
00096    EPNAME("RSA::XrdCryptosslRSA_key");
00097 
00098    fEVP = 0;
00099    publen = -1;
00100    prilen = -1;
00101 
00102    // Create container, first
00103    if (!key) {
00104       DEBUG("no input key");
00105       return;
00106    }
00107 
00108    if (check) {
00109       // Check consistency
00110       if (RSA_check_key(key->pkey.rsa) != 0) {
00111          fEVP = key;
00112          // Update status
00113          status = kComplete;
00114       } else {
00115          DEBUG("key contains inconsistent information");
00116       }
00117    } else {
00118       // Accept in any case (for incomplete keys)
00119       fEVP = key;
00120       // Update status
00121       status = kPublic;
00122    }
00123 }
00124 
00125 
00126 //____________________________________________________________________________
00127 XrdCryptosslRSA::XrdCryptosslRSA(const XrdCryptosslRSA &r)
00128 {
00129    // Copy Constructor
00130    EPNAME("RSA::XrdCryptosslRSA_copy");
00131 
00132    fEVP = 0;
00133    publen = -1;
00134    prilen = -1;
00135 
00136    if (!r.fEVP) {
00137       DEBUG("input key is empty");
00138       return;
00139    }
00140 
00141    // If the given key is set, copy it via a bio
00142    bool publiconly = (r.fEVP->pkey.rsa->d == 0);
00143    //
00144    // Bio for exporting the pub key
00145    BIO *bcpy = BIO_new(BIO_s_mem());
00146    if (bcpy) {
00147       // Write kref public key to BIO
00148       if (PEM_write_bio_PUBKEY(bcpy, r.fEVP)) {
00149          bool ok = (publiconly) ? 1 :
00150                    // Write kref private key to BIO
00151                    (PEM_write_bio_PrivateKey(bcpy,r.fEVP,0,0,0,0,0) != 0);
00152          if (ok) {
00153             // Read public key from BIO
00154             if ((fEVP = PEM_read_bio_PUBKEY(bcpy, 0, 0, 0))) {
00155                // Update status
00156                status = kPublic;
00157                ok = (publiconly) ? 1 :
00158                     // Read private key from BIO
00159                     (PEM_read_bio_PrivateKey(bcpy,&fEVP,0,0) != 0);
00160                if (ok) {
00161                   // Check consistency
00162                   if (!publiconly && RSA_check_key(fEVP->pkey.rsa) != 0) {
00163                      // Update status
00164                      status = kComplete;
00165                   }
00166                }
00167             }
00168          }
00169       }
00170       // Cleanup bio
00171       BIO_free(bcpy);
00172    }
00173 }
00174 
00175 //_____________________________________________________________________________
00176 XrdCryptosslRSA::~XrdCryptosslRSA()
00177 {
00178    // Destructor
00179    // Destroy the RSA asymmetric key pair
00180 
00181    if (fEVP)
00182       EVP_PKEY_free(fEVP);
00183    fEVP = 0;
00184 }
00185 
00186 //_____________________________________________________________________________
00187 int XrdCryptosslRSA::GetOutlen(int lin)
00188 {
00189    // Get minimal length of output buffer
00190 
00191    int lcmax = RSA_size(fEVP->pkey.rsa) - 42;
00192 
00193    return ((lin / lcmax) + 1) * RSA_size(fEVP->pkey.rsa);
00194 }
00195 
00196 //_____________________________________________________________________________
00197 int XrdCryptosslRSA::ImportPublic(const char *pub, int lpub)
00198 {
00199    // Import a public key
00200    // Allocate a RSA key pair and fill the public part importing 
00201    // from string representation (pub) to internal representation.
00202    // If lpub>0 use the first lpub bytes; otherwise use strlen(pub)
00203    // bytes.
00204    // Return 0 in case of success, -1 in case of failure
00205 
00206    if (fEVP)
00207       EVP_PKEY_free(fEVP);
00208    fEVP = 0;
00209    publen = -1;
00210    prilen = -1;
00211 
00212    // Temporary key
00213    EVP_PKEY *keytmp = 0;
00214 
00215    // Bio for exporting the pub key
00216    BIO *bpub = BIO_new(BIO_s_mem());
00217 
00218    // Check length
00219    lpub = (lpub <= 0) ? strlen(pub) : lpub;
00220 
00221    // Write key from pubexport to BIO
00222    BIO_write(bpub,(void *)pub,lpub);
00223 
00224    // Read pub key from BIO
00225    if ((keytmp = PEM_read_bio_PUBKEY(bpub, 0, 0, 0))) {
00226       fEVP = keytmp;
00227       // Update status
00228       status = kPublic;
00229       return 0;
00230    }
00231    return -1;
00232 }
00233 
00234 //_____________________________________________________________________________
00235 int XrdCryptosslRSA::ImportPrivate(const char *pri, int lpri)
00236 {
00237    // Import a private key
00238    // Fill the private part importing from string representation (pub) to
00239    // internal representation.
00240    // If lpub>0 use the first lpub bytes; otherwise use strlen(pub)
00241    // bytes.
00242    // Return 0 in case of success, -1 in case of failure
00243 
00244    if (!fEVP)
00245       return -1;
00246    prilen = -1;
00247 
00248    // Bio for exporting the pub key
00249    BIO *bpri = BIO_new(BIO_s_mem());
00250 
00251    // Check length
00252    lpri = (lpri <= 0) ? strlen(pri) : lpri;
00253 
00254    // Write key from private export to BIO
00255    BIO_write(bpri,(void *)pri,lpri);
00256 
00257    // Read private key from BIO
00258    if (PEM_read_bio_PrivateKey(bpri, &fEVP, 0, 0)) {
00259       // Update status
00260       status = kComplete;
00261       return 0;
00262    }
00263    return -1;
00264 }
00265 
00266 //_____________________________________________________________________________
00267 void XrdCryptosslRSA::Dump()
00268 {
00269    // Dump some info about the key
00270    EPNAME("RSA::Dump");
00271 
00272    DEBUG("---------------------------------------");
00273    DEBUG("address: "<<this);
00274    if (IsValid()) {
00275       char *btmp = new char[GetPublen()+1];
00276       if (btmp) {
00277          ExportPublic(btmp,GetPublen()+1);
00278          DEBUG("export pub key:"<<endl<<btmp);
00279          delete[] btmp;
00280       } else {
00281          DEBUG("cannot allocate memory for public key");
00282       }
00283    } else {
00284       DEBUG("key is invalid");
00285    }
00286    DEBUG("---------------------------------------");
00287 }
00288 
00289 //_____________________________________________________________________________
00290 int XrdCryptosslRSA::GetPublen()
00291 {
00292    // Minimu length of export format of public key 
00293 
00294    if (publen < 0) {
00295       // Bio for exporting the pub key
00296       BIO *bkey = BIO_new(BIO_s_mem());
00297       // Write public key to BIO
00298       PEM_write_bio_PUBKEY(bkey,fEVP);
00299       // data length
00300       char *cbio = 0;
00301       publen = (int) BIO_get_mem_data(bkey, &cbio);
00302       BIO_free(bkey);
00303    }
00304    return publen;
00305 }
00306 //_____________________________________________________________________________
00307 int XrdCryptosslRSA::ExportPublic(char *out, int)
00308 {
00309    // Export the public key into buffer out. The length of the buffer should be
00310    // at least GetPublen()+1 bytes. If out=0 the buffer is m-allocated internally
00311    // and should be freed by the caller.
00312    // Return 0 in case of success, -1 in case of failure
00313    EPNAME("RSA::ExportPublic");
00314 
00315    // Make sure we have a valid key
00316    if (!IsValid()) {
00317       DEBUG("key not valid");
00318       return -1;
00319    }
00320 
00321    // Bio for exporting the pub key
00322    BIO *bkey = BIO_new(BIO_s_mem());
00323 
00324    // Write public key to BIO
00325    PEM_write_bio_PUBKEY(bkey,fEVP);
00326 
00327    // data length
00328    char *cbio = 0;
00329    int lbio = (int) BIO_get_mem_data(bkey, &cbio);
00330    if (lbio <= 0 || !cbio) {
00331       DEBUG("problems attaching to BIO content");
00332       return -1;
00333    }
00334 
00335    // Check output buffer
00336    if (!out) {
00337       out = (char *) malloc(lbio+1);
00338       if (!out) {
00339          DEBUG("problems allocating output buffer");
00340          return -1;
00341       }
00342    }
00343    // Read key from BIO to buf
00344    memcpy(out, cbio, lbio);
00345    // Null terminate
00346    out[lbio] = 0;
00347    DEBUG("("<<lbio<<" bytes) "<< endl <<out);
00348    BIO_free(bkey);
00349 
00350    return 0;
00351 }
00352 
00353 //_____________________________________________________________________________
00354 int XrdCryptosslRSA::GetPrilen()
00355 {
00356    // Minimu length of export format of private key 
00357 
00358    if (prilen < 0) {
00359       // Bio for exporting the private key
00360       BIO *bkey = BIO_new(BIO_s_mem());
00361       // Write public key to BIO
00362       PEM_write_bio_PrivateKey(bkey,fEVP,0,0,0,0,0);
00363       // data length
00364       char *cbio = 0;
00365       prilen = (int) BIO_get_mem_data(bkey, &cbio);
00366       BIO_free(bkey);
00367    }
00368    return prilen;
00369 }
00370 
00371 //_____________________________________________________________________________
00372 int XrdCryptosslRSA::ExportPrivate(char *out, int)
00373 {
00374    // Export the private key into buffer out. The length of the buffer should be
00375    // at least GetPrilen()+1 bytes. If out=0 the buffer is m-allocated internally
00376    // and should be freed by the caller.
00377    // Return 0 in case of success, -1 in case of failure
00378    EPNAME("RSA::ExportPrivate");
00379 
00380    // Make sure we have a valid key
00381    if (!IsValid()) {
00382       DEBUG("key not valid");
00383       return -1;
00384    }
00385 
00386    // Bio for exporting the pub key
00387    BIO *bkey = BIO_new(BIO_s_mem());
00388 
00389    // Write public key to BIO
00390    PEM_write_bio_PrivateKey(bkey,fEVP,0,0,0,0,0);
00391 
00392    // data length
00393    char *cbio = 0;
00394    int lbio = (int) BIO_get_mem_data(bkey, &cbio);
00395    if (lbio <= 0 || !cbio) {
00396       DEBUG("problems attaching to BIO content");
00397       return -1;
00398    }
00399 
00400    // Check output buffer
00401    if (!out) {
00402       out = (char *) malloc(lbio+1);
00403       if (!out) {
00404          DEBUG("problems allocating output buffer");
00405          return -1;
00406       }
00407    }
00408    // Read key from BIO to buf
00409    memcpy(out, cbio, lbio);
00410    // Null terminate
00411    out[lbio] = 0;
00412    DEBUG("("<<lbio<<" bytes) "<< endl <<out);
00413    BIO_free(bkey);
00414 
00415    return 0;
00416 }
00417 
00418 //_____________________________________________________________________________
00419 int XrdCryptosslRSA::EncryptPrivate(const char *in, int lin, char *out, int loutmax)
00420 {
00421    // Encrypt lin bytes at 'in' using the internal private key.
00422    // The output buffer 'out' is allocated by the caller for max lout bytes.
00423    // The number of meaningful bytes in out is returned in case of success
00424    // (never larger that loutmax); -1 in case of error.
00425    EPNAME("RSA::EncryptPrivate");
00426 
00427    // Make sure we got something to encrypt
00428    if (!in || lin <= 0) {
00429       DEBUG("input buffer undefined");
00430       return -1;
00431    }
00432 
00433    // Make sure we got a buffer where to write
00434    if (!out || loutmax <= 0) {
00435       DEBUG("output buffer undefined");
00436       return -1;
00437    }
00438 
00439    //
00440    // Private encoding ...
00441    int lcmax = RSA_size(fEVP->pkey.rsa) - 11;  // Magic number (= 2*sha1_outlen + 2)
00442    int lout = 0;
00443    int len = lin;
00444    int kk = 0;
00445    int ke = 0;
00446 
00447    while (len > 0 && ke <= (loutmax - lout)) {
00448       int lc = (len > lcmax) ? lcmax : len ;
00449       if ((lout = RSA_private_encrypt(lc, (unsigned char *)&in[kk],
00450                                           (unsigned char *)&out[ke],
00451                                       fEVP->pkey.rsa, RSA_PKCS1_PADDING)) < 0) {
00452          char serr[120];
00453          ERR_error_string(ERR_get_error(), serr);
00454          DEBUG("error: " <<serr);
00455          return -1;
00456       }
00457       kk += lc;
00458       ke += lout;
00459       len -= lc;
00460    }
00461    if (len > 0 && ke > (loutmax - lout))
00462       DEBUG("buffer truncated");
00463    lout = ke;
00464 
00465    // Return   
00466    return lout;
00467 }
00468 
00469 //_____________________________________________________________________________
00470 int XrdCryptosslRSA::EncryptPublic(const char *in, int lin, char *out, int loutmax)
00471 {
00472    // Encrypt lin bytes at 'in' using the internal public key.
00473    // The output buffer 'out' is allocated by the caller for max lout bytes.
00474    // The number of meaningful bytes in out is returned in case of success
00475    // (never larger that loutmax); -1 in case of error.
00476    EPNAME("RSA::EncryptPublic");
00477    
00478    // Make sure we got something to encrypt
00479    if (!in || lin <= 0) {
00480       DEBUG("input buffer undefined");
00481       return -1;
00482    }
00483 
00484    // Make sure we got a buffer where to write
00485    if (!out || loutmax <= 0) {
00486       DEBUG("output buffer undefined");
00487       return -1;
00488    }
00489 
00490    //
00491    // Public encoding ...
00492    int lcmax = RSA_size(fEVP->pkey.rsa) - 42;  // Magic number (= 2*sha1_outlen + 2)
00493    int lout = 0;
00494    int len = lin;
00495    int kk = 0;
00496    int ke = 0;
00497 
00498    while (len > 0 && ke <= (loutmax - lout)) {
00499       int lc = (len > lcmax) ? lcmax : len ;
00500       if ((lout = RSA_public_encrypt(lc, (unsigned char *)&in[kk],
00501                                          (unsigned char *)&out[ke],
00502                                      fEVP->pkey.rsa, RSA_PKCS1_OAEP_PADDING)) < 0) {
00503          char serr[120];
00504          ERR_error_string(ERR_get_error(), serr);
00505          DEBUG("error: " <<serr);
00506          return -1;
00507       }
00508       kk += lc;
00509       ke += lout;
00510       len -= lc;
00511    }
00512    if (len > 0 && ke > (loutmax - lout))
00513       DEBUG("buffer truncated");
00514    lout = ke;
00515 
00516    // Return   
00517    return lout;
00518 }
00519 
00520 //_____________________________________________________________________________
00521 int XrdCryptosslRSA::DecryptPrivate(const char *in, int lin, char *out, int loutmax)
00522 {
00523    // Decrypt lin bytes at 'in' using the internal private key
00524    // The output buffer 'out' is allocated by the caller for max lout bytes.
00525    // The number of meaningful bytes in out is returned in case of success
00526    // (never larger that loutmax); -1 in case of error.
00527    EPNAME("RSA::DecryptPrivate");
00528 
00529    // Make sure we got something to decrypt
00530    if (!in || lin <= 0) {
00531       DEBUG("input buffer undefined");
00532       return -1;
00533    }
00534 
00535    // Make sure we got a buffer where to write
00536    if (!out || loutmax <= 0) {
00537       DEBUG("output buffer undefined");
00538       return -1;
00539    }
00540 
00541    int lout = 0;
00542    int len = lin;
00543    int lcmax = RSA_size(fEVP->pkey.rsa);
00544    int kk = 0;
00545    int ke = 0;
00546 
00547    //
00548    // Private decoding ...
00549    while (len > 0 && ke <= (loutmax - lout)) {
00550       if ((lout = RSA_private_decrypt(lcmax, (unsigned char *)&in[kk],
00551                                              (unsigned char *)&out[ke],
00552                                       fEVP->pkey.rsa, RSA_PKCS1_OAEP_PADDING)) < 0) {
00553          char serr[120];
00554          ERR_error_string(ERR_get_error(), serr);
00555          DEBUG("error: " <<serr);
00556          return -1;
00557       }
00558       kk += lcmax;
00559       len -= lcmax;
00560       ke += lout;
00561    }
00562    if (len > 0 && ke > (loutmax - lout))
00563       PRINT("buffer truncated");
00564    lout = ke;
00565    
00566    return lout;
00567 }
00568 
00569 //_____________________________________________________________________________
00570 int XrdCryptosslRSA::DecryptPublic(const char *in, int lin, char *out, int loutmax)
00571 {
00572    // Decrypt lin bytes at 'in' using the internal public key
00573    // The output buffer 'out' is allocated by the caller for max lout bytes.
00574    // The number of meaningful bytes in out is returned in case of success
00575    // (never larger that loutmax); -1 in case of error.
00576    EPNAME("RSA::DecryptPublic");
00577 
00578    // Make sure we got something to decrypt
00579    if (!in || lin <= 0) {
00580       DEBUG("input buffer undefined");
00581       return -1;
00582    }
00583 
00584    // Make sure we got a buffer where to write
00585    if (!out || loutmax <= 0) {
00586       DEBUG("output buffer undefined");
00587       return -1;
00588    }
00589 
00590    int lout = 0;
00591    int len = lin;
00592    int lcmax = RSA_size(fEVP->pkey.rsa);
00593    int kk = 0;
00594    int ke = 0;
00595 
00596    //
00597    // Private decoding ...
00598    while (len > 0 && ke <= (loutmax - lout)) {
00599       if ((lout = RSA_public_decrypt(lcmax, (unsigned char *)&in[kk],
00600                                             (unsigned char *)&out[ke],
00601                                      fEVP->pkey.rsa, RSA_PKCS1_PADDING)) < 0) {
00602          char serr[120];
00603          ERR_error_string(ERR_get_error(), serr);
00604          PRINT("error: " <<serr);
00605          return -1;
00606       }
00607       kk += lcmax;
00608       len -= lcmax;
00609       ke += lout;
00610    }
00611    if (len > 0 && ke > (loutmax - lout))
00612       PRINT("buffer truncated");
00613    lout = ke;
00614    
00615    return lout;
00616 }

Generated on Tue Jul 5 14:46:34 2011 for ROOT_528-00b_version by  doxygen 1.5.1