Cipher Class
 All Classes Namespaces Files Functions Variables Typedefs Macros Pages
cipher.cc
Go to the documentation of this file.
1 // ================================================================
2 // Description: Cipher class.
3 // Copyright: Copyright (c) 2012 by Joe Linoff
4 // Version: 1.2
5 // Author: Joe Linoff
6 //
7 // LICENSE
8 // The cipher package is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // The cipher package is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // General Public License for more details. You should have received
17 // a copy of the GNU General Public License along with the change
18 // tool; if not, write to the Free Software Foundation, Inc., 59
19 // Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 // ================================================================
21 #include "cipher.h"
22 #include <fstream>
23 #include <iostream>
24 #include <iomanip>
25 #include <string>
26 #include <vector>
27 #include <stdexcept>
28 #include <sstream>
29 #include <cstring> // strlen
30 #include <cstdlib> // getenv
31 #include <unistd.h> // getdomainname
32 #include <openssl/aes.h>
33 #include <openssl/bio.h>
34 #include <openssl/evp.h>
35 #include <openssl/buffer.h>
36 using namespace std;
37 
38 // ================================================================
39 // MACROS
40 // ================================================================
41 #define DBG_PRE __FILE__ << ":" << __LINE__ << ": "
42 #define DBG_FCT(fct) if(m_debug) cout << DBG_PRE << "FCT " << fct << endl
43 #define DBG_TDUMP(v) if(m_debug) tdump(__FILE__,__LINE__,#v,v)
44 #define DBG_PKV(v) if(m_debug) vdump(__FILE__,__LINE__,#v,v)
45 #define DBG_PKVR(k,v) if(m_debug) vdump(__FILE__,__LINE__,k,v)
46 #define DBG_BDUMP(a,x) if(m_debug) bdump(__FILE__,__LINE__,#a,a,x)
47 #define DBG_MDUMP(a) if(m_debug) bdump(__FILE__,__LINE__,#a,(unsigned char*)a.c_str(),a.size())
48 #define DBG_MADEIT cout << DBG_PRE << "MADE IT" << endl
49 #define PKV(v) vdump(__FILE__,__LINE__,#v,v)
50 
51 #define SALTED_PREFIX "Salted__"
52 
53 namespace
54 {
55  // ================================================================
56  // DEBUG mode only.
57  // Formated dump of a general type.
58  // ================================================================
59  template<typename T> void vdump(const string& fn,
60  uint ln,
61  const string& prefix,
62  const T& d)
63  {
64  cout << fn << ":" << ln << ": " << prefix << "\t" << d << endl;
65  }
66  // ================================================================
67  // DEBUG mode only.
68  // Explicit template instantiation of the above for string
69  // types so that I can report the length.
70  // ================================================================
71  template<> void vdump<string>(const string& fn,
72  uint ln,
73  const string& prefix,
74  const string& d)
75  {
76  cout << fn << ":" << ln << ": "
77  << prefix << "\t"
78  << left << setw(64) << d
79  << " (" << d.size() << ")"
80  << endl;
81  }
82  // ================================================================
83  // DEBUG mode only.
84  // Dump for fixed sized types like m_salt and m_key.
85  // ================================================================
86  template<typename T> void tdump(const string& fn,
87  uint ln,
88  const string& prefix,
89  const T& d)
90  {
91  cout << fn << ":" << ln << ": " << prefix << "\t";
92  for(uint i=0;i<sizeof(T);++i) {
93 #if 0
94  // Prettified output.
95  // I turned it off so that the format would match openssl.
96  if ((i%16)==0) {
97  if (i) {
98  cout << endl;
99  cout << "\t\t\t";
100  }
101  else {
102  if (prefix.size()<4) {
103  cout << "\t";
104  }
105  cout << "\t";
106  }
107  }
108  else if (i) {
109  cout << ", ";
110  }
111 #endif
112  cout << setw(2) << setfill('0') << hex << right << uint(d[i]) << dec << setfill(' ');
113  }
114  cout << " (" << sizeof(T) << ")" << endl;
115  }
116  // ================================================================
117  // DEBUG mode only.
118  // Binary data dump.
119  // ================================================================
120  void bdump(const string& fn,
121  uint ln,
122  const string& prefix,
123  unsigned char* a,
124  unsigned int len)
125  {
126  cout << fn << ":" << ln << ": " << prefix;
127  for(uint i=0;i<len;++i) {
128  if ((i%16)==0) {
129  if (i) {
130  cout << endl;
131  cout << "\t\t\t";
132  }
133  else {
134  cout << "\t\t";
135  }
136  }
137  else if (i) {
138  cout << ", ";
139  }
140  cout << setw(2) << hex << right << uint(a[i]) << dec;
141  }
142  cout << " (" << len << ")" << endl;
143  }
144 }
145 
146 // ================================================================
147 // Constructor.
148 // ================================================================
150  : m_cipher(CIPHER_DEFAULT_CIPHER),
151  m_digest(CIPHER_DEFAULT_DIGEST),
152  m_count(CIPHER_DEFAULT_COUNT),
153  m_embed(true), // compatible with openssl
154  m_debug(false)
155 {
156 }
157 
158 // ================================================================
159 // Constructor.
160 // ================================================================
161 Cipher::Cipher(const std::string& cipher,
162  const std::string& digest,
163  uint count,
164  bool embed)
165  : m_cipher(cipher),
166  m_digest(digest),
167  m_count(count),
168  m_embed(embed),
169  m_debug(false)
170 {
171 }
172 
173 // ================================================================
174 // Destructor.
175 // ================================================================
177 {
178 }
179 
180 // ================================================================
181 // encrypt
182 // ================================================================
183 string Cipher::encrypt(const string& plaintext,
184  const string& pass,
185  const string& salt)
186 {
187  DBG_FCT("encrypt");
188  set_salt(salt);
189  init(pass);
190  kv1_t x = encode_cipher(plaintext);
191  uchar* ct = x.first;
192  uint ctlen = x.second;
193  DBG_BDUMP(ct,ctlen);
194 
195  string ret = encode_base64(ct,ctlen);
196  delete [] ct;
197  DBG_MDUMP(ret);
198  return ret;
199 }
200 
201 // ================================================================
202 // encrypt_file
203 // ================================================================
204 void Cipher::encrypt_file(const string& ifn,
205  const string& ofn,
206  const string& pass,
207  const string& salt)
208 {
209  DBG_FCT("encrypt_file");
210  string plaintext = file_read(ifn);
211  string ciphertext = encrypt(plaintext,pass,salt);
212  file_write(ofn,ciphertext,true);
213 }
214 
215 // ================================================================
216 // decrypt
217 // ================================================================
218 string Cipher::decrypt(const string& mimetext,
219  const string& pass,
220  const string& salt)
221 {
222  DBG_FCT("decrypt");
223  kv1_t x = decode_base64(mimetext);
224  uchar* ct = x.first;
225  uchar* ctbeg = ct;
226  uint ctlen = x.second;
227  DBG_BDUMP(ct,ctlen);
228 
229  if (strncmp((const char*)ct,SALTED_PREFIX,8) == 0) {
230  memcpy(m_salt,&ct[8],8);
231  ct += 16;
232  ctlen -= 16;
233  }
234  else {
235  set_salt(salt);
236  }
237  init(pass);
238  string ret = decode_cipher(ct,ctlen);
239  delete [] ctbeg;
240  DBG_MDUMP(ret);
241  return ret;
242 }
243 
244 // ================================================================
245 // decrypt_file
246 // ================================================================
247 void Cipher::decrypt_file(const string& ifn,
248  const string& ofn,
249  const string& pass,
250  const string& salt)
251 {
252  DBG_FCT("decrypt_file");
253  string ciphertext = file_read(ifn);
254  string plaintext = decrypt(ciphertext,pass,salt);
255  file_write(ofn,plaintext);
256 }
257 
258 // ================================================================
259 // encode_base64
260 // ================================================================
261 string Cipher::encode_base64(uchar* ciphertext,
262  uint ciphertext_len) const
263 {
264  DBG_FCT("encode_base64");
265  BIO* b64 = BIO_new(BIO_f_base64());
266  BIO* bm = BIO_new(BIO_s_mem());
267  b64 = BIO_push(b64,bm);
268  if (BIO_write(b64,ciphertext,ciphertext_len)<2) {
269  throw runtime_error("BIO_write() failed");
270  }
271  if (BIO_flush(b64)<1) {
272  throw runtime_error("BIO_flush() failed");
273  }
274  BUF_MEM *bptr=0;
275  BIO_get_mem_ptr(b64,&bptr);
276  uint len=bptr->length;
277  char* mimetext = new char[len+1];
278  memcpy(mimetext, bptr->data, bptr->length-1);
279  mimetext[bptr->length-1]=0;
280  BIO_free_all(b64);
281 
282  string ret = mimetext;
283  delete [] mimetext;
284  return ret;
285 }
286 
287 // ================================================================
288 // decode_base64
289 // ================================================================
290 Cipher::kv1_t Cipher::decode_base64(const string& mimetext) const
291 {
292  DBG_FCT("decode_base64");
293  kv1_t x;
294  int SZ=mimetext.size(); // this will always be smaller
295  x.first = new uchar[SZ];
296  char* tmpbuf = new char[SZ+1];
297  strcpy(tmpbuf,mimetext.c_str());
298  BIO* b64 = BIO_new(BIO_f_base64());
299 
300  // This patch was suggested by Mihai Todor.
301  // It was added to the code on 2013-11-21.
302  // Please see this post for details:
303  // http://joelinoff.com/blog/?p=664
304  if (SZ <= 64) {
305  // If the string is less len 64 or less,
306  // then the -A switch must be used in
307  // openssl.
308  BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
309  }
310 
311  BIO* bm = BIO_new_mem_buf(tmpbuf,mimetext.size());
312  bm = BIO_push(b64,bm);
313  x.second = BIO_read(bm,x.first,SZ);
314  BIO_free_all(bm);
315  delete [] tmpbuf;
316  return x;
317 }
318 
319 // ================================================================
320 // encode_cipher
321 // ================================================================
322 Cipher::kv1_t Cipher::encode_cipher(const string& plaintext) const
323 {
324  DBG_FCT("encode_cipher");
325  uint SZ=plaintext.size()+AES_BLOCK_SIZE+20;
326  uchar* ciphertext = new uchar[SZ];
327  bzero(ciphertext,SZ);
328  uchar* pbeg = ciphertext;
329 
330  // This requires some explanation.
331  // In order to be compatible with openssl, I need to append
332  // 16 characters worth of information that describe the salt.
333  // I found this in the openssl source code but I couldn't
334  // find any associated documentation.
335  uint off = 0;
336  if (m_embed) {
337  memcpy(&ciphertext[0],SALTED_PREFIX,8);
338  memcpy(&ciphertext[8],m_salt,8);
339  off = 16;
340  ciphertext += off;
341  }
342 
343  int ciphertext_len=0;
344  int ciphertext_padlen=0;
345  EVP_CIPHER_CTX ctx;
346  EVP_CIPHER_CTX_init(&ctx);
347 
348  if (!EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, m_key, m_iv)) {
349  throw runtime_error("EVP_EncryptInit_ex() failed");
350  }
351  EVP_CIPHER_CTX_set_key_length(&ctx, EVP_MAX_KEY_LENGTH);
352 
353  uchar* p = (uchar*)plaintext.c_str();
354  uint plen = plaintext.size();
355  if (!EVP_EncryptUpdate(&ctx,ciphertext,&ciphertext_len,p,plen)) {
356  throw runtime_error("EVP_EncryptUpdate() failed");
357  }
358 
359  uchar* pbuf = ciphertext+ciphertext_len; // pad at the end
360  if (!EVP_EncryptFinal_ex(&ctx,pbuf,&ciphertext_padlen)) {
361  throw runtime_error("EVP_EncryptFinal_ex() failed");
362  }
363 
364  ciphertext_len += ciphertext_padlen + off; // <off> for the Salted prefix
365  return kv1_t(pbeg,ciphertext_len);
366 }
367 
368 // ================================================================
369 // decode_cipher
370 // ================================================================
371 string Cipher::decode_cipher(uchar* ciphertext,
372  uint ciphertext_len) const
373 {
374  DBG_FCT("decode_cipher");
375  uint SZ = ciphertext_len+20;
376  uchar* plaintext = new uchar[SZ];
377  bzero(plaintext,SZ);
378  int plaintext_len = 0;
379  EVP_CIPHER_CTX ctx;
380  EVP_CIPHER_CTX_init(&ctx);
381 
382  if (!EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, m_key, m_iv)) {
383  throw runtime_error("EVP_DecryptInit_ex() failed");
384  }
385  EVP_CIPHER_CTX_set_key_length(&ctx, EVP_MAX_KEY_LENGTH);
386 
387  if (!EVP_DecryptUpdate(&ctx,plaintext,&plaintext_len,ciphertext,ciphertext_len)) {
388  throw runtime_error("EVP_DecryptUpdate() failed");
389  }
390 
391  int plaintext_padlen=0;
392  if (!EVP_DecryptFinal_ex(&ctx,plaintext+plaintext_len,&plaintext_padlen)) {
393  throw runtime_error("EVP_DecryptFinal_ex() failed");
394  }
395  plaintext_len += plaintext_padlen;
396  plaintext[plaintext_len] = 0;
397 
398  string ret = (char*)plaintext;
399  delete [] plaintext;
400  return ret;
401 }
402 
403 // ================================================================
404 // cvt_salt
405 // ================================================================
406 void Cipher::set_salt(const string& salt)
407 {
408  DBG_FCT("set_salt");
409  if (salt.length() == 0) {
410  // Choose a random salt.
411  for(uint i=0;i<sizeof(m_salt);++i) {
412  m_salt[i] = rand() % 256;
413  }
414  }
415  else if (salt.length() == 8) {
416  memcpy(m_salt,salt.c_str(),8);
417  }
418  else if (salt.length()<8) {
419  throw underflow_error("init(): salt is too short, must be 8 characters");
420  }
421  else if (salt.length()>8) {
422  throw overflow_error("init(): salt is too long, must be 8 characters");
423  }
424 }
425 
426 // ================================================================
427 // init()
428 // ================================================================
429 void Cipher::init(const string& pass)
430 {
431  DBG_FCT("init");
432  // Use a default passphrase if the user didn't specify one.
433  m_pass = pass;
434  if (m_pass.empty() ) {
435  // Default: ' deFau1t pASsw0rD'
436  // Obfuscate so that a simple strings will not find it.
437  char a[] = {' ','d','e','F','a','u','1','t',' ',
438  'p','A','S','s','w','0','r','D',0};
439  m_pass = a;
440  }
441 
442  // Create the key and IV values from the passkey.
443  bzero(m_key,sizeof(m_key));
444  bzero(m_iv,sizeof(m_iv));
445  OpenSSL_add_all_algorithms();
446  const EVP_CIPHER* cipher = EVP_get_cipherbyname(m_cipher.c_str());
447  const EVP_MD* digest = EVP_get_digestbyname(m_digest.c_str());
448  if (!cipher) {
449  string msg = "init(): cipher does not exist "+m_cipher;
450  throw runtime_error(msg);
451  }
452  if (!digest) {
453  string msg = "init(): digest does not exist "+m_digest;
454  throw runtime_error(msg);
455  }
456 
457  int ks = EVP_BytesToKey(cipher, // cipher type
458  digest, // message digest
459  m_salt, // 8 bytes
460  (uchar*)m_pass.c_str(), // pass value
461  m_pass.length(),
462  m_count, // number of rounds
463  m_key,
464  m_iv);
465  if (ks!=32) {
466  throw runtime_error("init() failed: "
467  "EVP_BytesToKey did not return a 32 byte key");
468  }
469 
470  DBG_PKV(m_pass);
471  DBG_PKV(m_cipher);
472  DBG_PKV(m_digest);
473  DBG_TDUMP(m_salt);
474  DBG_TDUMP(m_key);
475  DBG_TDUMP(m_iv);
476  DBG_PKV(m_count);
477 }
478 
479 // ================================================================
480 // file_read
481 // ================================================================
482 string Cipher::file_read(const string& fn) const
483 {
484  DBG_FCT("file_read");
485  ifstream ifs(fn.c_str());
486  if (!ifs) {
487  string msg="Cannot read file '"+fn+"'";
488  throw runtime_error(msg);
489  }
490  string str((istreambuf_iterator<char>(ifs)),
491  istreambuf_iterator<char>());
492  return str;
493 }
494 
495 // ================================================================
496 // file_write
497 // ================================================================
498 void Cipher::file_write(const string& fn,const string& data,bool nl) const
499 {
500  DBG_FCT("file_write");
501  ofstream ofs(fn.c_str());
502  if (!ofs) {
503  string msg="Cannot write file '"+fn+"'";
504  throw runtime_error(msg);
505  }
506  ofs << data;
507  if (nl) {
508  ofs << endl;
509  }
510  ofs.close();
511 }
512 
std::string decrypt(const std::string &ciphertext, const std::string &pass="", const std::string &salt="")
Decrypt a buffer using AES 256 CBC (SHA1).
Definition: cipher.cc:218
aes_key_t m_key
Definition: cipher.h:293
std::pair< uchar *, uint > kv1_t
Definition: cipher.h:82
void encrypt_file(const std::string &ifn, const std::string &ofn, const std::string &pass="", const std::string &salt="")
Encrypt a file.
Definition: cipher.cc:204
void file_write(const std::string &fn, const std::string &data, bool nl=false) const
Write ASCII data to a file.
Definition: cipher.cc:498
bool m_embed
Definition: cipher.h:296
void vdump< string >(const string &fn, uint ln, const string &prefix, const string &d)
Definition: cipher.cc:71
std::string encrypt(const std::string &plaintext, const std::string &pass="", const std::string &salt="")
Encrypt buffer using AES 256 CBC (SHA1).
Definition: cipher.cc:183
void vdump(const string &fn, uint ln, const string &prefix, const T &d)
Definition: cipher.cc:59
#define CIPHER_DEFAULT_COUNT
Definition: cipher.h:30
std::string m_digest
Definition: cipher.h:291
#define DBG_MDUMP(a)
Definition: cipher.cc:47
std::string m_cipher
Definition: cipher.h:290
#define CIPHER_DEFAULT_DIGEST
Definition: cipher.h:29
std::string decode_cipher(uchar *ciphertext, uint ciphertext_len) const
Cipher decode.
Definition: cipher.cc:371
std::string file_read(const std::string &fn) const
Read a file into a buffer.
Definition: cipher.cc:482
Cipher()
Constructor.
Definition: cipher.cc:149
~Cipher()
Destructor.
Definition: cipher.cc:176
void set_salt(const std::string &salt)
Convert string salt to internal format.
Definition: cipher.cc:406
#define DBG_BDUMP(a, x)
Definition: cipher.cc:46
unsigned int uint
Definition: cipher.h:77
#define DBG_PKV(v)
Definition: cipher.cc:44
aes_iv_t m_iv
Definition: cipher.h:294
unsigned char uchar
Definition: cipher.h:78
aes_salt_t m_salt
Definition: cipher.h:292
#define SALTED_PREFIX
Definition: cipher.cc:51
std::string m_pass
Definition: cipher.h:289
#define CIPHER_DEFAULT_CIPHER
Definition: cipher.h:28
uint m_count
Definition: cipher.h:295
void init(const std::string &pass)
Initialize the cipher: set the key and IV values.
Definition: cipher.cc:429
kv1_t encode_cipher(const std::string &plaintext) const
Cipher encode.
Definition: cipher.cc:322
#define DBG_FCT(fct)
Definition: cipher.cc:42
std::string encode_base64(uchar *ciphertext, uint ciphertext_len) const
Base64 encode.
Definition: cipher.cc:261
#define DBG_TDUMP(v)
Definition: cipher.cc:43
kv1_t decode_base64(const std::string &mimetext) const
Base64 decode.
Definition: cipher.cc:290
void decrypt_file(const std::string &ifn, const std::string &ofn, const std::string &pass="", const std::string &salt="")
Decrypt a file.
Definition: cipher.cc:247
void bdump(const string &fn, uint ln, const string &prefix, unsigned char *a, unsigned int len)
Definition: cipher.cc:120
void tdump(const string &fn, uint ln, const string &prefix, const T &d)
Definition: cipher.cc:86