// ---------------------------------------------------------------------- // File: SymKeys.cc // Author: Andreas-Joachim Peters - CERN // ---------------------------------------------------------------------- /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2011 CERN/Switzerland * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program 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 General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* ************************************************************************/ #include #include #include #include #if OPENSSL_VERSION_NUMBER >= 0x30000000L #include #endif #include #include #include #include #include #include "common/Namespace.hh" #include "common/SymKeys.hh" #include "google/protobuf/io/zero_copy_stream_impl.h" #include "zlib.h" #ifdef __APPLE__ #define ENOKEY 126 #define EKEYREJECTED 129 #endif EOSCOMMONNAMESPACE_BEGIN SymKeyStore gSymKeyStore; //< global SymKey store singleton XrdSysMutex SymKey::msMutex; // Add compatibility methods present in OpenSSL >= 1.1.0 if we use an older // version of OpenSSL #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined (LIBRESSL_VERSION_NUMBER) #define EVP_MD_CTX_new EVP_MD_CTX_create #define EVP_MD_CTX_free EVP_MD_CTX_destroy #define ASN1_STRING_get0_data(x) ASN1_STRING_data(x) static HMAC_CTX* HMAC_CTX_new(void) { HMAC_CTX* ctx = (HMAC_CTX*)OPENSSL_malloc(sizeof(*ctx)); if (ctx != NULL) { HMAC_CTX_init(ctx); } return ctx; } static void HMAC_CTX_free(HMAC_CTX* ctx) { if (ctx != NULL) { HMAC_CTX_cleanup(ctx); OPENSSL_free(ctx); } } #endif #if OPENSSL_VERSION_NUMBER >= 0x30000000L static void openssl3provider() { static XrdSysMutex initMtx; XrdSysMutexHelper iMtx(initMtx); static bool init=0; if (!init) { EVP_MD *mdp = EVP_MD_fetch(NULL, "SHA2-256", NULL); if (mdp) EVP_MD_free(mdp); (void) OSSL_PROVIDER_load(NULL, "legacy"); } } #endif //---------------------------------------------------------------------------- // Constructor for a symmetric key //---------------------------------------------------------------------------- SymKey::SymKey(const char* inkey, time_t invalidity) { key64 = ""; memcpy(key, inkey, SHA_DIGEST_LENGTH); SymKey::Base64Encode(key, SHA_DIGEST_LENGTH, key64); mValidity = invalidity; SHA_CTX sha1; SHA1_Init(&sha1); SHA1_Update(&sha1, (const char*) inkey, SHA_DIGEST_LENGTH); SHA1_Final((unsigned char*) keydigest, &sha1); XrdOucString skeydigest64 = ""; Base64Encode(keydigest, SHA_DIGEST_LENGTH, skeydigest64); strncpy(keydigest64, skeydigest64.c_str(), (SHA_DIGEST_LENGTH * 2) - 1); } //------------------------------------------------------------------------------ // Compute the HMAC SHA-256 value //------------------------------------------------------------------------------ std::string SymKey::HmacSha256(const std::string& key, const std::string& data, unsigned int blockSize, unsigned int resultSize) { HMAC_CTX* ctx = HMAC_CTX_new(); std::string result; unsigned int data_len = data.length(); unsigned int key_len = key.length(); unsigned char* pKey = (unsigned char*) key.c_str(); unsigned char* pData = (unsigned char*) data.c_str(); result.resize(resultSize); unsigned char* pResult = (unsigned char*) result.c_str(); ENGINE_load_builtin_engines(); ENGINE_register_all_complete(); HMAC_Init_ex(ctx, pKey, key_len, EVP_sha256(), NULL); while (data_len > blockSize) { HMAC_Update(ctx, pData, blockSize); data_len -= blockSize; pData += blockSize; } if (data_len) { HMAC_Update(ctx, pData, data_len); } HMAC_Final(ctx, pResult, &resultSize); HMAC_CTX_free(ctx); return result; } //------------------------------------------------------------------------------ // Compute the HMAC SHA-256 value //------------------------------------------------------------------------------ std::string SymKey::Sha256(const std::string& data, unsigned int blockSize) { unsigned int data_len = data.length(); unsigned char* pData = (unsigned char*) data.c_str(); std::string result; result.resize(EVP_MAX_MD_SIZE); unsigned char* pResult = (unsigned char*) result.c_str(); unsigned int sz_result; { XrdSysMutexHelper scope_lock(msMutex); EVP_MD_CTX* md_ctx = EVP_MD_CTX_new(); EVP_DigestInit_ex(md_ctx, EVP_sha256(), NULL); while (data_len > blockSize) { EVP_DigestUpdate(md_ctx, pData, blockSize); data_len -= blockSize; pData += blockSize; } if (data_len) { EVP_DigestUpdate(md_ctx, pData, data_len); } EVP_DigestFinal_ex(md_ctx, pResult, &sz_result); EVP_MD_CTX_free(md_ctx); } // Return the hexdigest of the SHA256 value std::ostringstream oss; oss.fill('0'); oss << std::hex; pResult = (unsigned char*) result.c_str(); for (unsigned int i = 0; i < sz_result; ++i) { oss << std::setw(2) << (unsigned int) *pResult; pResult++; } result = oss.str(); return result; } //------------------------------------------------------------------------------ // Compute the HMAC SHA-1 value according to AWS standard //------------------------------------------------------------------------------ std::string SymKey::HmacSha1(std::string& data, const char* key) { std::string result(EVP_MAX_MD_SIZE, '\0'); unsigned int result_size = 0; unsigned int data_len = data.length(); // If no key specifed used the default key provided by the SymKeyStore if (!key) { key = gSymKeyStore.GetCurrentKey()->GetKey64(); } unsigned int key_len = strlen(key); unsigned char* pData = (unsigned char*) data.c_str(); unsigned char* pResult = (unsigned char*) result.c_str(); pResult = HMAC(EVP_sha1(), (void*)key, key_len, pData, data_len, pResult, &result_size); result.resize(result_size + 1); return result; } //------------------------------------------------------------------------------ // Base64 encoding function - base function //------------------------------------------------------------------------------ bool SymKey::Base64Encode(const char* decoded_bytes, ssize_t decoded_length, std::string& out) { BIO* b64 = BIO_new(BIO_f_base64()); if (!b64) { return false; } BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); BIO* bmem = BIO_new(BIO_s_mem()); if (!bmem) { return false; } b64 = BIO_push(b64, bmem); BIO_write(b64, decoded_bytes, decoded_length); if (BIO_flush(b64) != 1) { BIO_free_all(b64); return false; } BUF_MEM* bptr; BIO_get_mem_ptr(b64, &bptr); out.assign(bptr->data, bptr->length); BIO_free_all(b64); return true; } //------------------------------------------------------------------------------ // Base64 encoding function - returning an XrdOucString object //------------------------------------------------------------------------------ bool SymKey::Base64Encode(const char* in, unsigned int inlen, XrdOucString& out) { std::string encoded; if (Base64Encode(in, inlen, encoded)) { out = encoded.c_str(); return true; } return false; } //------------------------------------------------------------------------------ // Base64 decoding function - base function //------------------------------------------------------------------------------ bool SymKey::Base64Decode(const char* encoded_bytes, char*& decoded_bytes, ssize_t& decoded_length) { BIO* bmem = BIO_new_mem_buf((void*)encoded_bytes, -1); if (!bmem) { return false; } BIO* b64 = BIO_new(BIO_f_base64()); if (!b64) { return false; } BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); bmem = BIO_push(b64, bmem); ssize_t buffer_length = BIO_get_mem_data(bmem, NULL); decoded_bytes = (char*) malloc(buffer_length + 1); decoded_length = BIO_read(bmem, decoded_bytes, buffer_length); decoded_bytes[decoded_length] = '\0'; BIO_free_all(bmem); return true; } //------------------------------------------------------------------------------ // Base64 decoding of input given as XrdOucString //------------------------------------------------------------------------------ bool SymKey::Base64Decode(const char* in, std::string& out) { BIO* bmem = BIO_new_mem_buf((void*)in, -1); if (!bmem) { return false; } BIO* b64 = BIO_new(BIO_f_base64()); if (!b64) { return false; } BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); bmem = BIO_push(b64, bmem); size_t buffer_length = BIO_get_mem_data(bmem, NULL); out.resize(buffer_length, '\0'); int nread = BIO_read(bmem, (char*)out.data(), buffer_length); out.resize(nread); BIO_free_all(bmem); return true; } //------------------------------------------------------------------------------ // Base64 decoding of input given as XrdOucString //------------------------------------------------------------------------------ bool SymKey::Base64Decode(XrdOucString& in, char*& out, ssize_t& outlen) { return Base64Decode(in.c_str(), out, outlen); } //------------------------------------------------------------------------------ // Encode a base64: prefixed string - XrdOucString as input //------------------------------------------------------------------------------ bool SymKey::Base64(XrdOucString& in, XrdOucString& out) { if (in.beginswith("base64:")) { out = in; return false; } bool done = Base64Encode((char*) in.c_str(), in.length(), out); if (done) { out.insert("base64:", 0); return true; } else { return false; } } //------------------------------------------------------------------------------ // Encode a base64: prefixed string - std::string as input //------------------------------------------------------------------------------ bool SymKey::Base64(std::string& in, std::string& out) { if (in.substr(0, 7) == "base64:") { out = in; return false; } XrdOucString sout; bool done = Base64Encode((char*) in.c_str(), in.length(), sout); if (done) { out = "base64:"; out.append(sout.c_str()); return true; } else { return false; } } //------------------------------------------------------------------------------ // Decode a base64: prefixed string - XrdOucString as input //------------------------------------------------------------------------------ bool SymKey::DeBase64(XrdOucString& in, XrdOucString& out) { if (!in.beginswith("base64:")) { out = in; return true; } XrdOucString in64 = in; in64.erase(0, 7); char* valout = 0; ssize_t valout_len = 0; if (Base64Decode(in64, valout, valout_len)) { std::string s; s.assign(valout, 0, valout_len); out = s.c_str(); free(valout); return true; } return false; } //------------------------------------------------------------------------------ // Decode a base64: prefixed string - std::string as input //------------------------------------------------------------------------------ bool SymKey::DeBase64(const std::string& in, std::string& out) { if (in.substr(0, 7) != "base64:") { out = in; return true; } XrdOucString in64 = in.c_str(); in64.erase(0, 7); char* valout = 0; ssize_t valout_len = 0; Base64Decode(in64, valout, valout_len); if (valout) { out.assign(valout, valout_len); free(valout); return true; } return false; } //------------------------------------------------------------------------------ // Encode a base64: prefixed string - std::string as input //------------------------------------------------------------------------------ bool SymKey::ZBase64(std::string& in, std::string& out) { char desthex[9]; sprintf(desthex, "%08lx", in.size()); std::vector destbuffer; destbuffer.resize(in.size() + 128); destbuffer.reserve(in.size() + 128); uLongf destLen = destbuffer.size() - 8; sprintf(&(destbuffer[0]), "%08lx", in.size()); if (compress((Bytef*) & (destbuffer[8]), &destLen, (const Bytef*)in.c_str(), in.size())) { return false; } XrdOucString sout; bool done = Base64Encode((char*) & (destbuffer[0]), destLen + 8, sout); if (done) { out = "zbase64:"; out.append(sout.c_str()); return true; } else { return false; } } //------------------------------------------------------------------------------ // Decode a zbase64: prefixed string - std::string as input //------------------------------------------------------------------------------ bool SymKey::ZDeBase64(std::string& in, std::string& out) { if (in.substr(0, 8) != "zbase64:") { out = in; return true; } XrdOucString in64 = in.c_str(); in64.erase(0, 8); char* valout = 0; ssize_t valout_len = 0; Base64Decode(in64, valout, valout_len); if (valout) { // first 8 bytes are the length of the decompressed data in hext std::string desthex; desthex.assign(valout, 8); // now decompress the b64 buffer unsigned long destLen = strtoul(desthex.c_str(), 0, 16); std::vector destbuffer; destbuffer.reserve(destLen); destbuffer.resize(destLen); uLongf dstLen = destbuffer.size(); if (uncompress((Bytef*) & (destbuffer[0]), &dstLen, (const Bytef*)valout + 8, valout_len - 8)) { free(valout); return false; } else { free(valout); if (dstLen == destLen) { out.assign(&(destbuffer[0]), dstLen); return true; } else { return false; } } } return false; } //------------------------------------------------------------------------------ // Obfucate a buffer based on offset and hmac //------------------------------------------------------------------------------ void SymKey::ObfuscateBuffer(char* dst, const char* src, size_t size, off_t offset, SymKey::hmac_t& hmac) { const char* cipher = hmac.key.c_str(); size_t len = hmac.key.length(); size_t ilen = offset % len; bool overwrite = (dst == src); if ((!ilen) && (!(len % 8)) && (!(size % len)) && (!((unsigned long long)(dst) % 8)) && (!((unsigned long long)(src) % 8))) { // fast case uint64_t* pbuf = (uint64_t*) dst; uint64_t* sbuf = (uint64_t*) src; for (size_t i = 0; i < size / len; ++i) { uint64_t* cipher64 = (uint64_t*)(cipher); for (size_t k = 0; k < len / 8; ++k) { if (overwrite) { *pbuf++ ^= *cipher64++; } else { *pbuf++ = *sbuf++ ^ *cipher64++; } } } } else { // slow case if (dst == src) { for (size_t i = 0; i < size; ++i) { *dst++ ^= cipher[(offset + i) % len]; } } else { for (size_t i = 0; i < size; ++i) { *dst++ = *src++ ^ cipher[(offset + i) % len]; } } } } //------------------------------------------------------------------------------ // Unobfucate a buffer based on offset and hmac //------------------------------------------------------------------------------ void SymKey::UnobfuscateBuffer(char* buf, size_t size, off_t offset, SymKey::hmac_t& hmac) { const char* cipher = hmac.key.c_str(); size_t len = hmac.key.length(); size_t ilen = offset % len; if ((!ilen) && (!(len % 8)) && (!(size % len)) && (!((unsigned long long)(buf) % 8))) { // fast case uint64_t* pbuf = (uint64_t*) buf; for (size_t i = 0; i < size / len; ++i) { uint64_t* cipher64 = (uint64_t*)(cipher); for (size_t k = 0; k < len / 8; ++k) { *pbuf++ ^= *cipher64++; } } } else { // slow case char* pbuf = buf; for (size_t i = 0; i < size; ++i) { *pbuf++ ^= cipher[(offset + i) % len]; } } } //------------------------------------------------------------------------------ // Serialise a Google Protobuf object and base64 encode the result //------------------------------------------------------------------------------ bool SymKey::ProtobufBase64Encode(const google::protobuf::Message* msg, std::string& output) { #if GOOGLE_PROTOBUF_VERSION < 3004000 auto sz = msg->ByteSize(); #else auto sz = msg->ByteSizeLong(); #endif std::string buffer(sz , '\0'); google::protobuf::io::ArrayOutputStream aos((void*)buffer.data(), sz); if (!msg->SerializeToZeroCopyStream(&aos)) { return false; } return Base64Encode(buffer.data(), buffer.size(), output); } //------------------------------------------------------------------------------ // Set a key providing its base64 encoded representation and validity //------------------------------------------------------------------------------ SymKey* SymKeyStore::SetKey64(const char* inkey64, time_t invalidity) { if (!inkey64) { return 0; } char* binarykey = 0; ssize_t outlen = 0; XrdOucString key64 = inkey64; if (!SymKey::Base64Decode(key64, binarykey, outlen)) { return 0; } if (outlen != SHA_DIGEST_LENGTH) { free(binarykey); return 0; } return SetKey(binarykey, invalidity); } //------------------------------------------------------------------------------ // Set a key providing it's binary representation and validity //------------------------------------------------------------------------------ SymKey* SymKeyStore::SetKey(const char* inkey, time_t invalidity) { if (!inkey) { return 0; } std::unique_lock scope_lock(mMutex); SymKey* key = SymKey::Create(inkey, invalidity); free((void*) inkey); if (!key) { return 0; } // check if it exists SymKey* existkey = Store.Find(key->GetDigest64()); // if it exists we remove it add it with the new validity time // if it exists we remove it add it with the new validity time if (existkey) { Store.Del(existkey->GetDigest64()); } Store.Add(key->GetDigest64(), key, invalidity ? (invalidity + EOSCOMMONSYMKEYS_DELETIONOFFSET) : 0); // point the current key to last added currentKey = key; return key; } //------------------------------------------------------------------------------ // Retrieve key by keydigest in base64 format //------------------------------------------------------------------------------ SymKey* SymKeyStore::GetKey(const char* inkeydigest64) { std::unique_lock scope_lock(mMutex); SymKey* key = Store.Find(inkeydigest64); // if it exists we remove it add it with the new validity time return key; } //------------------------------------------------------------------------------ // Retrieve last added valid key from the store //------------------------------------------------------------------------------ SymKey* SymKeyStore::GetCurrentKey() { if (currentKey) { if (currentKey->IsValid()) { return currentKey; } } return 0; } //------------------------------------------------------------------------------ // Create EOS specific capability and append to the output env object //------------------------------------------------------------------------------ int SymKey::CreateCapability(XrdOucEnv* inenv, XrdOucEnv*& outenv, SymKey* key, std::chrono::seconds validity) { if (!key) { return ENOKEY; } if (!inenv) { return EINVAL; } if (outenv) { delete outenv; outenv = nullptr; } int envlen; XrdOucString toencrypt = inenv->Env(envlen); // Add the validity time toencrypt += "&cap.valid="; char svalidity[32]; snprintf(svalidity, 32, "%llu", (long long unsigned int)(time(NULL) + validity.count())); toencrypt += svalidity; XrdOucString encrypted = ""; if (!SymmetricStringEncrypt(toencrypt, encrypted, (char*)key->GetKey())) { return EKEYREJECTED; } XrdOucString encenv = ""; encenv += "cap.sym="; encenv += key->GetDigest64(); encenv += "&cap.msg="; encenv += encrypted; while (encenv.replace('\n', '#')) {}; outenv = new XrdOucEnv(encenv.c_str()); return 0; } //------------------------------------------------------------------------------ // Extract EOS specific capability encoded in the env object //------------------------------------------------------------------------------ int SymKey::ExtractCapability(XrdOucEnv* inenv, XrdOucEnv*& outenv) { if (outenv) { delete outenv; outenv = nullptr; } if (!inenv) { return EINVAL; } int envlen; XrdOucString instring = inenv->Env(envlen); while (instring.replace('#', '\n')) {}; XrdOucEnv fixedenv(instring.c_str()); const char* symkey = fixedenv.Get("cap.sym"); const char* symmsg = fixedenv.Get("cap.msg"); // fprintf(stderr,"%s\n%s\n", symkey, symmsg); if ((!symkey) || (!symmsg)) { return EINVAL; } eos::common::SymKey* key {nullptr}; if (!(key = eos::common::gSymKeyStore.GetKey(symkey))) { return ENOKEY; } XrdOucString todecrypt = symmsg; XrdOucString decrypted = ""; if (!SymmetricStringDecrypt(todecrypt, decrypted, (char*)key->GetKey())) { return EKEYREJECTED; } outenv = new XrdOucEnv(decrypted.c_str()); // Check time validity if (!outenv->Get("cap.valid")) { // validity missing return EINVAL; } else { time_t now = time(NULL); time_t capnow = atoi(outenv->Get("cap.valid")); // Capability expired!!! if (capnow < now) { return ETIME; } } return 0; } //------------------------------------------------------------------------------ // Cipher encrypt //------------------------------------------------------------------------------ bool SymKey::CipherEncrypt(const char* data, ssize_t data_length, char*& encrypted_data, ssize_t& encrypted_length, char* key) { // Set the initialization vector so that the encrypted text is unique uint_fast8_t iv[EVP_MAX_IV_LENGTH]; sprintf((char*)iv, "$KJh#(}q"); const EVP_CIPHER* cipher = EVP_des_cbc(); #if OPENSSL_VERSION_NUMBER >= 0x30000000L openssl3provider(); #endif // This is slow, but we really don't care here for small messages int buff_capacity = data_length + EVP_CIPHER_block_size(cipher); char* encrypt_buff = (char*) malloc(buff_capacity); if (!encrypt_buff) { return false; } uint_fast8_t* fast_ptr = (uint_fast8_t*)encrypt_buff; encrypted_length = 0; EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); EVP_CIPHER_CTX_init(ctx); EVP_EncryptInit_ex(ctx, cipher, 0, (const unsigned char*)key, iv); if (!(EVP_EncryptUpdate(ctx, fast_ptr, (int*)&encrypted_length, (uint_fast8_t*)data, data_length))) { EVP_CIPHER_CTX_free(ctx); free(encrypt_buff); return false; } if (encrypted_length < 0) { EVP_CIPHER_CTX_free(ctx); free(encrypt_buff); return false; } fast_ptr += encrypted_length; int tmplen = 0; if (!(EVP_EncryptFinal(ctx, fast_ptr, &tmplen))) { EVP_CIPHER_CTX_free(ctx); free(encrypt_buff); return false; } encrypted_length += tmplen; if (encrypted_length > buff_capacity) { EVP_CIPHER_CTX_free(ctx); free(encrypt_buff); return false; } encrypted_data = encrypt_buff; EVP_CIPHER_CTX_free(ctx); return true; } //------------------------------------------------------------------------------ // Cipher decrypt //------------------------------------------------------------------------------ bool SymKey::CipherDecrypt(char* encrypted_data, ssize_t encrypted_length, char*& data, ssize_t& data_length, char* key, bool noerror) { // Set the initialization vector uint_fast8_t iv[EVP_MAX_IV_LENGTH]; sprintf((char*)iv, "$KJh#(}q"); const EVP_CIPHER* cipher = EVP_des_cbc(); if (!cipher) { return false; } #if OPENSSL_VERSION_NUMBER >= 0x30000000L openssl3provider(); #endif // This is slow, but we really don't care here for small messages. We're // going to null terminate the text under the assumption it's non-null // terminated ASCII text. int buff_capacity = encrypted_length + EVP_CIPHER_block_size(cipher) + 1; data = (char*) malloc(buff_capacity); if (!data) { return false; } uint_fast8_t* fast_ptr = (uint_fast8_t*)data; data_length = 0; EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); EVP_CIPHER_CTX_init(ctx); EVP_DecryptInit_ex(ctx, cipher, 0, (const unsigned char*) key, iv); int decrypt_len = 0; if (!EVP_DecryptUpdate(ctx, fast_ptr, &decrypt_len, (uint_fast8_t*)encrypted_data, encrypted_length)) { EVP_CIPHER_CTX_free(ctx); free(data); return false; } if (decrypt_len < 0) { EVP_CIPHER_CTX_free(ctx); free(data); return false; } fast_ptr += decrypt_len; int tmplen = 0; if (!EVP_DecryptFinal(ctx, fast_ptr, &tmplen)) { if (!noerror) { std::cerr << __FUNCTION__ << "errno=" << EINVAL << " msg=\"Unable to finalize cipher block\"" << std::endl; } EVP_CIPHER_CTX_free(ctx); free(data); return false; } data_length = decrypt_len + tmplen; if (data_length > buff_capacity) { EVP_CIPHER_CTX_free(ctx); free(data); return false; } // Null terminate the decrypted buffer data[data_length] = 0; EVP_CIPHER_CTX_free(ctx); return true; } //------------------------------------------------------------------------------ // Encrypt string and base64 encode it //------------------------------------------------------------------------------ bool SymKey::SymmetricStringEncrypt(XrdOucString& in, XrdOucString& out, char* key) { char* tmpbuf = 0; ssize_t tmpbuflen = 0; if (!CipherEncrypt(in.c_str(), in.length(), tmpbuf, tmpbuflen, key)) { return false; } std::string b64out; if (!Base64Encode(tmpbuf, tmpbuflen, b64out)) { free(tmpbuf); return false; } out = b64out.c_str(); free(tmpbuf); return true; } //------------------------------------------------------------------------------ // Decrypt base64 encoded string //------------------------------------------------------------------------------ bool SymKey::SymmetricStringDecrypt(XrdOucString& in, XrdOucString& out, char* key) { char* tmpbuf = 0; ssize_t tmpbuflen; if (!Base64Decode((char*)in.c_str(), tmpbuf, tmpbuflen)) { free(tmpbuf); return false; } char* data; ssize_t data_len; if (!CipherDecrypt(tmpbuf, tmpbuflen, data, data_len, key, true)) { free(tmpbuf); return false; } out = data; free(tmpbuf); free(data); return true; } EOSCOMMONNAMESPACE_END