libutil++  1.9.3
 All Classes Functions Variables
Crypt.cpp
1 /*
2 ** libutil++
3 ** $Id: Crypt.cpp 1653 2016-02-28 19:54:59Z sella $
4 ** Copyright (c) 2011-2016 Digital Genesis, LLC. All Rights Reserved.
5 ** Released under the LGPL Version 2.1 License.
6 ** http://www.digitalgenesis.com
7 */
8 
9 static const char rcsid[] __attribute__((used)) = "$Id: Crypt.cpp 1653 2016-02-28 19:54:59Z sella $";
10 
11 #include "Crypt.h"
12 #include "CommonMacro.h"
13 #include "Time.h"
14 #include "../Exception.h"
15 
16 #ifndef SKIP_CRYPT
17 
18 #include <mhash.h>
19 #include <mutils/mhash.h>
20 #include <string.h>
21 #include <stdlib.h>
22 
23 //#define DUMP
24 
25 using namespace sella::util;
26 
27 Crypt::Crypt(const char *algo, const char *mode, int keylen, uint32_t seed) : init(false), password(NULL), salt(NULL), key(NULL), iv(NULL), algo(algo), mode(mode) {
28  td = mcrypt_module_open((char*) algo, NULL, (char*) mode, NULL);
29 
30  if (mcrypt_enc_is_block_algorithm(td) == 1 && mcrypt_enc_is_block_mode(td) == 1) {
31  THROW(Exception, "Crypt does not support block algorithm or block modes");
32  }
33 
34  setKeyLen(keylen);
35 
36  if (seed == 0) {
37  setFlipSeed((uint32_t) Time::gettimeofday_usec());
38  } else {
39  setFlipSeed(seed);
40  }
41 
42  setPassword(CRYPT_PASSWORD_DEF, CRYPT_SALT_DEF);
43 }
44 
45 Crypt::Crypt(const Crypt &other) :
46  init(false),
47  seed(other.seed),
48  password(strdup(other.password)),
49  salt(strdup(other.salt)),
50  key((unsigned char *)malloc(other.keylen)),
51  iv(NULL),
52  keylen(other.keylen),
53  algo(other.algo),
54  mode(other.mode)
55 {
56  memcpy(this->key, other.key, this->keylen);
57 
58  this->td = mcrypt_module_open((char*) this->algo.c_str(), NULL, (char*) this->mode.c_str(), NULL);
59 }
60 
61 Crypt::~Crypt() {
62  clear();
63 
64  mcrypt_module_close(td);
65 }
66 
67 Crypt& Crypt::operator=(const Crypt &other) throw () {
68  if (this != &other) {
69  clear();
70 
71  this->init = false;
72  this->seed = other.seed;
73  this->password = strdup(other.password);
74  this->salt = strdup(other.salt);
75  this->iv = NULL;
76  this->keylen = other.keylen;
77  this->algo = other.algo;
78  this->mode = other.mode;
79 
80  key = (unsigned char *)malloc(this->keylen);
81  memcpy(this->key, other.key, this->keylen);
82 
83  this->td = mcrypt_module_open((char*) this->algo.c_str(), NULL, (char*) this->mode.c_str(), NULL);
84  }
85 
86  return *this;
87 }
88 
89 void Crypt::clear(void) {
90  int iv_size = mcrypt_enc_get_iv_size(td);
91 
92  deinitialize();
93 
94  /* Scrub from memory before release */
95  if (this->iv) {
96  memset(this->iv, 0, iv_size);
97  SAFE_FREE(this->iv);
98  }
99 
100  if (this->key) {
101  memset(this->key, 0, this->keylen);
102  SAFE_FREE(this->key);
103  }
104 
105  if (this->salt) {
106  memset(this->salt, 0, strlen(this->salt));
107  SAFE_FREE(this->salt);
108  }
109 
110  if (this->password) {
111  memset(this->password, 0, strlen(this->password));
112  SAFE_FREE(this->password);
113  }
114 }
115 
116 void Crypt::setSeed(uint32_t seed) {
117  this->seed = seed;
118 
119  /* Seed change invalidates iv */
120  if (this->iv) { /* Scrub from memory before release */
121  int iv_size = mcrypt_enc_get_iv_size(td);
122 
123  memset(this->iv, 0, iv_size);
124  SAFE_FREE(this->iv);
125  }
126 }
127 
128 void Crypt::setFlipSeed(uint32_t seed, uint32_t pattern) {
129  setSeed((~seed) ^ pattern);
130 }
131 
132 uint32_t Crypt::getSeed(void) const {
133  return seed;
134 }
135 
136 bool Crypt::setPassword(const char *password, const char *salt) {
137  KEYGEN data;
138  int passlen, saltlen;
139  unsigned char* key = NULL;
140 
141  assert(password != NULL);
142  assert(salt != NULL);
143 
144  /* Scrub from memory before release */
145  if (this->key) {
146  memset(this->key, 0, this->keylen);
147  SAFE_FREE(this->key);
148  }
149 
150  if (this->salt) {
151  memset(this->salt, 0, strlen(this->salt));
152  SAFE_FREE(this->salt);
153  }
154 
155  if (this->password) {
156  memset(this->password, 0, strlen(this->password));
157  SAFE_FREE(this->password);
158  }
159 
160  if (password == NULL || salt == NULL) {
161  goto error;
162  }
163 
164  if ((key = (unsigned char*) calloc(1, keylen)) == NULL) {
165  goto error;
166  }
167 
168  if ((saltlen = mhash_get_keygen_salt_size(KEYGEN_MCRYPT)) == 0) {
169  saltlen = strlen(salt);
170  } else if (saltlen > (int) strlen(salt)) {
171  saltlen = strlen(salt);
172  }
173 
174  data.hash_algorithm[0] = MHASH_MD5;
175  data.count = 0;
176  data.salt = (void*) salt;
177  data.salt_size = saltlen;
178  passlen = strlen(password);
179 
180  if (mhash_keygen_ext(KEYGEN_MCRYPT, data, key, keylen, (unsigned char*) password, passlen) < 0) {
181  goto error;
182  }
183 
184  this->key = key;
185  this->password = strndup(password, passlen);
186  this->salt = strndup(salt, saltlen);
187 
188 #ifdef DUMP
189  printf("key(%d): 0x", keylen);
190  for (int i = 0; i < keylen; i++) {
191  printf("%.2x", this->key[i]);
192  }
193  printf("\n");
194 #endif
195 
196  return true;
197 
198 error:
199  if (key) { /* Scrub local key value before release. */
200  memset(key, 0, this->keylen);
201  SAFE_FREE(key);
202  }
203 
204  return false;
205 }
206 
207 const char* Crypt::getPassword(void) {
208  return password;
209 }
210 
211 const unsigned char* Crypt::getKey(void) {
212  return key;
213 }
214 
215 void Crypt::setKeyLen(int bits) {
216  int maxlen = mcrypt_enc_get_key_size(td);
217  keylen = bits / 8;
218 
219  if (keylen > maxlen) {
220  keylen = maxlen;
221  } else if (keylen < 1) {
222  keylen = CRYPT_KEYLEN_DEF;
223  }
224 
225  /* KeyLen change invalides key */
226  if (password && salt) {
227  char *tpassword = strdup(password);
228  char *tsalt = strdup(salt);
229 
230  setPassword(password, salt);
231 
232  /* Scrub memory before release */
233  memset(tpassword, 0, strlen(tpassword));
234  SAFE_FREE(tpassword);
235 
236  memset(tsalt, 0, strlen(tsalt));
237  SAFE_FREE(tsalt);
238  }
239 }
240 
241 int Crypt::getKeyLen(void) const {
242  return (keylen * 8);
243 }
244 
245 bool Crypt::encrypt(char *plaintext, int len) {
246  if (!plaintext || len < 1) {
247  return false;
248  }
249 
250  if (!initialize()) {
251  return false;
252  }
253 
254  return !mcrypt_generic(td, plaintext, len);
255 }
256 
257 bool Crypt::decrypt(char *ciphertext, int len) {
258  if (!ciphertext || len < 1) {
259  return false;
260  }
261 
262  if (!initialize()) {
263  return false;
264  }
265 
266  return !mdecrypt_generic(td, ciphertext, len);
267 }
268 
269 bool Crypt::check(const char *ciphertext, int len) {
270  bool retval;
271  void *tmp;
272 
273  if ((tmp = malloc(len)) == NULL) {
274  return false;
275  }
276 
277  memcpy(tmp, ciphertext, len);
278 
279  retval = decrypt((char*) tmp, len);
280 
281  memset(tmp, 0, len); /* Scrub memory before release */
282  free(tmp);
283 
284  return retval;
285 }
286 
287 bool Crypt::initialize(void) {
288  if (!deinitialize()) {
289  return false;
290  }
291 
292  if (iv == NULL) {
293  if (!generateIV()) {
294  return false;
295  }
296  }
297 
298  if (mcrypt_generic_init(td, key, keylen, iv) >= 0) {
299  init = true;
300 
301  return true;
302  }
303 
304  return false;
305 }
306 
307 bool Crypt::deinitialize(void) {
308  if (init) {
309  init = false;
310 
311  if (mcrypt_generic_deinit(td) < 0) {
312  return false;
313  }
314  }
315 
316  return true;
317 }
318 
319 bool Crypt::generateIV(void) {
320  struct drand48_data state;
321  long int result;
322  int iv_size = mcrypt_enc_get_iv_size(td);
323 
324  if (this->iv) { /* Scrub from memory before release */
325  memset(this->iv, 0, iv_size);
326  SAFE_FREE(this->iv);
327  }
328 
329  if ((this->iv = (unsigned char*) malloc(iv_size)) == NULL) {
330  return false;
331  }
332 
333  srand48_r(seed, &state);
334  for (int i = 0; i < iv_size; i++) {
335  lrand48_r(&state, &result);
336  this->iv[i] = (unsigned char) result;
337  }
338 
339 #ifdef DUMP
340  printf("iv(%d)[seed: %lu]: 0x", iv_size, seed);
341  for (int i = 0; i < iv_size; i++) {
342  printf("%.1x", this->iv[i]);
343  }
344  printf("\n");
345 #endif
346 
347  return true;
348 }
349 
350 #endif
351 
352 /*
353 ** vim: noet ts=3 sw=3
354 */