2 * Worldvisions Tunnel Vision Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
5 * RSA cryptography abstractions.
8 #include <openssl/rsa.h>
9 #include <openssl/pem.h>
10 #include "wvsslhacks.h"
13 #include "wvfileutils.h"
15 /***** WvRSAKey *****/
18 : debug("RSA", WvLog::Debug5
)
24 WvRSAKey::WvRSAKey(const WvRSAKey
&k
)
25 : debug("RSA", WvLog::Debug5
)
30 rsa
= RSAPublicKey_dup(k
.rsa
);
32 rsa
= RSAPrivateKey_dup(k
.rsa
);
36 WvRSAKey::WvRSAKey(struct rsa_st
*_rsa
, bool _priv
)
37 : debug("RSA", WvLog::Debug5
)
42 debug("Initializing with a NULL key.. are you insane?\n");
51 WvRSAKey::WvRSAKey(WvStringParm keystr
, bool _priv
)
52 : debug("RSA", WvLog::Debug5
)
57 decode(RsaHex
, keystr
);
59 decode(RsaPubHex
, keystr
);
65 WvRSAKey::WvRSAKey(int bits
)
66 : debug("RSA", WvLog::Debug5
)
68 rsa
= RSA_generate_key(bits
, 0x10001, NULL
, NULL
);
80 bool WvRSAKey::isok() const
82 return rsa
&& (!priv
|| RSA_check_key(rsa
) == 1);
86 WvString
WvRSAKey::encode(const DumpMode mode
) const
91 return retval
.getstr();
95 void WvRSAKey::encode(const DumpMode mode
, WvBuf
&buf
) const
99 debug(WvLog::Warning
, "Tried to encode RSA key, but RSA key is "
104 if (mode
== RsaHex
|| mode
== RsaPubHex
)
108 if (mode
== RsaHex
&& priv
)
110 size_t size
= i2d_RSAPrivateKey(rsa
, NULL
);
111 unsigned char *key
= keybuf
.alloc(size
);
112 size_t newsize
= i2d_RSAPrivateKey(rsa
, & key
);
113 assert(size
== newsize
);
117 size_t size
= i2d_RSAPublicKey(rsa
, NULL
);
118 unsigned char *key
= keybuf
.alloc(size
);
119 size_t newsize
= i2d_RSAPublicKey(rsa
, & key
);
120 assert(size
== newsize
);
123 buf
.putstr(WvString(WvHexEncoder().strflushbuf(keybuf
, true)));
127 BIO
*bufbio
= BIO_new(BIO_s_mem());
129 const EVP_CIPHER
*enc
= EVP_get_cipherbyname("rsa");
132 PEM_write_bio_RSAPrivateKey(bufbio
, rsa
, enc
,
133 NULL
, 0, NULL
, NULL
);
134 else if (mode
== RsaPubPEM
)
135 PEM_write_bio_RSAPublicKey(bufbio
, rsa
);
137 debug(WvLog::Warning
, "Should never happen: tried to encode RSA "
138 "key with unsupported mode.");
140 BIO_get_mem_ptr(bufbio
, &bm
);
141 buf
.put(bm
->data
, bm
->length
);
147 void WvRSAKey::decode(const DumpMode mode
, WvStringParm encoded
)
158 void WvRSAKey::decode(const DumpMode mode
, WvBuf
&encoded
)
160 debug("Decoding RSA key.\n");
164 debug("Replacing already existent RSA key.\n");
170 // we handle hexified keys a bit differently, since
171 // OpenSSL has no built-in support for them...
172 if (mode
== RsaHex
|| mode
== RsaPubHex
)
174 // unhexify the supplied key
176 if (!WvHexDecoder().flush(encoded
, keybuf
, true) ||
179 debug("Couldn't unhexify RSA key.\n");
183 size_t keylen
= keybuf
.used();
184 const unsigned char *key
= keybuf
.get(keylen
);
186 // create the RSA struct
189 rsa
= wv_d2i_RSAPrivateKey(NULL
, &key
, keylen
);
193 rsa
= wv_d2i_RSAPublicKey(NULL
, &key
, keylen
);
200 BIO
*membuf
= BIO_new(BIO_s_mem());
201 BIO_write(membuf
, encoded
.get(encoded
.used()), encoded
.used());
205 rsa
= PEM_read_bio_RSAPrivateKey(membuf
, NULL
, NULL
, NULL
);
208 else if (mode
== RsaPubPEM
)
209 rsa
= PEM_read_bio_RSAPublicKey(membuf
, NULL
, NULL
, NULL
);
211 debug(WvLog::Warning
, "Should never happen: tried to encode RSA "
212 "key with unsupported mode.");
214 BIO_free_all(membuf
);
219 /***** WvRSAEncoder *****/
221 WvRSAEncoder::WvRSAEncoder(Mode _mode
, const WvRSAKey
& _key
) :
222 mode(_mode
), key(_key
)
224 if (key
.isok() && key
.rsa
!= NULL
)
225 rsasize
= RSA_size(key
.rsa
);
227 rsasize
= 0; // BAD KEY! (should assert but would break compatibility)
231 WvRSAEncoder::~WvRSAEncoder()
236 bool WvRSAEncoder::_reset()
242 bool WvRSAEncoder::_encode(WvBuf
&in
, WvBuf
&out
, bool flush
)
257 // reserve space for PKCS1_PADDING
258 const size_t maxchunklen
= rsasize
- 12;
260 while ((chunklen
= in
.used()) != 0)
262 if (chunklen
>= maxchunklen
)
263 chunklen
= maxchunklen
;
268 const unsigned char *data
= in
.get(chunklen
);
269 unsigned char *crypt
= out
.alloc(rsasize
);
270 size_t cryptlen
= (mode
== Encrypt
) ?
271 RSA_public_encrypt(chunklen
,
272 const_cast<unsigned char*>(data
), crypt
,
273 key
.rsa
, RSA_PKCS1_PADDING
) :
274 RSA_private_encrypt(chunklen
,
275 const_cast<unsigned char*>(data
), crypt
,
276 key
.rsa
, RSA_PKCS1_PADDING
);
277 if (cryptlen
!= rsasize
)
279 out
.unalloc(rsasize
);
288 const size_t chunklen
= rsasize
;
289 while (in
.used() >= chunklen
)
292 const unsigned char *crypt
= in
.get(chunklen
);
293 unsigned char *data
= out
.alloc(rsasize
);
294 int cryptlen
= (mode
== Decrypt
) ?
295 RSA_private_decrypt(chunklen
,
296 const_cast<unsigned char*>(crypt
), data
,
297 key
.rsa
, RSA_PKCS1_PADDING
) :
298 RSA_public_decrypt(chunklen
,
299 const_cast<unsigned char*>(crypt
), data
,
300 key
.rsa
, RSA_PKCS1_PADDING
);
303 out
.unalloc(rsasize
);
307 out
.unalloc(rsasize
- cryptlen
);
309 // flush does not make sense for us here
310 if (flush
&& in
.used() != 0)
319 /***** WvRSAStream *****/
321 WvRSAStream::WvRSAStream(WvStream
*_cloned
,
322 const WvRSAKey
&_my_key
, const WvRSAKey
&_their_key
,
323 WvRSAEncoder::Mode readmode
, WvRSAEncoder::Mode writemode
) :
324 WvEncoderStream(_cloned
)
326 readchain
.append(new WvRSAEncoder(readmode
, _my_key
), true);
327 writechain
.append(new WvRSAEncoder(writemode
, _their_key
), true);
328 if (_my_key
.isok() && _my_key
.rsa
)
329 min_readsize
= RSA_size(_my_key
.rsa
);