irods  4.2.8
About: iRODS (the integrated Rule Oriented Data System) is a distributed data-management system for creating data grids, digital libraries, persistent archives, and real-time data systems.
  Fossies Dox: irods-4.2.8.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

irods_buffer_encryption.cpp
Go to the documentation of this file.
1 // =-=-=-=-=-=-=-
3 #include "irods_log.hpp"
4 
5 // =-=-=-=-=-=-=-
6 // ssl includes
7 #include <openssl/rand.h>
8 #include <openssl/err.h>
9 #include <openssl/aes.h>
10 #include <openssl/md5.h>
11 
12 #include <iostream>
13 #include <sstream>
14 #include <iomanip>
15 #include <memory>
16 
17 namespace irods {
19  public:
21  OpenSSL_add_all_algorithms();
22  }
23 
25  EVP_cleanup();
26  }
27  };
29 
31  unsigned char* _buf,
32  int _sz ) {
33  MD5_CTX ctx;
34  MD5_Init( &ctx );
35  MD5_Update( &ctx, _buf, _sz );
36  unsigned char hash[16];
37  MD5_Final( hash, &ctx );
38 
39  std::stringstream ss;
40  for ( int i = 0; i < 16; ++i ) {
41  ss << std::setfill( '0' ) << std::setw( 2 ) << std::hex << ( int )hash[i];
42  }
43 
44  return ss.str();
45  }
46 
47 // =-=-=-=-=-=-=-
48 // public - constructor
50  key_size_( 32 ),
51  salt_size_( 8 ),
52  num_hash_rounds_( 16 ),
53  algorithm_( "aes-256-cbc" ) {
54  }
55 
57  int _key_sz,
58  int _salt_sz,
59  int _num_rnds,
60  const char* _algo ) :
61  key_size_( _key_sz ),
62  salt_size_( _salt_sz ),
63  num_hash_rounds_( _num_rnds ),
64  algorithm_( _algo ) {
65 
67  algorithm_.begin(),
68  algorithm_.end(),
69  algorithm_.begin(),
70  ::tolower );
71 
72  // =-=-=-=-=-=-=-
73  // select some sane defaults
74  if ( 0 == key_size_ ) {
75  key_size_ = 32;
76  }
77 
78  if ( 0 == salt_size_ ) {
79  salt_size_ = 8;
80  }
81 
82  if ( 0 == num_hash_rounds_ ) {
83  num_hash_rounds_ = 16;
84  }
85 
86  if ( algorithm_.empty() ) {
87  algorithm_ = "aes-256-cbc";
88  }
89  } // ctor
90 
91 // =-=-=-=-=-=-=-
92 // public - destructor
94  } // dtor
95 
96 // =-=-=-=-=-=-=-
97 // public static - generate a random key
99  array_t& _out_key,
100  int _key_size
101  ) {
102  // =-=-=-=-=-=-=-
103  // generate random bytes
104  _out_key.resize( _key_size );
105  const int rnd_err = RAND_bytes( &_out_key[0], _key_size );
106  if ( 1 != rnd_err ) {
107  char err[ 256 ];
108  ERR_error_string_n( ERR_get_error(), err, sizeof( err ) );
109  const std::string msg = std::string( "failed in RAND_bytes - " ) + err;
110  return ERROR( ERR_get_error(), msg );
111  }
112 
113  return SUCCESS();
114 
115  } // buffer_crypt::generate_key
116 
117 // =-=-=-=-=-=-=-
118 // public static - hex encode byte array
120  const array_t& _in_buf,
121  std::string& _out_str ) {
122  std::stringstream ss;
123  for ( irods::buffer_crypt::array_t::size_type i = 0; i < _in_buf.size(); ++i ) {
124  ss << std::setfill( '0' ) << std::setw( 2 ) << std::hex << static_cast<unsigned int>( _in_buf[i] );
125  }
126 
127  _out_str = ss.str();
128 
129  return SUCCESS();
130  } // buffer_crypt::hex_encode
131 
132 // =-=-=-=-=-=-=-
133 // public - create a hashed key and initialization vector
135  array_t& _out_iv ) {
136  // =-=-=-=-=-=-=-
137  // generate a random initialization vector
138  unsigned char* iv = new unsigned char[ key_size_ ];
139  int rnd_err = RAND_bytes(
140  iv,
141  key_size_ );
142  if ( 1 != rnd_err ) {
143  delete [] iv;
144  char err[ 256 ];
145  ERR_error_string_n( ERR_get_error(), err, 256 );
146  std::string msg( "failed in RAND_bytes - " );
147  msg += err;
148  return ERROR( ERR_get_error(), msg );
149 
150  }
151 
152  // =-=-=-=-=-=-=-
153  // copy the iv to the out variable
154  _out_iv.assign(
155  &iv[0],
156  &iv[ key_size_ ] );
157 
158  // =-=-=-=-=-=-=-
159  // clean up
160  delete [] iv;
161 
162  return SUCCESS();
163 
164  } // buffer_crypt::initialization_vector
165 
166 // =-=-=-=-=-=-=-
167 // public - encryptor
169  const array_t& _key,
170  const array_t& _iv,
171  const array_t& _in_buf,
172  array_t& _out_buf ) {
173 
174  // =-=-=-=-=-=-=-
175  // create an encryption context
176  auto* context = EVP_CIPHER_CTX_new();
177 
178  auto* algo = EVP_get_cipherbyname( algorithm_.c_str() );
179  if ( !algo ) {
180  rodsLog(
181  LOG_NOTICE,
182  "buffer_crypt::encrypt - algorithm not supported [%s]",
183  algorithm_.c_str() );
184  // default to aes 256 cbc
185  algo = EVP_aes_256_cbc();
186  }
187 
188  int ret = EVP_EncryptInit_ex(
189  context,
190  algo,
191  NULL,
192  &_key[0],
193  &_iv[0] );
194  if ( 0 == ret ) {
195  char err[ 256 ];
196  ERR_error_string_n( ERR_get_error(), err, 256 );
197  std::string msg( "failed in EVP_EncryptInit_ex - " );
198  msg += err;
199  return ERROR( ERR_get_error(), msg );
200  }
201 
202 
203  // =-=-=-=-=-=-=-
204  // max ciphertext len for a n bytes of plaintext is n + AES_BLOCK_SIZE -1 bytes
205  int cipher_len = _in_buf.size() + AES_BLOCK_SIZE;
206  unsigned char* cipher_text = new unsigned char[ cipher_len ] ;
207  // =-=-=-=-=-=-=-
208  // update ciphertext, cipher_len is filled with the length of ciphertext generated,
209  ret = EVP_EncryptUpdate(
210  context,
211  cipher_text,
212  &cipher_len,
213  &_in_buf[0],
214  _in_buf.size() );
215  if ( 0 == ret ) {
216  delete [] cipher_text;
217  char err[ 256 ];
218  ERR_error_string_n( ERR_get_error(), err, 256 );
219  std::string msg( "failed in EVP_EncryptUpdate - " );
220  msg += err;
221  return ERROR( ERR_get_error(), msg );
222  }
223 
224  // =-=-=-=-=-=-=-
225  // update ciphertext with the final remaining bytes
226  int final_len = 0;
227  ret = EVP_EncryptFinal_ex(
228  context,
229  cipher_text + cipher_len,
230  &final_len );
231  if ( 0 == ret ) {
232  delete [] cipher_text;
233  char err[ 256 ];
234  ERR_error_string_n( ERR_get_error(), err, 256 );
235  std::string msg( "failed in EVP_EncryptFinal_ex - " );
236  msg += err;
237  return ERROR( ERR_get_error(), msg );
238  }
239 
240  // =-=-=-=-=-=-=-
241  // clean up and assign out variables before exit
242  _out_buf.resize( cipher_len + final_len );
243 
244  // =-=-=-=-=-=-=-
245  // copy the iv to the out variable
246  _out_buf.assign(
247  &cipher_text[0],
248  &cipher_text[ cipher_len + final_len ] );
249 
250  delete [] cipher_text;
251 
252  EVP_CIPHER_CTX_free( context );
253 
254  return SUCCESS();
255 
256  } // encrypt
257 
258 // =-=-=-=-=-=-=-
259 // public - decryptor
261  const array_t& _key,
262  const array_t& _iv,
263  const array_t& _in_buf,
264  array_t& _out_buf ) {
265  // =-=-=-=-=-=-=-
266  // create an decryption context
267  auto* context = EVP_CIPHER_CTX_new();
268 
269  auto* algo = EVP_get_cipherbyname( algorithm_.c_str() );
270  if ( !algo ) {
271  rodsLog(
272  LOG_NOTICE,
273  "buffer_crypt::decrypt - algorithm not supported [%s]",
274  algorithm_.c_str() );
275  // default to aes 256 cbc
276  algo = EVP_aes_256_cbc();
277  }
278 
279  int ret = EVP_DecryptInit_ex(
280  context,
281  algo,
282  NULL,
283  &_key[0],
284  &_iv [0] );
285  if ( 0 == ret ) {
286  char err[ 256 ];
287  ERR_error_string_n( ERR_get_error(), err, 256 );
288  std::string msg( "failed in EVP_DecryptInit_ex - " );
289  msg += err;
290  return ERROR( ERR_get_error(), msg );
291  }
292 
293  // =-=-=-=-=-=-=-
294  // allocate a plain text buffer
295  // because we have padding ON, we must allocate an extra cipher block size of memory
296  int plain_len = 0;
297  auto plain_text = std::make_unique<unsigned char[]>(_in_buf.size() + AES_BLOCK_SIZE);
298 
299  // =-=-=-=-=-=-=-
300  // update the plain text, plain_len is filled with the length of the plain text
301  ret = EVP_DecryptUpdate(
302  context,
303  plain_text.get(),
304  &plain_len,
305  &_in_buf[0],
306  _in_buf.size() );
307  if ( 0 == ret ) {
308  char err[ 256 ];
309  ERR_error_string_n( ERR_get_error(), err, 256 );
310  std::string msg( "failed in EVP_DecryptUpdate - " );
311  msg += err;
312  return ERROR( ERR_get_error(), msg );
313  }
314 
315  // =-=-=-=-=-=-=-
316  // finalize the plain text, final_len is filled with the resulting length of the plain text
317  int final_len = 0;
318  ret = EVP_DecryptFinal_ex(
319  context,
320  plain_text.get() + plain_len,
321  &final_len );
322  if ( 0 == ret ) {
323  char err[ 256 ];
324  ERR_error_string_n( ERR_get_error(), err, 256 );
325  std::string msg( "failed in EVP_DecryptFinal_ex - " );
326  msg += err;
327  return ERROR( ERR_get_error(), msg );
328  }
329 
330  // =-=-=-=-=-=-=-
331  // assign the plain text to the outvariable and clean up
332  _out_buf.resize( plain_len + final_len );
333 
334  // =-=-=-=-=-=-=-
335  // copy the iv to the out variable
336  _out_buf.assign(
337  plain_text.get(),
338  plain_text.get() + plain_len + final_len );
339 
340  EVP_CIPHER_CTX_free( context );
341 
342  return SUCCESS();
343 
344  } // decrypt
345 
346 }; // namespace irods
rodsLog
void rodsLog(int level, const char *formatStr,...)
Definition: rodsLog.cpp:86
NULL
#define NULL
Definition: rodsDef.h:70
irods::buffer_crypt::decrypt
irods::error decrypt(const array_t &, const array_t &, const array_t &, array_t &)
Definition: irods_buffer_encryption.cpp:260
irods::buffer_crypt::array_t
std::vector< unsigned char > array_t
Definition: irods_buffer_encryption.hpp:30
irods::transform
void transform(const InputC &ic, OutputC &oc, UnaryOperation func)
Definition: irods_re_plugin.hpp:822
SUCCESS
#define SUCCESS()
Definition: irods_error.hpp:121
irods::global_evp_lifetime_mgr_
static const evp_lifetime_mgr global_evp_lifetime_mgr_
Definition: irods_buffer_encryption.cpp:28
irods_buffer_encryption.hpp
irods::evp_lifetime_mgr::~evp_lifetime_mgr
~evp_lifetime_mgr()
Definition: irods_buffer_encryption.cpp:24
irods
Definition: apiHandler.hpp:35
irods::buffer_crypt::num_hash_rounds_
int num_hash_rounds_
Definition: irods_buffer_encryption.hpp:97
irods::evp_lifetime_mgr
Definition: irods_buffer_encryption.cpp:18
irods::buffer_crypt::buffer_crypt
buffer_crypt()
Definition: irods_buffer_encryption.cpp:49
irods::buffer_crypt::algorithm_
std::string algorithm_
Definition: irods_buffer_encryption.hpp:98
irods::buffer_crypt::initialization_vector
irods::error initialization_vector(array_t &)
Definition: irods_buffer_encryption.cpp:134
irods::buffer_crypt::encrypt
irods::error encrypt(const array_t &, const array_t &, const array_t &, array_t &)
Definition: irods_buffer_encryption.cpp:168
LOG_NOTICE
#define LOG_NOTICE
Definition: rodsLog.h:33
ERROR
#define ERROR(code_, message_)
Definition: irods_error.hpp:117
irods::error
Definition: irods_error.hpp:23
int
typedef int((*funcPtr)())
irods::buffer_crypt::generate_key
static irods::error generate_key(array_t &, int)
Definition: irods_buffer_encryption.cpp:98
irods::buffer_crypt::hex_encode
static irods::error hex_encode(const array_t &, std::string &)
Definition: irods_buffer_encryption.cpp:119
irods::buffer_crypt::gen_hash
static std::string gen_hash(unsigned char *, int)
Definition: irods_buffer_encryption.cpp:30
irods::evp_lifetime_mgr::evp_lifetime_mgr
evp_lifetime_mgr()
Definition: irods_buffer_encryption.cpp:20
irods::buffer_crypt::~buffer_crypt
~buffer_crypt()
Definition: irods_buffer_encryption.cpp:93
irods::buffer_crypt::key_size_
int key_size_
Definition: irods_buffer_encryption.hpp:95
irods::buffer_crypt::salt_size_
int salt_size_
Definition: irods_buffer_encryption.hpp:96
irods_log.hpp