first check-in of feisty meow codebase. many things broken still due to recent
[feisty_meow.git] / core / library / crypto / rsa_crypto.cpp
1 /*****************************************************************************\
2 *                                                                             *
3 *  Name   : RSA public key encryption                                         *
4 *  Author : Chris Koeritz                                                     *
5 *                                                                             *
6 *  Purpose:                                                                   *
7 *                                                                             *
8 *    Supports public (and private) key encryption and decryption using the    *
9 *  OpenSSL package's support for RSA encryption.                              *
10 *                                                                             *
11 *******************************************************************************
12 * Copyright (c) 2005-$now By Author.  This program is free software; you can  *
13 * redistribute it and/or modify it under the terms of the GNU General Public  *
14 * License as published by the Free Software Foundation; either version 2 of   *
15 * the License or (at your option) any later version.  This is online at:      *
16 *     http://www.fsf.org/copyleft/gpl.html                                    *
17 * Please send any updates to: fred@gruntose.com                               *
18 \*****************************************************************************/
19
20 #include "rsa_crypto.h"
21 #include "ssl_init.h"
22
23 #include <basis/functions.h>
24 #include <loggers/critical_events.h>
25 #include <mathematics/chaos.h>
26 #include <structures/object_packers.h>
27
28 #include <openssl/bn.h>
29 #include <openssl/rsa.h>
30
31 using namespace basis;
32 using namespace loggers;
33 using namespace mathematics;
34 using namespace structures;
35
36 namespace crypto {
37
38 // notes from openssl docs: length to be encrypted in a chunk must be less than
39 // RSA_size(rsa) - 11 for the PKCS #1 v1.5 based padding modes, less than
40 // RSA_size(rsa) - 41 for RSA_PKCS1_OAEP_PADDING and exactly RSA_size(rsa)
41 // for RSA_NO_PADDING.
42
43 #undef LOG
44 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
45
46 //nice printing method...  RSA_print_fp(stdout, private_key, 0);
47
48 rsa_crypto::rsa_crypto(int key_size)
49 : _key(NIL)
50 {
51   _key = generate_key(key_size);  // generate_key initializes ssl for us.
52 }
53
54 rsa_crypto::rsa_crypto(const byte_array &key)
55 : _key(NIL)
56 {
57   static_ssl_initializer();
58   byte_array key_copy = key;
59   set_key(key_copy);
60 }
61
62 rsa_crypto::rsa_crypto(rsa_st *key)
63 : _key(NIL)
64 {
65   static_ssl_initializer();
66   set_key(key);
67 }
68
69 rsa_crypto::rsa_crypto(const rsa_crypto &to_copy)
70 : root_object(),
71   _key(NIL)
72 {
73   static_ssl_initializer();
74   set_key(to_copy._key);
75 }
76
77 rsa_crypto::~rsa_crypto()
78 {
79   RSA_free(_key);
80 }
81
82 const rsa_crypto &rsa_crypto::operator = (const rsa_crypto &to_copy)
83 {
84   if (this == &to_copy) return *this;
85   set_key(to_copy._key);
86   return *this;
87 }
88
89 rsa_st *rsa_crypto::generate_key(int key_size)
90 {
91   FUNCDEF("generate_key");
92   if (key_size < 4) key_size = 4;  // laughable lower default.
93   static_ssl_initializer();
94   rsa_st *to_return = RSA_generate_key(key_size, 65537, NIL, NIL);
95   if (!to_return) {
96     continuable_error(static_class_name(), func,
97         a_sprintf("failed to generate a key of %d bits.", key_size));
98   }
99   return to_return;
100 }
101
102 bool rsa_crypto::check_key(rsa_st *key) { return RSA_check_key(key) == 1; }
103
104 bool rsa_crypto::set_key(byte_array &key)
105 {
106   FUNCDEF("set_key [byte_array]");
107   if (!key.length()) return false;
108   if (_key) RSA_free(_key);
109   _key = RSA_new();
110   abyte type;
111   if (!structures::detach(key, type)) return false;
112   if ( (type != 'r') && (type != 'u') ) return false;
113   // get the public key bits first.
114   byte_array n;
115   if (!structures::detach(key, n)) return false;
116   _key->n = BN_bin2bn(n.access(), n.length(), NIL);
117   if (!_key->n) return false;
118   byte_array e;
119   if (!structures::detach(key, e)) return false;
120   _key->e = BN_bin2bn(e.access(), e.length(), NIL);
121   if (!_key->e) return false;
122   if (type == 'u') return true;  // done with public key.
123
124   // the rest is for a private key.
125   byte_array d;
126   if (!structures::detach(key, d)) return false;
127   _key->d = BN_bin2bn(d.access(), d.length(), NIL);
128   if (!_key->d) return false;
129   byte_array p;
130   if (!structures::detach(key, p)) return false;
131   _key->p = BN_bin2bn(p.access(), p.length(), NIL);
132   if (!_key->p) return false;
133   byte_array q;
134   if (!structures::detach(key, q)) return false;
135   _key->q = BN_bin2bn(q.access(), q.length(), NIL);
136   if (!_key->q) return false;
137   byte_array dmp1;
138   if (!structures::detach(key, dmp1)) return false;
139   _key->dmp1 = BN_bin2bn(dmp1.access(), dmp1.length(), NIL);
140   if (!_key->dmp1) return false;
141   byte_array dmq1;
142   if (!structures::detach(key, dmq1)) return false;
143   _key->dmq1 = BN_bin2bn(dmq1.access(), dmq1.length(), NIL);
144   if (!_key->dmq1) return false;
145   byte_array iqmp;
146   if (!structures::detach(key, iqmp)) return false;
147   _key->iqmp = BN_bin2bn(iqmp.access(), iqmp.length(), NIL);
148   if (!_key->iqmp) return false;
149   int check = RSA_check_key(_key);
150   if (check != 1) {
151     continuable_error(static_class_name(), func, "failed to check the private "
152         "portion of the key!");
153     return false;
154   }
155
156   return true;
157 }
158
159 bool rsa_crypto::set_key(rsa_st *key)
160 {
161   FUNCDEF("set_key [rsa_st]");
162   if (!key) return NIL;
163   // test the incoming key.
164   int check = RSA_check_key(key);
165   if (check != 1) return false;
166   // clean out the old key.
167   if (_key) RSA_free(_key);
168   _key = RSAPrivateKey_dup(key);
169   if (!_key) {
170     continuable_error(static_class_name(), func, "failed to create a "
171         "duplicate of the key!");
172     return false;
173   }
174   return true;
175 }
176
177 bool rsa_crypto::public_key(byte_array &pubkey) const
178 {
179 //  FUNCDEF("public_key");
180   if (!_key) return false;
181   structures::attach(pubkey, abyte('u'));  // signal a public key.
182   // convert the two public portions into binary.
183   byte_array n(BN_num_bytes(_key->n));
184   int ret = BN_bn2bin(_key->n, n.access());
185   byte_array e(BN_num_bytes(_key->e));
186   ret = BN_bn2bin(_key->e, e.access());
187   // pack those two chunks.
188   structures::attach(pubkey, n);
189   structures::attach(pubkey, e);
190   return true;
191 }
192
193 bool rsa_crypto::private_key(byte_array &privkey) const
194 {
195 //  FUNCDEF("private_key");
196   if (!_key) return false;
197   int posn = privkey.length();
198   bool worked = public_key(privkey);  // get the public pieces first.
199   if (!worked) return false;
200   privkey[posn] = abyte('r');  // switch public key flag to private.
201   // convert the multiple private portions into binary.
202   byte_array d(BN_num_bytes(_key->d));
203   int ret = BN_bn2bin(_key->d, d.access());
204   byte_array p(BN_num_bytes(_key->p));
205   ret = BN_bn2bin(_key->p, p.access());
206   byte_array q(BN_num_bytes(_key->q));
207   ret = BN_bn2bin(_key->q, q.access());
208   byte_array dmp1(BN_num_bytes(_key->dmp1));
209   ret = BN_bn2bin(_key->dmp1, dmp1.access());
210   byte_array dmq1(BN_num_bytes(_key->dmq1));
211   ret = BN_bn2bin(_key->dmq1, dmq1.access());
212   byte_array iqmp(BN_num_bytes(_key->iqmp));
213   ret = BN_bn2bin(_key->iqmp, iqmp.access());
214   // pack all those in now.
215   structures::attach(privkey, d);
216   structures::attach(privkey, p);
217   structures::attach(privkey, q);
218   structures::attach(privkey, dmp1);
219   structures::attach(privkey, dmq1);
220   structures::attach(privkey, iqmp);
221   return true;
222 }
223
224 bool rsa_crypto::public_encrypt(const byte_array &source,
225     byte_array &target) const
226 {
227 //  FUNCDEF("public_encrypt");
228   target.reset();
229   if (!source.length()) return false;
230   const int max_chunk = RSA_size(_key) - 12;
231
232   byte_array encoded(RSA_size(_key));
233   for (int i = 0; i < source.length(); i += max_chunk) {
234     int edge = i + max_chunk - 1;
235     if (edge > source.last())
236       edge = source.last();
237     int next_chunk = edge - i + 1;
238     RSA_public_encrypt(next_chunk, &source[i],
239         encoded.access(), _key, RSA_PKCS1_PADDING);
240     target += encoded;
241   }
242   return true;
243 }
244
245 bool rsa_crypto::private_decrypt(const byte_array &source,
246     byte_array &target) const
247 {
248 //  FUNCDEF("private_decrypt");
249   target.reset();
250   if (!source.length()) return false;
251   const int max_chunk = RSA_size(_key);
252
253   byte_array decoded(max_chunk);
254   for (int i = 0; i < source.length(); i += max_chunk) {
255     int edge = i + max_chunk - 1;
256     if (edge > source.last())
257       edge = source.last();
258     int next_chunk = edge - i + 1;
259     int dec_size = RSA_private_decrypt(next_chunk, &source[i],
260         decoded.access(), _key, RSA_PKCS1_PADDING);
261     if (dec_size < 0) return false;  // that didn't work.
262     decoded.zap(dec_size, decoded.last());
263     target += decoded;
264     decoded.reset(max_chunk);
265   }
266   return true;
267 }
268
269 bool rsa_crypto::private_encrypt(const byte_array &source,
270     byte_array &target) const
271 {
272 //  FUNCDEF("private_encrypt");
273   target.reset();
274   if (!source.length()) return false;
275   const int max_chunk = RSA_size(_key) - 12;
276
277   byte_array encoded(RSA_size(_key));
278   for (int i = 0; i < source.length(); i += max_chunk) {
279     int edge = i + max_chunk - 1;
280     if (edge > source.last())
281       edge = source.last();
282     int next_chunk = edge - i + 1;
283     RSA_private_encrypt(next_chunk, &source[i],
284         encoded.access(), _key, RSA_PKCS1_PADDING);
285     target += encoded;
286   }
287   return true;
288 }
289
290 bool rsa_crypto::public_decrypt(const byte_array &source,
291     byte_array &target) const
292 {
293 //  FUNCDEF("public_decrypt");
294   target.reset();
295   if (!source.length()) return false;
296   const int max_chunk = RSA_size(_key);
297
298   byte_array decoded(max_chunk);
299   for (int i = 0; i < source.length(); i += max_chunk) {
300     int edge = i + max_chunk - 1;
301     if (edge > source.last())
302       edge = source.last();
303     int next_chunk = edge - i + 1;
304     int dec_size = RSA_public_decrypt(next_chunk, &source[i],
305         decoded.access(), _key, RSA_PKCS1_PADDING);
306     if (dec_size < 0) return false;  // that didn't work.
307     decoded.zap(dec_size, decoded.last());
308     target += decoded;
309     decoded.reset(max_chunk);
310   }
311   return true;
312 }
313
314 } //namespace.
315