BitShares-Core  7.0.2
BitShares blockchain node software and command-line wallet software
aes.cpp
Go to the documentation of this file.
1 #include <fc/crypto/aes.hpp>
2 #include <fc/crypto/openssl.hpp>
4 #include <fc/fwd_impl.hpp>
5 
6 #include <fc/io/fstream.hpp>
7 
8 #include <fc/log/logger.hpp>
9 
10 #include <fc/thread/thread.hpp>
11 #include <fc/io/raw.hpp>
12 #include <boost/endian/buffers.hpp>
13 #include <boost/thread/mutex.hpp>
14 #include <openssl/opensslconf.h>
15 #ifndef OPENSSL_THREADS
16 # error "OpenSSL must be configured to support threads"
17 #endif
18 #include <openssl/crypto.h>
19 
20 #if defined(_WIN32)
21 # include <windows.h>
22 #endif
23 
24 namespace fc {
25 
27 {
28  evp_cipher_ctx ctx;
29 };
30 
32 {
33  static int init = init_openssl();
34  (void)init;
35 }
36 
38 {
39 }
40 
41 void aes_encoder::init( const fc::sha256& key, const uint128_t& init_value )
42 {
43  my->ctx.obj = EVP_CIPHER_CTX_new();
44  /* Create and initialise the context */
45  if(!my->ctx)
46  {
47  FC_THROW_EXCEPTION( aes_exception, "error allocating evp cipher context",
48  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
49  }
50 
51  /* Initialise the encryption operation. IMPORTANT - ensure you use a key
52  * and IV size appropriate for your cipher
53  * In this example we are using 256 bit AES (i.e. a 256 bit key). The
54  * IV size for *most* modes is the same as the block size. For AES this
55  * is 128 bits */
56  boost::endian::little_uint64_buf_t iv[2];
57  iv[0] = uint128_hi64( init_value );
58  iv[1] = uint128_lo64( init_value );
59  if(1 != EVP_EncryptInit_ex(my->ctx, EVP_aes_256_cbc(), NULL, (unsigned char*)&key, (const unsigned char*)iv[0].data()))
60  {
61  FC_THROW_EXCEPTION( aes_exception, "error during aes 256 cbc encryption init",
62  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
63  }
64  EVP_CIPHER_CTX_set_padding( my->ctx, 0 );
65 }
66 
67 uint32_t aes_encoder::encode( const char* plaintxt, uint32_t plaintext_len, char* ciphertxt )
68 {
69  int ciphertext_len = 0;
70  /* Provide the message to be encrypted, and obtain the encrypted output.
71  * * EVP_EncryptUpdate can be called multiple times if necessary
72  * */
73  if(1 != EVP_EncryptUpdate(my->ctx, (unsigned char*)ciphertxt, &ciphertext_len, (const unsigned char*)plaintxt, plaintext_len))
74  {
75  FC_THROW_EXCEPTION( aes_exception, "error during aes 256 cbc encryption update",
76  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
77  }
78  FC_ASSERT( (uint32_t) ciphertext_len == plaintext_len, "", ("ciphertext_len",ciphertext_len)("plaintext_len",plaintext_len) );
79  return ciphertext_len;
80 }
81 #if 0
82 uint32_t aes_encoder::final_encode( char* ciphertxt )
83 {
84  int ciphertext_len = 0;
85  /* Finalise the encryption. Further ciphertext bytes may be written at
86  * * this stage.
87  * */
88  if(1 != EVP_EncryptFinal_ex(my->ctx, (unsigned char*)ciphertxt, &ciphertext_len))
89  {
90  FC_THROW_EXCEPTION( exception, "error during aes 256 cbc encryption final",
91  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
92  }
93  return ciphertext_len;
94 }
95 #endif
96 
97 
99 {
100  evp_cipher_ctx ctx;
101 };
102 
104 {
105  static int init = init_openssl();
106  (void)init;
107 }
108 
109 void aes_decoder::init( const fc::sha256& key, const uint128_t& init_value )
110 {
111  my->ctx.obj = EVP_CIPHER_CTX_new();
112  /* Create and initialise the context */
113  if(!my->ctx)
114  {
115  FC_THROW_EXCEPTION( aes_exception, "error allocating evp cipher context",
116  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
117  }
118 
119  /* Initialise the encryption operation. IMPORTANT - ensure you use a key
120  * and IV size appropriate for your cipher
121  * In this example we are using 256 bit AES (i.e. a 256 bit key). The
122  * IV size for *most* modes is the same as the block size. For AES this
123  * is 128 bits */
124  boost::endian::little_uint64_buf_t iv[2];
125  iv[0] = uint128_hi64( init_value );
126  iv[1] = uint128_lo64( init_value );
127  if(1 != EVP_DecryptInit_ex(my->ctx, EVP_aes_256_cbc(), NULL, (unsigned char*)&key, (const unsigned char*)iv[0].data()))
128  {
129  FC_THROW_EXCEPTION( aes_exception, "error during aes 256 cbc encryption init",
130  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
131  }
132  EVP_CIPHER_CTX_set_padding( my->ctx, 0 );
133 }
135 {
136 }
137 
138 uint32_t aes_decoder::decode( const char* ciphertxt, uint32_t ciphertxt_len, char* plaintext )
139 {
140  int plaintext_len = 0;
141  /* Provide the message to be decrypted, and obtain the decrypted output.
142  * * EVP_DecryptUpdate can be called multiple times if necessary
143  * */
144  if (1 != EVP_DecryptUpdate(my->ctx, (unsigned char*)plaintext, &plaintext_len, (const unsigned char*)ciphertxt, ciphertxt_len))
145  {
146  FC_THROW_EXCEPTION( aes_exception, "error during aes 256 cbc decryption update",
147  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
148  }
149  FC_ASSERT( ciphertxt_len == (uint32_t)plaintext_len, "", ("ciphertxt_len",ciphertxt_len)("plaintext_len",plaintext_len) );
150  return plaintext_len;
151 }
152 #if 0
153 uint32_t aes_decoder::final_decode( char* plaintext )
154 {
155  return 0;
156  int ciphertext_len = 0;
157  /* Finalise the encryption. Further ciphertext bytes may be written at
158  * * this stage.
159  * */
160  if(1 != EVP_DecryptFinal_ex(my->ctx, (unsigned char*)plaintext, &ciphertext_len))
161  {
162  FC_THROW_EXCEPTION( exception, "error during aes 256 cbc encryption final",
163  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
164  }
165  return ciphertext_len;
166 }
167 #endif
168 
169 
170 
171 
172 
173 
174 
175 
176 
177 
178 
179 
181 unsigned aes_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
182  unsigned char *iv, unsigned char *ciphertext)
183 {
184  evp_cipher_ctx ctx( EVP_CIPHER_CTX_new() );
185 
186  int len = 0;
187  unsigned ciphertext_len = 0;
188 
189  /* Create and initialise the context */
190  if(!ctx)
191  {
192  FC_THROW_EXCEPTION( aes_exception, "error allocating evp cipher context",
193  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
194  }
195 
196  /* Initialise the encryption operation. IMPORTANT - ensure you use a key
197  * and IV size appropriate for your cipher
198  * In this example we are using 256 bit AES (i.e. a 256 bit key). The
199  * IV size for *most* modes is the same as the block size. For AES this
200  * is 128 bits */
201  if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
202  {
203  FC_THROW_EXCEPTION( aes_exception, "error during aes 256 cbc encryption init",
204  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
205  }
206 
207  /* Provide the message to be encrypted, and obtain the encrypted output.
208  * * EVP_EncryptUpdate can be called multiple times if necessary
209  * */
210  if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
211  {
212  FC_THROW_EXCEPTION( aes_exception, "error during aes 256 cbc encryption update",
213  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
214  }
215  ciphertext_len = len;
216 
217  /* Finalise the encryption. Further ciphertext bytes may be written at
218  * * this stage.
219  * */
220  if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
221  {
222  FC_THROW_EXCEPTION( aes_exception, "error during aes 256 cbc encryption final",
223  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
224  }
225  ciphertext_len += len;
226 
227  return ciphertext_len;
228 }
229 
230 unsigned aes_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
231  unsigned char *iv, unsigned char *plaintext)
232 {
233  evp_cipher_ctx ctx( EVP_CIPHER_CTX_new() );
234  int len = 0;
235  unsigned plaintext_len = 0;
236 
237  /* Create and initialise the context */
238  if(!ctx)
239  {
240  FC_THROW_EXCEPTION( aes_exception, "error allocating evp cipher context",
241  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
242  }
243 
244  /* Initialise the decryption operation. IMPORTANT - ensure you use a key
245  * * and IV size appropriate for your cipher
246  * * In this example we are using 256 bit AES (i.e. a 256 bit key). The
247  * * IV size for *most* modes is the same as the block size. For AES this
248  * * is 128 bits */
249  if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
250  {
251  FC_THROW_EXCEPTION( aes_exception, "error during aes 256 cbc decrypt init",
252  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
253  }
254 
255  /* Provide the message to be decrypted, and obtain the plaintext output.
256  * * EVP_DecryptUpdate can be called multiple times if necessary
257  * */
258  if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
259  {
260  FC_THROW_EXCEPTION( aes_exception, "error during aes 256 cbc decrypt update",
261  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
262  }
263 
264  plaintext_len = len;
265 
266  /* Finalise the decryption. Further plaintext bytes may be written at
267  * * this stage.
268  * */
269  if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
270  {
271  FC_THROW_EXCEPTION( aes_exception, "error during aes 256 cbc decrypt final",
272  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
273  }
274  plaintext_len += len;
275 
276  return plaintext_len;
277 }
278 
279 unsigned aes_cfb_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
280  unsigned char *iv, unsigned char *plaintext)
281 {
282  evp_cipher_ctx ctx( EVP_CIPHER_CTX_new() );
283  int len = 0;
284  unsigned plaintext_len = 0;
285 
286  /* Create and initialise the context */
287  if(!ctx)
288  {
289  FC_THROW_EXCEPTION( aes_exception, "error allocating evp cipher context",
290  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
291  }
292 
293  /* Initialise the decryption operation. IMPORTANT - ensure you use a key
294  * * and IV size appropriate for your cipher
295  * * In this example we are using 256 bit AES (i.e. a 256 bit key). The
296  * * IV size for *most* modes is the same as the block size. For AES this
297  * * is 128 bits */
298  if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cfb128(), NULL, key, iv))
299  {
300  FC_THROW_EXCEPTION( aes_exception, "error during aes 256 cbc decrypt init",
301  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
302  }
303 
304  /* Provide the message to be decrypted, and obtain the plaintext output.
305  * * EVP_DecryptUpdate can be called multiple times if necessary
306  * */
307  if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
308  {
309  FC_THROW_EXCEPTION( aes_exception, "error during aes 256 cbc decrypt update",
310  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
311  }
312 
313  plaintext_len = len;
314 
315  /* Finalise the decryption. Further plaintext bytes may be written at
316  * * this stage.
317  * */
318  if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
319  {
320  FC_THROW_EXCEPTION( aes_exception, "error during aes 256 cbc decrypt final",
321  ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
322  }
323  plaintext_len += len;
324 
325  return plaintext_len;
326 }
327 
328 std::vector<char> aes_encrypt( const fc::sha512& key, const std::vector<char>& plain_text )
329 {
330  std::vector<char> cipher_text(plain_text.size()+16);
331  auto cipher_len = aes_encrypt( (unsigned char*)plain_text.data(), (int)plain_text.size(),
332  (unsigned char*)&key, ((unsigned char*)&key)+32,
333  (unsigned char*)cipher_text.data() );
334  FC_ASSERT( cipher_len <= cipher_text.size() );
335  cipher_text.resize(cipher_len);
336  return cipher_text;
337 
338 }
339 std::vector<char> aes_decrypt( const fc::sha512& key, const std::vector<char>& cipher_text )
340 {
341  std::vector<char> plain_text( cipher_text.size() );
342  auto plain_len = aes_decrypt( (unsigned char*)cipher_text.data(), (int)cipher_text.size(),
343  (unsigned char*)&key, ((unsigned char*)&key)+32,
344  (unsigned char*)plain_text.data() );
345  plain_text.resize(plain_len);
346  return plain_text;
347 }
348 
349 
353 void aes_save( const fc::path& file, const fc::sha512& key, std::vector<char> plain_text )
354 { try {
355  auto cipher = aes_encrypt( key, plain_text );
356  fc::sha512::encoder check_enc;
357  fc::raw::pack( check_enc, key );
358  fc::raw::pack( check_enc, cipher );
359  auto check = check_enc.result();
360 
361  fc::ofstream out(file);
362  fc::raw::pack( out, check );
363  fc::raw::pack( out, cipher );
364 } FC_RETHROW_EXCEPTIONS( warn, "", ("file",file) ) }
365 
369 std::vector<char> aes_load( const fc::path& file, const fc::sha512& key )
370 { try {
371  FC_ASSERT( fc::exists( file ) );
372 
374  fc::sha512 check;
375  std::vector<char> cipher;
376 
377  fc::raw::unpack( in, check );
378  fc::raw::unpack( in, cipher );
379 
380  fc::sha512::encoder check_enc;
381  fc::raw::pack( check_enc, key );
382  fc::raw::pack( check_enc, cipher );
383 
384  FC_ASSERT( check_enc.result() == check );
385 
386  return aes_decrypt( key, cipher );
387 } FC_RETHROW_EXCEPTIONS( warn, "", ("file",file) ) }
388 
389 /* This stuff has to go somewhere, I guess this is as good a place as any...
390  OpenSSL isn't thread-safe unless you give it access to some mutexes,
391  so the CRYPTO_set_id_callback() function needs to be called before there's any
392  chance of OpenSSL being accessed from multiple threads.
393 */
395 {
396  static boost::mutex* openssl_mutexes;
397  static unsigned long get_thread_id();
398  static void locking_callback(int mode, int type, const char *file, int line);
401 };
403 
404 boost::mutex* openssl_thread_config::openssl_mutexes = nullptr;
405 
407 {
408 #ifdef _WIN32
409  return (unsigned long)::GetCurrentThreadId();
410 #else
411  return (unsigned long)(&fc::thread::current()); // TODO: should expose boost thread id
412 #endif
413 }
414 
415 void openssl_thread_config::locking_callback(int mode, int type, const char *file, int line)
416 {
417  if (mode & CRYPTO_LOCK)
418  openssl_mutexes[type].lock();
419  else
420  openssl_mutexes[type].unlock();
421 }
422 
423 // Warning: Things get complicated if third-party libraries also try to install their their own
424 // OpenSSL thread functions. Right now, we don't install our own handlers if another library has
425 // installed them before us which is a partial solution, but you'd really need to evaluate
426 // each library that does this to make sure they will play nice.
428 {
429  if (CRYPTO_get_id_callback() == NULL &&
430  CRYPTO_get_locking_callback() == NULL)
431  {
432  openssl_mutexes = new boost::mutex[CRYPTO_num_locks()];
433  CRYPTO_set_id_callback(&get_thread_id);
434  CRYPTO_set_locking_callback(&locking_callback);
435  }
436 }
438 {
439  if (CRYPTO_get_id_callback() == &get_thread_id)
440  {
441  CRYPTO_set_id_callback(NULL);
442  CRYPTO_set_locking_callback(NULL);
443  delete[] openssl_mutexes;
444  openssl_mutexes = nullptr;
445  }
446 }
447 
448 } // namespace fc
fc::thread::current
static thread & current()
Definition: thread.cpp:125
fc::aes_decoder::aes_decoder
aes_decoder()
Definition: aes.cpp:103
fc::aes_decoder::decode
uint32_t decode(const char *ciphertxt, uint32_t len, char *plaintext)
Definition: aes.cpp:138
fc::exception
Used to generate a useful error report when an exception is thrown.
Definition: exception.hpp:56
fc::openssl_thread_config
Definition: aes.cpp:394
fc::aes_encoder::impl
Definition: aes.cpp:26
fc::openssl_thread_config::openssl_thread_config
openssl_thread_config()
Definition: aes.cpp:427
fc::raw::unpack
void unpack(Stream &s, flat_set< T, A... > &value, uint32_t _max_depth)
Definition: flat.hpp:23
fc::aes_load
std::vector< char > aes_load(const fc::path &file, const fc::sha512 &key)
Definition: aes.cpp:369
openssl.hpp
fc::aes_decoder::~aes_decoder
~aes_decoder()
Definition: aes.cpp:134
fc
Definition: api.hpp:15
fc::ifstream::binary
@ binary
Definition: fstream.hpp:29
fc::aes_decoder::impl
Definition: aes.cpp:98
fc::uint128_hi64
uint64_t uint128_hi64(const uint128_t &x)
Definition: uint128.hpp:57
fc::sha256
Definition: sha256.hpp:10
fc::sha512::encoder
Definition: sha512.hpp:32
fc::aes_encoder::aes_encoder
aes_encoder()
Definition: aes.cpp:31
fc::ifstream
Definition: fstream.hpp:27
fc::sha512
Definition: sha512.hpp:9
fc::aes_encoder::impl::ctx
evp_cipher_ctx ctx
Definition: aes.cpp:28
fc::path
wraps boost::filesystem::path to provide platform independent path manipulation.
Definition: filesystem.hpp:28
fc::sha512::data
char * data() const
Definition: sha512.cpp:22
thread.hpp
fc::uint128_lo64
uint64_t uint128_lo64(const uint128_t &x)
Definition: uint128.hpp:54
fc::aes_save
void aes_save(const fc::path &file, const fc::sha512 &key, std::vector< char > plain_text)
Definition: aes.cpp:353
graphene::elasticsearch::mode
mode
Definition: elasticsearch_plugin.hpp:53
FC_ASSERT
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
fc::ofstream
Definition: fstream.hpp:9
fc::openssl_thread_config::get_thread_id
static unsigned long get_thread_id()
Definition: aes.cpp:406
fc::aes_decoder::init
void init(const fc::sha256 &key, const uint128_t &init_value)
Definition: aes.cpp:109
fc::openssl_thread_config::locking_callback
static void locking_callback(int mode, int type, const char *file, int line)
Definition: aes.cpp:415
exception.hpp
Defines exception's used by fc.
fc::init_openssl
int init_openssl()
Definition: openssl.cpp:63
FC_RETHROW_EXCEPTIONS
#define FC_RETHROW_EXCEPTIONS(LOG_LEVEL, FORMAT,...)
Catchs all exception's, std::exceptions, and ... and rethrows them after appending the provided log m...
Definition: exception.hpp:464
logger.hpp
fc::aes_encoder::encode
uint32_t encode(const char *plaintxt, uint32_t len, char *ciphertxt)
Definition: aes.cpp:67
fc::openssl_thread_config::openssl_mutexes
static boost::mutex * openssl_mutexes
Definition: aes.cpp:396
fstream.hpp
fc::openssl_thread_config_manager
openssl_thread_config openssl_thread_config_manager
Definition: aes.cpp:402
fc::sha512::encoder::result
sha512 result()
Definition: sha512.cpp:46
aes.hpp
fc::aes_encoder::~aes_encoder
~aes_encoder()
Definition: aes.cpp:37
FC_THROW_EXCEPTION
#define FC_THROW_EXCEPTION(EXCEPTION, FORMAT,...)
Definition: exception.hpp:379
fc::aes_cfb_decrypt
unsigned aes_cfb_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext)
Definition: aes.cpp:279
fc::aes_encoder::init
void init(const fc::sha256 &key, const uint128_t &init_value)
Definition: aes.cpp:41
fc::aes_decoder::impl::ctx
evp_cipher_ctx ctx
Definition: aes.cpp:100
fwd_impl.hpp
fc::aes_decrypt
unsigned aes_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext)
Definition: aes.cpp:230
fc::openssl_thread_config::~openssl_thread_config
~openssl_thread_config()
Definition: aes.cpp:437
fc::exists
bool exists(const path &p)
Definition: filesystem.cpp:209
fc::aes_encrypt
unsigned aes_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext)
Definition: aes.cpp:181
fc::raw::pack
void pack(Stream &s, const flat_set< T, A... > &value, uint32_t _max_depth)
Definition: flat.hpp:11
raw.hpp