feisty meow concerns codebase  2.140
rsa_crypto.cpp
Go to the documentation of this file.
1 /*
2 * Name : RSA public key encryption
3 * Author : Chris Koeritz
4 * Purpose:
5 * Supports public (and private) key encryption and decryption using the
6 * OpenSSL package's support for RSA encryption.
7 ****
8 * Copyright (c) 2005-$now By Author. This program is free software; you can *
9 * redistribute it and/or modify it under the terms of the GNU General Public *
10 * License as published by the Free Software Foundation; either version 2 of *
11 * the License or (at your option) any later version. This is online at: *
12 * http://www.fsf.org/copyleft/gpl.html *
13 * Please send any updates to: fred@gruntose.com *
14 */
15 
16 //note: rsa crypto provides a nice printing method... RSA_print_fp(stdout, private_key, 0);
17 
18 // notes from openssl docs: length to be encrypted in a chunk must be less than
19 // RSA_size(rsa) - 11 for the PKCS #1 v1.5 based padding modes, less than
20 // RSA_size(rsa) - 41 for RSA_PKCS1_OAEP_PADDING and exactly RSA_size(rsa)
21 // for RSA_NO_PADDING.
22 
23 #include "rsa_crypto.h"
24 #include "ssl_init.h"
25 
26 #include <basis/functions.h>
29 #include <mathematics/chaos.h>
32 
33 #include <openssl/bn.h>
34 #include <openssl/err.h>
35 #include <openssl/rsa.h>
36 
37 using namespace basis;
38 using namespace loggers;
39 using namespace mathematics;
40 using namespace structures;
41 
42 namespace crypto {
43 
44 //#define DEBUG_RSA_CRYPTO
45  // uncomment for noisier version.
46 
47 #ifdef DEBUG_RSA_CRYPTO
48  #undef LOG
49  #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
50 #else
51  #undef LOG
52  #define LOG(s)
53 #endif
54 
55 SAFE_STATIC(mutex, __single_stepper, )
56  // protects unsafe areas of rsa crypto from access by multiple threads at once.
57 
58 rsa_crypto::rsa_crypto(int key_size)
59 : _key(NULL_POINTER)
60 {
61  FUNCDEF("ctor(int)");
62  LOG("prior to generating key");
63  _key = generate_key(key_size); // generate_key initializes ssl for us.
64  LOG("after generating key");
65 }
66 
67 rsa_crypto::rsa_crypto(const byte_array &key)
68 : _key(NULL_POINTER)
69 {
70  FUNCDEF("ctor(byte_array)");
72  byte_array key_copy = key;
73  LOG("prior to set key");
74  set_key(key_copy);
75  LOG("after set key");
76 }
77 
79 : _key(NULL_POINTER)
80 {
81  FUNCDEF("ctor(RSA)");
83  LOG("prior to set key");
84  set_key(key);
85  LOG("after set key");
86 }
87 
89 : root_object(),
90  _key(NULL_POINTER)
91 {
92  FUNCDEF("copy ctor");
94  LOG("prior to set key");
95  set_key(to_copy._key);
96  LOG("after set key");
97 }
98 
100 {
101  FUNCDEF("destructor");
102  LOG("prior to rsa free");
103  auto_synchronizer mutt(__single_stepper());
104  RSA_free(_key);
105  LOG("after rsa free");
106 }
107 
109 {
110  if (this == &to_copy) return *this;
111  set_key(to_copy._key);
112  return *this;
113 }
114 
116 {
117  FUNCDEF("generate_key");
118  if (key_size < 4) key_size = 4; // laughable lower default.
120  LOG("into generate key");
121  auto_synchronizer mutt(__single_stepper());
122  RSA *to_return = RSA_new();
123  BIGNUM *e = BN_new();
124  BN_set_word(e, 65537);
125 //hmmm: only one value of e?
126  int ret = RSA_generate_key_ex(to_return, key_size, e, NULL_POINTER);
127  if (!ret) {
129  a_sprintf("failed to generate a key of %d bits: error is %ld.", key_size, ERR_get_error()));
130  BN_free(e);
131  RSA_free(to_return);
132  return NULL;
133  }
134  LOG("after key generated");
135  BN_free(e);
136  return to_return;
137 }
138 
140 {
141  auto_synchronizer mutt(__single_stepper());
142  return RSA_check_key(key) == 1;
143 }
144 
146 {
147  FUNCDEF("set_key [byte_array]");
148  if (!key.length()) return false;
149  auto_synchronizer mutt(__single_stepper());
150  if (_key) RSA_free(_key);
151  _key = RSA_new();
152  abyte type;
153  if (!structures::detach(key, type)) return false;
154  if ( (type != 'r') && (type != 'u') ) return false;
155  // get the public key bits first.
156  byte_array n;
157  if (!structures::detach(key, n)) return false;
158  BIGNUM *the_n = BN_bin2bn(n.access(), n.length(), NULL_POINTER);
159  if (!the_n) return false;
160  byte_array e;
161  if (!structures::detach(key, e)) return false;
162  BIGNUM *the_e = BN_bin2bn(e.access(), e.length(), NULL_POINTER);
163  if (!the_e) return false;
164 
165  if (type == 'u') {
166  // done with public key.
167 #ifdef NEWER_OPENSSL
168  RSA_set0_key(_key, the_n, the_e, NULL_POINTER);
169 #else
170  _key->n = the_n; _key->e = the_e;
171 #endif
172  return true;
173  }
174 
175  // the rest is for a private key.
176  byte_array d;
177  if (!structures::detach(key, d)) return false;
178  BIGNUM *the_d = BN_bin2bn(d.access(), d.length(), NULL_POINTER);
179  if (!the_d) return false;
180 
181  byte_array p;
182  if (!structures::detach(key, p)) return false;
183  BIGNUM *the_p = BN_bin2bn(p.access(), p.length(), NULL_POINTER);
184  if (!the_p) return false;
185  byte_array q;
186  if (!structures::detach(key, q)) return false;
187  BIGNUM *the_q = BN_bin2bn(q.access(), q.length(), NULL_POINTER);
188  if (!the_q) return false;
189  byte_array dmp1;
190  if (!structures::detach(key, dmp1)) return false;
191  BIGNUM *the_dmp1 = BN_bin2bn(dmp1.access(), dmp1.length(), NULL_POINTER);
192  if (!the_dmp1) return false;
193  byte_array dmq1;
194  if (!structures::detach(key, dmq1)) return false;
195  BIGNUM *the_dmq1 = BN_bin2bn(dmq1.access(), dmq1.length(), NULL_POINTER);
196  if (!the_dmq1) return false;
197  byte_array iqmp;
198  if (!structures::detach(key, iqmp)) return false;
199  BIGNUM *the_iqmp = BN_bin2bn(iqmp.access(), iqmp.length(), NULL_POINTER);
200  if (!the_iqmp) return false;
201 
202  // we can set the n, e and d now.
203 #ifdef NEWER_OPENSSL
204  int ret = RSA_set0_key(_key, the_n, the_e, the_d);
205  if (ret != 1) return false;
206  ret = RSA_set0_factors(_key, the_p, the_q);
207  if (ret != 1) return false;
208  ret = RSA_set0_crt_params(_key, the_dmp1, the_dmq1, the_iqmp);
209  if (ret != 1) return false;
210 #else
211  _key->n = the_n; _key->e = the_e; _key->d = the_d;
212  _key->p = the_p; _key->q = the_q;
213  _key->dmp1 = the_dmp1; _key->dmq1 = the_dmq1; _key->iqmp = the_iqmp;
214 #endif
215 
216  int check = RSA_check_key(_key);
217  if (check != 1) {
218  continuable_error(static_class_name(), func, "failed to check the private "
219  "portion of the key!");
220  return false;
221  }
222 
223  return true;
224 }
225 
227 {
228  FUNCDEF("set_key [RSA]");
229  if (!key) return NULL_POINTER;
230  // test the incoming key.
231  auto_synchronizer mutt(__single_stepper());
232  int check = RSA_check_key(key);
233  if (check != 1) return false;
234  // clean out the old key.
235  if (_key) RSA_free(_key);
236  _key = RSAPrivateKey_dup(key);
237  if (!_key) {
238  continuable_error(static_class_name(), func, "failed to create a "
239  "duplicate of the key!");
240  return false;
241  }
242  return true;
243 }
244 
246 {
247  FUNCDEF("public_key");
248  if (!_key) return false;
249  structures::attach(pubkey, abyte('u')); // signal a public key.
250  // convert the two public portions into binary.
251  BIGNUM **the_n = new BIGNUM *, **the_e = new BIGNUM *, **the_d = new BIGNUM *;
252 #ifdef NEWER_OPENSSL
253  RSA_get0_key(_key, (const BIGNUM **)the_n, (const BIGNUM **)the_e, (const BIGNUM **)the_d);
254 #else
255  *the_n = _key->n; *the_e = _key->e; *the_d = _key->d;
256 #endif
257  byte_array n(BN_num_bytes(*the_n));
258  int ret = BN_bn2bin(*the_n, n.access());
259  byte_array e(BN_num_bytes(*the_e));
260  ret = BN_bn2bin(*the_e, e.access());
261  // pack those two chunks.
262  structures::attach(pubkey, n);
263  structures::attach(pubkey, e);
264  WHACK(the_n); WHACK(the_e); WHACK(the_d);
265 
266  return true;
267 }
268 
270 {
271  FUNCDEF("private_key");
272  if (!_key) return false;
273  int posn = privkey.length();
274  bool worked = public_key(privkey); // get the public pieces first.
275  if (!worked) return false;
276  privkey[posn] = abyte('r'); // switch public key flag to private.
277  // convert the multiple private portions into binary.
278  //const BIGNUM **the_n = NULL_POINTER, **the_e = NULL_POINTER, **the_d = NULL_POINTER;
279  BIGNUM **the_n = new BIGNUM *, **the_e = new BIGNUM *, **the_d = new BIGNUM *;
280  BIGNUM **the_p = new BIGNUM *, **the_q = new BIGNUM *;
281  BIGNUM **the_dmp1 = new BIGNUM *, **the_dmq1 = new BIGNUM *, **the_iqmp = new BIGNUM *;
282 #ifdef NEWER_OPENSSL
283  RSA_get0_key(_key, (const BIGNUM **)the_n, (const BIGNUM **)the_e, (const BIGNUM **)the_d);
284  RSA_get0_factors(_key, (const BIGNUM **)the_p, (const BIGNUM **)the_q);
285  RSA_get0_crt_params(_key, (const BIGNUM **)the_dmp1, (const BIGNUM **)the_dmq1, (const BIGNUM **)the_iqmp);
286 #else
287  *the_n = _key->n; *the_e = _key->e; *the_d = _key->d;
288  *the_p = _key->p; *the_q = _key->q;
289  *the_dmp1 = _key->dmp1; *the_dmq1 = _key->dmq1; *the_iqmp = _key->iqmp;
290 #endif
291  byte_array d(BN_num_bytes(*the_d));
292  int ret = BN_bn2bin(*the_d, d.access());
293  byte_array p(BN_num_bytes(*the_p));
294  ret = BN_bn2bin(*the_p, p.access());
295  byte_array q(BN_num_bytes(*the_q));
296  ret = BN_bn2bin(*the_q, q.access());
297  byte_array dmp1(BN_num_bytes(*the_dmp1));
298  ret = BN_bn2bin(*the_dmp1, dmp1.access());
299  byte_array dmq1(BN_num_bytes(*the_dmq1));
300  ret = BN_bn2bin(*the_dmq1, dmq1.access());
301  byte_array iqmp(BN_num_bytes(*the_iqmp));
302  ret = BN_bn2bin(*the_iqmp, iqmp.access());
303  // pack all those in now.
304  structures::attach(privkey, d);
305  structures::attach(privkey, p);
306  structures::attach(privkey, q);
307  structures::attach(privkey, dmp1);
308  structures::attach(privkey, dmq1);
309  structures::attach(privkey, iqmp);
310  return true;
311 }
312 
314  byte_array &target) const
315 {
316  FUNCDEF("public_encrypt");
317  target.reset();
318  if (!source.length()) return false;
319 
320  auto_synchronizer mutt(__single_stepper());
321  const int max_chunk = RSA_size(_key) - 12;
322 
323  byte_array encoded(RSA_size(_key));
324  for (int i = 0; i < source.length(); i += max_chunk) {
325  int edge = i + max_chunk - 1;
326  if (edge > source.last())
327  edge = source.last();
328  int next_chunk = edge - i + 1;
329  RSA_public_encrypt(next_chunk, &source[i],
330  encoded.access(), _key, RSA_PKCS1_PADDING);
331  target += encoded;
332  }
333  return true;
334 }
335 
337  byte_array &target) const
338 {
339  FUNCDEF("private_decrypt");
340  target.reset();
341  if (!source.length()) return false;
342 
343  auto_synchronizer mutt(__single_stepper());
344  const int max_chunk = RSA_size(_key);
345 
346  byte_array decoded(max_chunk);
347  for (int i = 0; i < source.length(); i += max_chunk) {
348  int edge = i + max_chunk - 1;
349  if (edge > source.last())
350  edge = source.last();
351  int next_chunk = edge - i + 1;
352  int dec_size = RSA_private_decrypt(next_chunk, &source[i],
353  decoded.access(), _key, RSA_PKCS1_PADDING);
354  if (dec_size < 0) return false; // that didn't work.
355  decoded.zap(dec_size, decoded.last());
356  target += decoded;
357  decoded.reset(max_chunk);
358  }
359  return true;
360 }
361 
363  byte_array &target) const
364 {
365  FUNCDEF("private_encrypt");
366  target.reset();
367  if (!source.length()) return false;
368 
369  auto_synchronizer mutt(__single_stepper());
370  const int max_chunk = RSA_size(_key) - 12;
371 
372  byte_array encoded(RSA_size(_key));
373  for (int i = 0; i < source.length(); i += max_chunk) {
374  int edge = i + max_chunk - 1;
375  if (edge > source.last())
376  edge = source.last();
377  int next_chunk = edge - i + 1;
378  RSA_private_encrypt(next_chunk, &source[i],
379  encoded.access(), _key, RSA_PKCS1_PADDING);
380  target += encoded;
381  }
382  return true;
383 }
384 
386  byte_array &target) const
387 {
388  FUNCDEF("public_decrypt");
389  target.reset();
390  if (!source.length()) return false;
391 
392  auto_synchronizer mutt(__single_stepper());
393  const int max_chunk = RSA_size(_key);
394 
395  byte_array decoded(max_chunk);
396  for (int i = 0; i < source.length(); i += max_chunk) {
397  int edge = i + max_chunk - 1;
398  if (edge > source.last())
399  edge = source.last();
400  int next_chunk = edge - i + 1;
401  int dec_size = RSA_public_decrypt(next_chunk, &source[i],
402  decoded.access(), _key, RSA_PKCS1_PADDING);
403  if (dec_size < 0) return false; // that didn't work.
404  decoded.zap(dec_size, decoded.last());
405  target += decoded;
406  decoded.reset(max_chunk);
407  }
408  return true;
409 }
410 
411 } //namespace.
412 
a_sprintf is a specialization of astring that provides printf style support.
Definition: astring.h:440
void reset(int number=0, const contents *initial_contents=NULL_POINTER)
Resizes this array and sets the contents from an array of contents.
Definition: array.h:349
contents * access()
A non-constant access of the underlying C-array. BE REALLY CAREFUL.
Definition: array.h:175
int length() const
Returns the current reported length of the allocated C array.
Definition: array.h:115
outcome zap(int start, int end)
Deletes from "this" the objects inclusively between "start" and "end".
Definition: array.h:769
int last() const
Returns the last valid element in the array.
Definition: array.h:118
auto_synchronizer simplifies concurrent code by automatically unlocking.
Definition: mutex.h:113
A very common template for a dynamic array of bytes.
Definition: byte_array.h:36
Supports public key encryption and decryption.
Definition: rsa_crypto.h:33
const rsa_crypto & operator=(const rsa_crypto &to_copy)
Definition: rsa_crypto.cpp:108
bool public_encrypt(const basis::byte_array &source, basis::byte_array &target) const
encrypts "source" using our public key and stores it in "target".
Definition: rsa_crypto.cpp:313
bool set_key(basis::byte_array &key)
resets this object's key to "key".
Definition: rsa_crypto.cpp:145
bool private_key(basis::byte_array &privkey) const
makes a copy of the private key held here.
Definition: rsa_crypto.cpp:269
static RSA * generate_key(int key_size)
creates a random RSA key using the lower-level openssl methods.
Definition: rsa_crypto.cpp:115
bool private_decrypt(const basis::byte_array &source, basis::byte_array &target) const
decrypts "source" using our private key and stores it in "target".
Definition: rsa_crypto.cpp:336
bool public_decrypt(const basis::byte_array &source, basis::byte_array &target) const
decrypts "source" using our public key and stores it in "target".
Definition: rsa_crypto.cpp:385
bool check_key(RSA *key)
checks the RSA "key" provided for validity.
Definition: rsa_crypto.cpp:139
bool private_encrypt(const basis::byte_array &source, basis::byte_array &target) const
encrypts "source" using our private key and stores it in "target".
Definition: rsa_crypto.cpp:362
virtual ~rsa_crypto()
Definition: rsa_crypto.cpp:99
bool public_key(basis::byte_array &pubkey) const
makes a copy of the public key held here.
Definition: rsa_crypto.cpp:245
rsa_crypto(int key_size)
constructs using a randomized private key of the "key_size".
Definition: rsa_crypto.cpp:58
#define continuable_error(c, f, i)
#define NULL_POINTER
The value representing a pointer to nothing.
Definition: definitions.h:32
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition: enhance_cpp.h:57
The guards collection helps in testing preconditions and reporting errors.
Definition: array.h:30
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition: functions.h:121
unsigned char abyte
A fairly important unit which is seldom defined...
Definition: definitions.h:51
const ssl_init & static_ssl_initializer()
the main method for accessing the SSL initialization support.
A logger that sends to the console screen using the standard output device.
An extension to floating point primitives providing approximate equality.
Definition: averager.h:21
A dynamic container class that holds any kind of object via pointers.
Definition: amorph.h:55
void attach(byte_array &packed_form, const byte_array &to_attach)
Packs a byte_array "to_attach" into "packed_form".
bool detach(byte_array &packed_form, byte_array &to_detach)
Unpacks a byte_array "to_detach" from "packed_form".
#define LOG(s)
Definition: rsa_crypto.cpp:52
struct rsa_st RSA
Definition: rsa_crypto.h:23
#define SAFE_STATIC(type, func_name, parms)
Statically defines a singleton object whose scope is the program's lifetime.
#define static_class_name()