0.9.8.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Crypto.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007-2015 Hypertable, Inc.
3  *
4  * This file is part of Hypertable.
5  *
6  * Hypertable is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; version 3
9  * of the License.
10  *
11  * Hypertable is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301, USA.
20  */
21 
26 
27 #include <Common/Compat.h>
28 
29 #include "Crypto.h"
30 
31 #include <Common/Logger.h>
32 #include <Common/Serialization.h>
33 
34 extern "C" {
35 #include <openssl/pem.h>
36 #include <openssl/ssl.h>
37 #include <openssl/rsa.h>
38 #include <openssl/evp.h>
39 #include <openssl/bio.h>
40 #include <openssl/err.h>
41 }
42 
43 using namespace Hypertable;
44 
45 #pragma clang diagnostic push
46 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
47 
48 namespace {
49 
50  RSA *create_rsa(unsigned char *key, bool is_public) {
51  RSA *rsa {};
52  BIO *keybio = BIO_new_mem_buf(key, -1);
53 
54  HT_ASSERT(keybio);
55 
56  if (is_public)
57  rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa, NULL, NULL);
58  else
59  rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
60 
61  return rsa;
62  }
63 
64 }
65 
66 const string Crypto::rsa_encrypt(const char *public_key, const string &message) {
67  char error_buf[256];
68  EVP_PKEY *evpPubKey {};
69 
70  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
71 
72  BIO *bio = BIO_new_mem_buf((void *)public_key, -1);
73 
74  PEM_read_bio_PUBKEY(bio, &evpPubKey, NULL, NULL);
75 
76  BIO_free_all(bio);
77 
78  size_t encMsgLen = 0;
79  int blockLen = 0;
80 
81  unsigned char *iv = new unsigned char [EVP_MAX_IV_LENGTH];
82  int ek_len;
83  unsigned char *ek[1];
84  ek[0] = new unsigned char [EVP_PKEY_size(evpPubKey)];
85 
86  unsigned char *encMsg = new unsigned char [message.length() + EVP_MAX_IV_LENGTH];
87 
88  if (!EVP_SealInit(ctx, EVP_aes_256_cbc(), ek, &ek_len, iv, &evpPubKey, 1)) {
89  ERR_load_crypto_strings();
90  HT_FATALF("EVP_SealInit() - %s", ERR_error_string(ERR_get_error(), error_buf));
91  }
92 
93  if (!EVP_SealUpdate(ctx, encMsg + encMsgLen, &blockLen, (const unsigned char*)message.c_str(), (int)message.length())) {
94  ERR_load_crypto_strings();
95  HT_FATALF("EVP_SealUpdate() - %s", ERR_error_string(ERR_get_error(), error_buf));
96  }
97  encMsgLen += blockLen;
98 
99  if(!EVP_SealFinal(ctx, encMsg + encMsgLen, &blockLen)) {
100  ERR_load_crypto_strings();
101  HT_FATALF("EVP_SealFinal() - %s", ERR_error_string(ERR_get_error(), error_buf));
102  }
103  encMsgLen += blockLen;
104 
105  string encrypted_message;
106  encrypted_message.reserve(2 + ek_len + EVP_MAX_IV_LENGTH + encMsgLen + 1);
107  uint8_t buf[2];
108  uint8_t *ptr = buf;
109  Serialization::encode_i16(&ptr, (uint16_t)ek_len);
110  encrypted_message.append((const char *)buf, 2);
111  encrypted_message.append((const char *)ek[0], ek_len);
112  encrypted_message.append((const char *)iv, EVP_MAX_IV_LENGTH);
113  encrypted_message.append((const char *)encMsg, encMsgLen);
114 
115  delete [] iv;
116  delete [] ek[0];
117  delete [] encMsg;
118  EVP_CIPHER_CTX_free(ctx);
119 
120  return encrypted_message;
121 }
122 
123 const string Crypto::rsa_decrypt(const char *private_key, const string &message) {
124  char error_buf[256];
125  EVP_PKEY *evpPriKey {};
126  EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
127 
128  BIO *bio = BIO_new_mem_buf((void *)private_key, -1);
129 
130  PEM_read_bio_PrivateKey(bio, &evpPriKey, nullptr, nullptr);
131 
132  BIO_free_all(bio);
133 
134  unsigned char *ek {};
135  int ek_len {};
136  unsigned char *iv {};
137  unsigned char *ciphertext {};
138  int ciphertext_len {};
139 
140  const uint8_t *buf = (const uint8_t *)message.c_str();
141  size_t remain = message.length();
142  ek_len = Serialization::decode_i16(&buf, &remain);
143 
144  ek = (unsigned char *)buf;
145  buf += ek_len;
146  remain -= ek_len;
147 
148  iv = (unsigned char *)buf;
149  buf += EVP_MAX_IV_LENGTH;
150  remain -= EVP_MAX_IV_LENGTH;
151 
152  ciphertext = (unsigned char *)buf;
153  ciphertext_len = (int)remain;
154 
155  if (EVP_OpenInit(ctx, EVP_aes_256_cbc(), ek, ek_len, iv, evpPriKey) != 1) {
156  ERR_load_crypto_strings();
157  HT_FATALF("EVP_OpenInit() - %s", ERR_error_string(ERR_get_error(), error_buf));
158  }
159 
160  int len {};
161  int plaintext_len {};
162  unsigned char *plaintext = new unsigned char [ message.length() ];
163  if (EVP_OpenUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len) != 1) {
164  ERR_load_crypto_strings();
165  HT_FATALF("EVP_OpenUpdate() - %s", ERR_error_string(ERR_get_error(), error_buf));
166  }
167  plaintext_len = len;
168 
169  if (EVP_OpenFinal(ctx, plaintext + len, &len) != 1) {
170  ERR_load_crypto_strings();
171  HT_FATALF("EVP_OpenFinal() - %s", ERR_error_string(ERR_get_error(), error_buf));
172  }
173  plaintext_len += len;
174 
175  HT_ASSERT(plaintext_len <= (int)message.length());
176 
177  string decrypted_message;
178  decrypted_message.reserve(plaintext_len+1);
179  decrypted_message.append((const char *)plaintext, plaintext_len);
180 
181  delete [] plaintext;
182  EVP_CIPHER_CTX_free(ctx);
183 
184  return decrypted_message;
185 }
186 
187 
188 const string Crypto::rsa_signature_encrypt(const char *key, bool key_is_public,
189  const string &message) {
190  RSA *rsa = create_rsa((unsigned char *)key, key_is_public ? 1 : 0);
191  HT_ASSERT(rsa);
192  int buf_len = message.length() + RSA_size(rsa);
193  unsigned char *buf = new unsigned char [ buf_len ];
194  int len;
195  if (key_is_public)
196  len = RSA_public_encrypt(message.length(), (const unsigned char *)message.c_str(), buf, rsa, RSA_PKCS1_PADDING);
197  else
198  len = RSA_private_encrypt(message.length(), (const unsigned char *)message.c_str(), buf, rsa, RSA_PKCS1_PADDING);
199  HT_ASSERT(len < buf_len);
200  if (len < 0) {
201  char ebuf[256];
202  ERR_load_crypto_strings();
203  HT_FATALF("RSA_public_encrypt() - %s", ERR_error_string(ERR_get_error(), ebuf));
204  }
205  string encrypted_message;
206  encrypted_message.reserve(len+1);
207  encrypted_message.append((const char *)buf, len);
208  free(rsa);
209  delete [] buf;
210  return encrypted_message;
211 }
212 
213 const string Crypto::rsa_signature_decrypt(const char *key, bool key_is_public,
214  const string &signature) {
215  RSA *rsa = create_rsa((unsigned char *)key, key_is_public ? 1 : 0);
216  HT_ASSERT(rsa);
217  int buf_len = signature.length() + RSA_size(rsa);
218  unsigned char *buf = new unsigned char [ buf_len ];
219  int len;
220  if (key_is_public)
221  len = RSA_public_decrypt(signature.length(),
222  (const unsigned char *)signature.c_str(),
223  buf, rsa, RSA_PKCS1_PADDING);
224  else
225  len = RSA_private_decrypt(signature.length(),
226  (const unsigned char *)signature.c_str(),
227  buf, rsa, RSA_PKCS1_PADDING);
228  HT_ASSERT(len < buf_len);
229  if (len < 0) {
230  char ebuf[256];
231  ERR_load_crypto_strings();
232  HT_FATALF("RSA_public_decrypt() - %s", ERR_error_string(ERR_get_error(), ebuf));
233  }
234  string decrypted_message;
235  decrypted_message.reserve(len+1);
236  decrypted_message.append((const char *)buf, len);
237  free(rsa);
238  delete [] buf;
239  return decrypted_message;
240 }
241 
242 #pragma clang diagnostic pop
static const string rsa_decrypt(const char *private_key, const string &message)
Decrypts a message with RSA algorithm.
Definition: Crypto.cc:123
static const string rsa_signature_encrypt(const char *key, bool key_is_public, const string &message)
Computes RSA signature for message.
Definition: Crypto.cc:188
Declarations for Crypto.
#define HT_ASSERT(_e_)
Definition: Logger.h:396
static const string rsa_encrypt(const char *public_key, const string &message)
Encrypts a message with RSA algorithm.
Definition: Crypto.cc:66
uint16_t decode_i16(const uint8_t **bufp, size_t *remainp)
Decode a 16-bit integer in little-endian order.
Logging routines and macros.
Compatibility Macros for C/C++.
static const string rsa_signature_decrypt(const char *key, bool key_is_public, const string &signature)
Recovers message from RSA signature.
Definition: Crypto.cc:213
void encode_i16(uint8_t **bufp, uint16_t val)
Encode a 16-bit integer in little-endian order.
Functions to serialize/deserialize primitives to/from a memory buffer.
Hypertable definitions
#define HT_FATALF(msg,...)
Definition: Logger.h:343