/******************************************************************************/ /* */ /* X r d C r y p t o S s l C i p h e r . c c */ /* */ /* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */ /* Produced by Gerri Ganis for CERN */ /* */ /* This file is part of the XRootD software suite. */ /* */ /* XRootD is free software: you can redistribute it and/or modify it under */ /* the terms of the GNU Lesser General Public License as published by the */ /* Free Software Foundation, either version 3 of the License, or (at your */ /* option) any later version. */ /* */ /* XRootD 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 Lesser General Public */ /* License for more details. */ /* */ /* You should have received a copy of the GNU Lesser General Public License */ /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */ /* COPYING (GPL license). If not, see . */ /* */ /* The copyright holder's institutional names and contributor's names may not */ /* be used to endorse or promote products derived from this software without */ /* specific prior written permission of the institution or contributor. */ /******************************************************************************/ /* ************************************************************************** */ /* */ /* OpenSSL implementation of XrdCryptoCipher */ /* */ /* ************************************************************************** */ #include #include "XrdSut/XrdSutRndm.hh" #include "XrdCrypto/XrdCryptosslTrace.hh" #include "XrdCrypto/XrdCryptosslCipher.hh" //#include #include #include #include // ---------------------------------------------------------------------------// // // Cipher interface // // ---------------------------------------------------------------------------// #if OPENSSL_VERSION_NUMBER < 0x10100000L static void DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) { if (p != NULL) *p = dh->p; if (q != NULL) *q = dh->q; if (g != NULL) *g = dh->g; } static int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) { /* If the fields p and g in d are NULL, the corresponding input * parameters MUST be non-NULL. q may remain NULL. */ if ((dh->p == NULL && p == NULL) || (dh->g == NULL && g == NULL)) return 0; if (p != NULL) { BN_free(dh->p); dh->p = p; } if (q != NULL) { BN_free(dh->q); dh->q = q; } if (g != NULL) { BN_free(dh->g); dh->g = g; } if (q != NULL) { dh->length = BN_num_bits(q); } return 1; } static void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key) { if (pub_key != NULL) *pub_key = dh->pub_key; if (priv_key != NULL) *priv_key = dh->priv_key; } static int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) { /* If the field pub_key in dh is NULL, the corresponding input * parameters MUST be non-NULL. The priv_key field may * be left NULL. */ if (dh->pub_key == NULL && pub_key == NULL) return 0; if (pub_key != NULL) { BN_free(dh->pub_key); dh->pub_key = pub_key; } if (priv_key != NULL) { BN_free(dh->priv_key); dh->priv_key = priv_key; } return 1; } static int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) { /* If the field pub_key in d is NULL, the corresponding input * parameters MUST be non-NULL. The priv_key field may * be left NULL. */ if (d->pub_key == NULL && pub_key == NULL) return 0; if (pub_key != NULL) { BN_free(d->pub_key); d->pub_key = pub_key; } if (priv_key != NULL) { BN_free(d->priv_key); d->priv_key = priv_key; } return 1; } #endif #if !defined(HAVE_DH_PADDED) #if defined(HAVE_DH_PADDED_FUNC) int DH_compute_key_padded(unsigned char *, const BIGNUM *, DH *); #else static int DH_compute_key_padded(unsigned char *key, const BIGNUM *pub_key, DH *dh) { int rv, pad; rv = dh->meth->compute_key(key, pub_key, dh); if (rv <= 0) return rv; pad = BN_num_bytes(dh->p) - rv; if (pad > 0) { memmove(key + pad, key, rv); memset(key, 0, pad); } return rv + pad; } #endif #endif //_____________________________________________________________________________ bool XrdCryptosslCipher::IsSupported(const char *cip) { // Check if the specified cipher is supported return (EVP_get_cipherbyname(cip) != 0); } //____________________________________________________________________________ XrdCryptosslCipher::XrdCryptosslCipher(const char *t, int l) { // Main Constructor // Complete initialization of a cipher of type t and length l // The initialization vector is also created // Used to create ciphers valid = 0; ctx = 0; fIV = 0; lIV = 0; cipher = 0; fDH = 0; deflength = 1; // Check and set type char cipnam[64] = {"bf-cbc"}; if (t && strcmp(t,"default")) { strcpy(cipnam,t); cipnam[63] = 0; } cipher = EVP_get_cipherbyname(cipnam); if (cipher) { // Determine key length l = (l > EVP_MAX_KEY_LENGTH) ? EVP_MAX_KEY_LENGTH : l; int ldef = EVP_CIPHER_key_length(cipher); int lgen = (l > ldef) ? l : ldef; // Generate and set a new key char *ktmp = XrdSutRndm::GetBuffer(lgen); if (ktmp) { // Init context ctx = EVP_CIPHER_CTX_new(); if (ctx) { valid = 1; // Try setting the key length if (l && l != ldef) { EVP_CipherInit_ex(ctx, cipher, 0, 0, 0, 1); EVP_CIPHER_CTX_set_key_length(ctx,l); EVP_CipherInit_ex(ctx, 0, 0, (unsigned char *)ktmp, 0, 1); if (l == EVP_CIPHER_CTX_key_length(ctx)) { // Use the l bytes at ktmp SetBuffer(l,ktmp); deflength = 0; } } if (!Length()) { EVP_CipherInit_ex(ctx, cipher, 0, (unsigned char *)ktmp, 0, 1); SetBuffer(ldef,ktmp); } // Set also the type SetType(cipnam); } // Cleanup delete[] ktmp; } } // Finally, generate and set a new IV if (valid) GenerateIV(); } //____________________________________________________________________________ XrdCryptosslCipher::XrdCryptosslCipher(const char *t, int l, const char *k, int liv, const char *iv) { // Constructor. // Initialize a cipher of type t and length l using the key at k and // the initialization vector at iv. // Used to import ciphers. valid = 0; ctx = 0; fIV = 0; lIV = 0; fDH = 0; cipher = 0; deflength = 1; // Check and set type char cipnam[64] = {"bf-cbc"}; if (t && strcmp(t,"default")) { strcpy(cipnam,t); cipnam[63] = 0; } cipher = EVP_get_cipherbyname(cipnam); if (cipher) { // Init context ctx = EVP_CIPHER_CTX_new(); if (ctx) { // Set the key SetBuffer(l,k); if (l != EVP_CIPHER_key_length(cipher)) deflength = 0; // Set also the type SetType(cipnam); // Set validity flag valid = 1; } } // // Init cipher if (valid) { // // Set the IV SetIV(liv,iv); if (deflength) { EVP_CipherInit_ex(ctx, cipher, 0, (unsigned char *)Buffer(), 0, 1); } else { EVP_CipherInit_ex(ctx, cipher, 0, 0, 0, 1); EVP_CIPHER_CTX_set_key_length(ctx,Length()); EVP_CipherInit_ex(ctx, 0, 0, (unsigned char *)Buffer(), 0, 1); } } } //____________________________________________________________________________ XrdCryptosslCipher::XrdCryptosslCipher(XrdSutBucket *bck) { // Constructor from bucket. // Initialize a cipher of type t and length l using the key at k // Used to import ciphers. valid = 0; ctx = 0; fIV = 0; lIV = 0; fDH = 0; cipher = 0; deflength = 1; if (bck && bck->size > 0) { valid = 1; kXR_int32 ltyp = 0; kXR_int32 livc = 0; kXR_int32 lbuf = 0; kXR_int32 lp = 0; kXR_int32 lg = 0; kXR_int32 lpub = 0; kXR_int32 lpri = 0; char *bp = bck->buffer; int cur = 0; memcpy(<yp,bp+cur,sizeof(kXR_int32)); cur += sizeof(kXR_int32); memcpy(&livc,bp+cur,sizeof(kXR_int32)); cur += sizeof(kXR_int32); memcpy(&lbuf,bp+cur,sizeof(kXR_int32)); cur += sizeof(kXR_int32); memcpy(&lp,bp+cur,sizeof(kXR_int32)); cur += sizeof(kXR_int32); memcpy(&lg,bp+cur,sizeof(kXR_int32)); cur += sizeof(kXR_int32); memcpy(&lpub,bp+cur,sizeof(kXR_int32)); cur += sizeof(kXR_int32); memcpy(&lpri,bp+cur,sizeof(kXR_int32)); cur += sizeof(kXR_int32); // Type if (ltyp) { char *buf = new char[ltyp+1]; if (buf) { memcpy(buf,bp+cur,ltyp); buf[ltyp] = 0; cipher = EVP_get_cipherbyname(buf); if (!cipher) cipher = EVP_get_cipherbyname("bf-cbc"); if (cipher) { // Set the type SetType(buf); } else { valid = 0; } delete[] buf; } else valid = 0; cur += ltyp; } // IV if (livc) { char *buf = new char[livc]; if (buf) { memcpy(buf,bp+cur,livc); cur += livc; // Set the IV SetIV(livc,buf); delete[] buf; } else valid = 0; cur += livc; } // buffer if (lbuf) { char *buf = new char[lbuf]; if (buf) { memcpy(buf,bp+cur,lbuf); // Set the buffer UseBuffer(lbuf,buf); if (cipher && lbuf != EVP_CIPHER_key_length(cipher)) deflength = 0; } else valid = 0; cur += lbuf; } // DH, if any if (lp > 0 || lg > 0 || lpub > 0 || lpri > 0) { if ((fDH = DH_new())) { char *buf = 0; BIGNUM *p = NULL, *g = NULL; BIGNUM *pub = NULL, *pri = NULL; // p if (lp > 0) { buf = new char[lp+1]; if (buf) { memcpy(buf,bp+cur,lp); buf[lp] = 0; BN_hex2bn(&p,buf); delete[] buf; } else valid = 0; cur += lp; } // g if (lg > 0) { buf = new char[lg+1]; if (buf) { memcpy(buf,bp+cur,lg); buf[lg] = 0; BN_hex2bn(&g,buf); delete[] buf; } else valid = 0; cur += lg; } DH_set0_pqg(fDH, p, NULL, g); // pub_key if (lpub > 0) { buf = new char[lpub+1]; if (buf) { memcpy(buf,bp+cur,lpub); buf[lpub] = 0; BN_hex2bn(&pub,buf); delete[] buf; } else valid = 0; cur += lpub; } // priv_key if (lpri > 0) { buf = new char[lpri+1]; if (buf) { memcpy(buf,bp+cur,lpri); buf[lpri] = 0; BN_hex2bn(&pri,buf); delete[] buf; } else valid = 0; cur += lpri; } DH_set0_key(fDH, pub, pri); int dhrc = 0; DH_check(fDH,&dhrc); if (dhrc == 0) valid = 1; } else valid = 0; } } // // Init cipher if (valid) { // Init context ctx = EVP_CIPHER_CTX_new(); if (ctx) { if (deflength) { EVP_CipherInit_ex(ctx, cipher, 0, (unsigned char *)Buffer(), 0, 1); } else { EVP_CipherInit_ex(ctx, cipher, 0, 0, 0, 1); EVP_CIPHER_CTX_set_key_length(ctx,Length()); EVP_CipherInit_ex(ctx, 0, 0, (unsigned char *)Buffer(), 0, 1); } } else valid = 0; } if (!valid) { Cleanup(); } } //____________________________________________________________________________ XrdCryptosslCipher::XrdCryptosslCipher(bool padded, int bits, char *pub, int lpub, const char *t) { // Constructor for key agreement. // If pub is not defined, generates a DH full key, // the public part and parameters can be retrieved using Public(). // The number of random bits to be used in 'bits'. // If pub is defined with the public part and parameters of the // counterpart fully initialize a cipher with that information. // Sets also the name to 't', if different from the default one. // Used for key agreement. EPNAME("sslCipher::XrdCryptosslCipher"); valid = 0; ctx = 0; fIV = 0; lIV = 0; fDH = 0; cipher = 0; deflength = 1; if (!pub) { DEBUG("generate DH full key"); // // at least 128 bits bits = (bits < kDHMINBITS) ? kDHMINBITS : bits; // // Generate params for DH object fDH = DH_new(); if (fDH && DH_generate_parameters_ex(fDH, bits, DH_GENERATOR_5, NULL)) { int prc = 0; DH_check(fDH,&prc); if (prc == 0) { // // Generate DH key if (DH_generate_key(fDH)) { // Init context ctx = EVP_CIPHER_CTX_new(); if (ctx) valid = 1; } } } } else { DEBUG("initialize cipher from key-agreement buffer"); // char *ktmp = 0; int ltmp = 0; // Extract string with bignumber BIGNUM *bnpub = 0; char *pb = strstr(pub,"---BPUB---"); char *pe = strstr(pub,"---EPUB--"); // one less (pub not null-terminated) if (pb && pe) { lpub = (int)(pb-pub); pb += 10; *pe = 0; BN_hex2bn(&bnpub, pb); *pe = '-'; } if (bnpub) { // // Prepare to decode the input buffer BIO *biop = BIO_new(BIO_s_mem()); if (biop) { // // Write buffer into BIO BIO_write(biop,pub,lpub); // // Create a key object if ((fDH = DH_new())) { // // Read parms from BIO PEM_read_bio_DHparams(biop,&fDH,0,0); int prc = 0; DH_check(fDH,&prc); if (prc == 0) { // // generate DH key if (DH_generate_key(fDH)) { // Now we can compute the cipher ktmp = new char[DH_size(fDH)]; memset(ktmp, 0, DH_size(fDH)); if (ktmp) { if (padded) { ltmp = DH_compute_key_padded((unsigned char *)ktmp,bnpub,fDH); } else { ltmp = DH_compute_key((unsigned char *)ktmp,bnpub,fDH); } if (ltmp > 0) valid = 1; } } } } BIO_free(biop); } BN_free( bnpub ); } // // If a valid key has been computed, set the cipher if (valid) { // Init context ctx = EVP_CIPHER_CTX_new(); if (ctx) { // Check and set type char cipnam[64] = {"bf-cbc"}; if (t && strcmp(t,"default")) { strcpy(cipnam,t); cipnam[63] = 0; } if ((cipher = EVP_get_cipherbyname(cipnam))) { // At most EVP_MAX_KEY_LENGTH bytes ltmp = (ltmp > EVP_MAX_KEY_LENGTH) ? EVP_MAX_KEY_LENGTH : ltmp; int ldef = EVP_CIPHER_key_length(cipher); // Try setting the key length if (ltmp != ldef) { EVP_CipherInit_ex(ctx, cipher, 0, 0, 0, 1); EVP_CIPHER_CTX_set_key_length(ctx,ltmp); EVP_CipherInit_ex(ctx, 0, 0, (unsigned char *)ktmp, 0, 1); if (ltmp == EVP_CIPHER_CTX_key_length(ctx)) { // Use the ltmp bytes at ktmp SetBuffer(ltmp,ktmp); deflength = 0; } } if (!Length()) { EVP_CipherInit_ex(ctx, cipher, 0, (unsigned char *)ktmp, 0, 1); SetBuffer(ldef,ktmp); } // Set also the type SetType(cipnam); } } else valid = 0; } // Cleanup if (ktmp) {delete[] ktmp; ktmp = 0;} } // Cleanup, if invalid if (!valid) Cleanup(); } //____________________________________________________________________________ XrdCryptosslCipher::XrdCryptosslCipher(const XrdCryptosslCipher &c) : XrdCryptoCipher() { // Copy Constructor // Basics deflength = c.deflength; valid = c.valid; ctx = 0; // IV lIV = 0; fIV = 0; SetIV(c.lIV,c.fIV); // Cipher cipher = c.cipher; // Set the key SetBuffer(c.Length(),c.Buffer()); // Set also the type SetType(c.Type()); // DH fDH = 0; if (valid && c.fDH) { valid = 0; if ((fDH = DH_new())) { const BIGNUM *p, *g; DH_get0_pqg(c.fDH, &p, NULL, &g); DH_set0_pqg(fDH, p ? BN_dup(p) : NULL, NULL, g ? BN_dup(g) : NULL); const BIGNUM *pub, *pri; DH_get0_key(c.fDH, &pub, &pri); DH_set0_key(fDH, pub ? BN_dup(pub) : NULL, pri ? BN_dup(pri) : NULL); int dhrc = 0; DH_check(fDH,&dhrc); if (dhrc == 0) valid = 1; } } if (valid) { // Init context ctx = EVP_CIPHER_CTX_new(); if (!ctx) valid = 0; } if (!valid) { Cleanup(); } } //____________________________________________________________________________ XrdCryptosslCipher::~XrdCryptosslCipher() { // Destructor. // Cleanup IV if (fIV) delete[] fIV; // Cleanups if (valid) EVP_CIPHER_CTX_free(ctx); Cleanup(); } //____________________________________________________________________________ void XrdCryptosslCipher::Cleanup() { // Cleanup temporary memory // Cleanup IV if (fDH) { DH_free(fDH); fDH = 0; } } //____________________________________________________________________________ bool XrdCryptosslCipher::Finalize(bool padded, char *pub, int /*lpub*/, const char *t) { // Finalize cipher during key agreement. Should be called // for a cipher build with special constructor defining member fDH. // The buffer pub should contain the public part of the counterpart. // Sets also the name to 't', if different from the default one. // Used for key agreement. EPNAME("sslCipher::Finalize"); if (!fDH) { DEBUG("DH undefined: this cipher cannot be finalized" " by this method"); return 0; } char *ktmp = 0; int ltmp = 0; valid = 0; if (pub) { // // Extract string with bignumber BIGNUM *bnpub = 0; char *pb = strstr(pub,"---BPUB---"); char *pe = strstr(pub,"---EPUB--"); if (pb && pe) { //lpub = (int)(pb-pub); pb += 10; *pe = 0; BN_hex2bn(&bnpub, pb); *pe = '-'; } if (bnpub) { // Now we can compute the cipher ktmp = new char[DH_size(fDH)]; memset(ktmp, 0, DH_size(fDH)); if (ktmp) { if (padded) { ltmp = DH_compute_key_padded((unsigned char *)ktmp,bnpub,fDH); } else { ltmp = DH_compute_key((unsigned char *)ktmp,bnpub,fDH); } if (ltmp > 0) valid = 1; } BN_free(bnpub); bnpub=0; } // // If a valid key has been computed, set the cipher if (valid) { // Check and set type char cipnam[64] = {"bf-cbc"}; if (t && strcmp(t,"default")) { strcpy(cipnam,t); cipnam[63] = 0; } if ((cipher = EVP_get_cipherbyname(cipnam))) { // At most EVP_MAX_KEY_LENGTH bytes ltmp = (ltmp > EVP_MAX_KEY_LENGTH) ? EVP_MAX_KEY_LENGTH : ltmp; int ldef = EVP_CIPHER_key_length(cipher); // Try setting the key length if (ltmp != ldef) { EVP_CipherInit_ex(ctx, cipher, 0, 0, 0, 1); EVP_CIPHER_CTX_set_key_length(ctx,ltmp); EVP_CipherInit_ex(ctx, 0, 0, (unsigned char *)ktmp, 0, 1); if (ltmp == EVP_CIPHER_CTX_key_length(ctx)) { // Use the ltmp bytes at ktmp SetBuffer(ltmp,ktmp); deflength = 0; } } if (!Length()) { EVP_CipherInit_ex(ctx, cipher, 0, (unsigned char *)ktmp, 0, 1); SetBuffer(ldef,ktmp); } // Set also the type SetType(cipnam); } } // Cleanup if (ktmp) {delete[] ktmp; ktmp = 0;} } // Cleanup, if invalid if (!valid) { EVP_CIPHER_CTX_free(ctx); Cleanup(); } // We are done return valid; } //_____________________________________________________________________________ int XrdCryptosslCipher::Publen() { // Minimum length of export format of public key static int lhdr = strlen("-----BEGIN DH PARAMETERS-----" "-----END DH PARAMETERS-----") + 3; if (fDH) { // minimum length of the core is 22 bytes int l = 2*DH_size(fDH); if (l < 22) l = 22; // for headers l += lhdr; // some margin return (l+20); } else return 0; } //_____________________________________________________________________________ char *XrdCryptosslCipher::Public(int &lpub) { // Return buffer with the public part of the DH key and the shared // parameters; lpub contains the length of the meaningful bytes. // Buffer should be deleted by the caller. static int lhend = strlen("-----END DH PARAMETERS-----"); if (fDH) { // // Calculate and write public key hex const BIGNUM *pub; DH_get0_key(fDH, &pub, NULL); char *phex = BN_bn2hex(pub); int lhex = strlen(phex); // // Prepare bio to export info buffer BIO *biop = BIO_new(BIO_s_mem()); if (biop) { int ltmp = Publen() + lhex + 20; char *pub = new char[ltmp]; if (pub) { // Write parms first PEM_write_bio_DHparams(biop,fDH); // Read key from BIO to buf BIO_read(biop,(void *)pub,ltmp); BIO_free(biop); // Add public key char *p = strstr(pub,"-----END DH PARAMETERS-----"); // Buffer length up to now lpub = (int)(p - pub) + lhend + 1; if (phex && p) { // position at the end p += (lhend+1); // Begin of public key hex memcpy(p,"---BPUB---",10); p += 10; // Calculate and write public key hex memcpy(p,phex,lhex); OPENSSL_free(phex); // End of public key hex p += lhex; memcpy(p,"---EPUB---",10); // Calculate total length lpub += (20 + lhex); } else { if (phex) OPENSSL_free(phex); } // return return pub; } } else { if (phex) OPENSSL_free(phex); } } lpub = 0; return (char *)0; } //_____________________________________________________________________________ void XrdCryptosslCipher::PrintPublic(BIGNUM *pub) { // Print public part // // Prepare bio to export info buffer BIO *biop = BIO_new(BIO_s_mem()); if (biop) { // Use a DSA structure to export the public part DSA *dsa = DSA_new(); if (dsa) { DSA_set0_key(dsa, BN_dup(pub), NULL); // Write public key to BIO PEM_write_bio_DSA_PUBKEY(biop,dsa); // Read key from BIO to buf int lpub = Publen(); char *bpub = new char[lpub]; if (bpub) { BIO_read(biop,(void *)bpub,lpub); cerr << bpub << endl; delete[] bpub; } DSA_free(dsa); } BIO_free(biop); } } //_____________________________________________________________________________ XrdSutBucket *XrdCryptosslCipher::AsBucket() { // Return pointer to a bucket created using the internal information // serialized // The bucket is responsible for the allocated memory XrdSutBucket *buck = (XrdSutBucket *)0; if (valid) { // Serialize .. total length kXR_int32 lbuf = Length(); kXR_int32 ltyp = Type() ? strlen(Type()) : 0; kXR_int32 livc = lIV; const BIGNUM *p, *g; const BIGNUM *pub, *pri; DH_get0_pqg(fDH, &p, NULL, &g); DH_get0_key(fDH, &pub, &pri); char *cp = BN_bn2hex(p); char *cg = BN_bn2hex(g); char *cpub = BN_bn2hex(pub); char *cpri = BN_bn2hex(pri); kXR_int32 lp = cp ? strlen(cp) : 0; kXR_int32 lg = cg ? strlen(cg) : 0; kXR_int32 lpub = cpub ? strlen(cpub) : 0; kXR_int32 lpri = cpri ? strlen(cpri) : 0; int ltot = 7*sizeof(kXR_int32) + ltyp + Length() + livc + lp + lg + lpub + lpri; char *newbuf = new char[ltot]; if (newbuf) { int cur = 0; memcpy(newbuf+cur,<yp,sizeof(kXR_int32)); cur += sizeof(kXR_int32); memcpy(newbuf+cur,&livc,sizeof(kXR_int32)); cur += sizeof(kXR_int32); memcpy(newbuf+cur,&lbuf,sizeof(kXR_int32)); cur += sizeof(kXR_int32); memcpy(newbuf+cur,&lp,sizeof(kXR_int32)); cur += sizeof(kXR_int32); memcpy(newbuf+cur,&lg,sizeof(kXR_int32)); cur += sizeof(kXR_int32); memcpy(newbuf+cur,&lpub,sizeof(kXR_int32)); cur += sizeof(kXR_int32); memcpy(newbuf+cur,&lpri,sizeof(kXR_int32)); cur += sizeof(kXR_int32); if (Type()) { memcpy(newbuf+cur,Type(),ltyp); cur += ltyp; } if (fIV) { memcpy(newbuf+cur,fIV,livc); cur += livc; } if (Buffer()) { memcpy(newbuf+cur,Buffer(),lbuf); cur += lbuf; } if (cp) { memcpy(newbuf+cur,cp,lp); cur += lp; OPENSSL_free(cp); } if (cg) { memcpy(newbuf+cur,cg,lg); cur += lg; OPENSSL_free(cg); } if (cpub) { memcpy(newbuf+cur,cpub,lpub); cur += lpub; OPENSSL_free(cpub); } if (cpri) { memcpy(newbuf+cur,cpri,lpri); cur += lpri; OPENSSL_free(cpri); } // The bucket now buck = new XrdSutBucket(newbuf,ltot,kXRS_cipher); } } return buck; } //____________________________________________________________________________ void XrdCryptosslCipher::SetIV(int l, const char *iv) { // Set IV from l bytes at iv. If !iv, sets the IV length. if (fIV) { delete[] fIV; fIV = 0; lIV = 0; } if (l > 0) { if (iv) { fIV = new char[l]; if (fIV) memcpy(fIV,iv,l); } lIV = l; } } //____________________________________________________________________________ char *XrdCryptosslCipher::RefreshIV(int &l) { // Regenerate IV and return it // Generate a new IV GenerateIV(); // Set output l = lIV; return fIV; } //____________________________________________________________________________ void XrdCryptosslCipher::GenerateIV() { // Generate IV // Cleanup existing one, if any if (fIV) { delete[] fIV; fIV = 0; lIV = 0; } // Generate a new one, using crypt-like chars fIV = XrdSutRndm::GetBuffer(EVP_MAX_IV_LENGTH, 3); if (fIV) lIV = EVP_MAX_IV_LENGTH; } //____________________________________________________________________________ int XrdCryptosslCipher::Encrypt(const char *in, int lin, char *out) { // Encrypt lin bytes at in with local cipher. // The outbut buffer must be provided by the caller for at least // EncOutLength(lin) bytes. // Returns number of meaningful bytes in out, or 0 in case of problems return EncDec(1, in, lin, out); } //____________________________________________________________________________ int XrdCryptosslCipher::Decrypt(const char *in, int lin, char *out) { // Decrypt lin bytes at in with local cipher. // The outbut buffer must be provided by the caller for at least // DecOutLength(lin) bytes. // Returns number of meaningful bytes in out, or 0 in case of problems return EncDec(0, in, lin, out); } //____________________________________________________________________________ int XrdCryptosslCipher::EncDec(int enc, const char *in, int lin, char *out) { // Encrypt (enc = 1)/ Decrypt (enc = 0) lin bytes at in with local cipher. // The outbut buffer must be provided by the caller for at least // EncOutLength(lin) or DecOutLength(lin) bytes. // Returns number of meaningful bytes in out, or 0 in case of problems EPNAME("Cipher::EncDec"); int lout = 0; const char *action = (enc == 1) ? "encrypting" : "decrypting"; // Check inputs if (!in || lin <= 0 || !out) { DEBUG("wrong inputs arguments"); if (!in) DEBUG("in: NULL"); if (lin <= 0) DEBUG("lin: "< 0) ? lIV : EVP_MAX_IV_LENGTH; }