XRootD
XrdCryptoLite_BFecb.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d C r y p t o L i t e _ B F e c b . c c */
4 /* */
5 /* (c) 2026 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* Produced by Andrew Hanushevsky for Stanford University under contract */
7 /* DE-AC02-76-SFO0515 with the Department of Energy */
8 /* */
9 /* This file is part of the XRootD software suite. */
10 /* */
11 /* XRootD is free software: you can redistribute it and/or modify it under */
12 /* the terms of the GNU Lesser General Public License as published by the */
13 /* Free Software Foundation, either version 3 of the License, or (at your */
14 /* option) any later version. */
15 /* */
16 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
17 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
18 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
19 /* License for more details. */
20 /* */
21 /* You should have received a copy of the GNU Lesser General Public License */
22 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
23 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
24 /* */
25 /* The copyright holder's institutional names and contributor's names may not */
26 /* be used to endorse or promote products derived from this software without */
27 /* specific prior written permission of the institution or contributor. */
28 /******************************************************************************/
29 
30 #include <openssl/evp.h>
31 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
32 #include <openssl/provider.h>
33 #endif
34 
36 #include "XrdOuc/XrdOucUtils.hh"
37 
38 /******************************************************************************/
39 /* C o n s t r u c t o r */
40 /******************************************************************************/
41 
43  const unsigned char* key,
44  unsigned int keylen)
45  : decCTX(0), encCTX(0)
46 {
47 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
48 // With openssl v3 the blowfish cipher is only available via the "legacy"
49 // provider. Legacy is typically not enabled by default (but can be via
50 // openssl.cnf) so it is loaded here. Explicitly loading a provider will
51 // disable the automatic loading of the "default" one. The default might
52 // not have already been loaded, or standard algorithms might be available
53 // via another configured provider, such as FIPS. So an attempt is made to
54 // fetch a common default algorithm, possibly automaticlly loading the
55 // default provider. Afterwards the legacy provider is loaded.
56 //
57  static struct loadProviders {
58  loadProviders() {
59  EVP_MD *mdp = EVP_MD_fetch(NULL, "SHA2-256", NULL);
60  if (mdp) EVP_MD_free(mdp);
61  // Load legacy provider into the default (NULL) library context
62  (void) OSSL_PROVIDER_load(NULL, "legacy");
63  }
64  } lp;
65 #endif
66 
67 // Handle auto generation of a random key
68 //
69  unsigned char bfKey[16];
70  if (!key || !keylen)
71  {XrdOucUtils::Random(bfKey, sizeof(bfKey));
72  key = bfKey;
73  keylen = sizeof(bfKey);
74  }
75 
76 // The legacy openssl EVP is rather outdated, cumbersome, non thread-safe,
77 // and badly documented. Unfortunately, it is the only one generally availabe
78 // on all platforms (modern versions like CryptoPP need manual installation).
79 // So, we need to construct a decryption context and an encryption context
80 // because the context can only do one type of action at a time and resetting
81 // the key when switching actions is CPU intensive. What a pain in the but!
82 //
83  aOK = false;
84  if (!(decCTX = EVP_CIPHER_CTX_new())) return;
85  if (1 != EVP_DecryptInit_ex(decCTX, EVP_bf_ecb(), NULL, NULL, NULL)) return;
86  EVP_CIPHER_CTX_set_padding(decCTX, 0);
87  EVP_CIPHER_CTX_set_key_length(decCTX, keylen);
88  if (1 != EVP_DecryptInit_ex(decCTX, NULL, NULL, key, NULL)) return;
89 
90  if (!(encCTX = EVP_CIPHER_CTX_new())) return;
91  if (1 != EVP_EncryptInit_ex(encCTX, EVP_bf_ecb(), NULL, NULL, NULL)) return;
92  EVP_CIPHER_CTX_set_padding(encCTX, 0);
93  EVP_CIPHER_CTX_set_key_length(encCTX, keylen);
94  if (1 != EVP_EncryptInit_ex(encCTX, NULL, NULL, key, NULL)) return;
95  aOK = true;
96 }
97 
98 /******************************************************************************/
99 /* D e s t r u c t o r */
100 /******************************************************************************/
101 
103 {
104  EVP_CIPHER_CTX_free(decCTX);
105  EVP_CIPHER_CTX_free(encCTX);
106 }
107 
108 /******************************************************************************/
109 /* D e c r y p t */
110 /******************************************************************************/
111 
112 void XrdCryptoLite_BFecb::Decrypt(const unsigned char* in8,
113  unsigned char* out8)
114 {
115  int dlen;
116 
117 // Perform the action. Since we said padding is zero and the input must be
118 // 8 bytes, and we are using blowfish ECB when we decrypt the result will
119 // not be buffered but placed in the output buffer upon return.
120 //
121  evpMutex.Lock();
122  EVP_DecryptUpdate(decCTX, out8, &dlen, in8, 8);
123  evpMutex.UnLock();
124 }
125 
126 /******************************************************************************/
127 /* E n c r y p t */
128 /******************************************************************************/
129 
130 void XrdCryptoLite_BFecb::Encrypt(const unsigned char* in8,
131  unsigned char* out8)
132 {
133  int dlen;
134 
135 // Perform the action
136 //
137 // Perform the action. Since we said padding is zero and the input must be
138 // 8 bytes, and we are using blowfish ECB when we encrypt the result will
139 // not be buffered but placed in the output buffer upon return.
140 //
141  evpMutex.Lock();
142  EVP_EncryptUpdate(encCTX, out8, &dlen, in8, 8);
143  evpMutex.UnLock();
144 }
145 
146 /******************************************************************************/
147 /* Static: I n s t a n c e */
148 /******************************************************************************/
149 
151  unsigned int klen)
152 {
153  XrdCryptoLite_BFecb* obj;
154  bool isOK;
155 
156 // Get an instance or return a nil pointer
157 //
158  obj = new XrdCryptoLite_BFecb(isOK, key, klen);
159  if (!isOK) {delete obj; obj = 0;}
160  return obj;
161 }
static XrdCryptoLite_BFecb * Instance(const unsigned char *key=0, unsigned int klen=0)
XrdCryptoLite_BFecb(bool &aOK, const unsigned char *key=0, unsigned int keylen=0)
void Decrypt(const unsigned char *in8, unsigned char *out8)
void Encrypt(const unsigned char *in8, unsigned char *out8)
static void Random(unsigned char *buff, unsigned int inblen)