00001
00002
00003
00004
00005
00006
00007 #include <assert.h>
00008 #include <openssl/rsa.h>
00009 #include <openssl/pem.h>
00010 #include "wvsslhacks.h"
00011 #include "wvrsa.h"
00012 #include "wvhex.h"
00013 #include "wvfileutils.h"
00014
00015
00016
00017 WvRSAKey::WvRSAKey(const WvRSAKey &k)
00018 {
00019 if (k.prv)
00020 init(k.private_str(), true);
00021 else
00022 init(k.public_str(), false);
00023 }
00024
00025
00026 WvRSAKey::WvRSAKey(struct rsa_st *_rsa, bool priv)
00027 {
00028 if (_rsa == NULL)
00029 {
00030
00031 pub = WvString::null;
00032 prv = WvString::null;
00033 rsa = NULL;
00034 seterr("Initializing with a NULL key.. are you insane?");
00035 return;
00036 }
00037
00038 rsa = _rsa;
00039 pub = hexifypub(rsa);
00040 if (priv)
00041 prv = hexifyprv(rsa);
00042 }
00043
00044
00045 WvRSAKey::WvRSAKey(WvStringParm keystr, bool priv)
00046 {
00047 init(keystr, priv);
00048 }
00049
00050
00051 WvRSAKey::WvRSAKey(int bits)
00052 {
00053 rsa = RSA_generate_key(bits, 0x10001, NULL, NULL);
00054 pub = hexifypub(rsa);
00055 prv = hexifyprv(rsa);
00056 }
00057
00058
00059 WvRSAKey::~WvRSAKey()
00060 {
00061 if (rsa)
00062 RSA_free(rsa);
00063 }
00064
00065
00066 bool WvRSAKey::isok() const
00067 {
00068 return rsa && !errstring && (!prv || RSA_check_key(rsa) == 1);
00069 }
00070
00071
00072 void WvRSAKey::init(WvStringParm keystr, bool priv)
00073 {
00074
00075 rsa = NULL;
00076 pub = WvString::null;
00077 prv = WvString::null;
00078
00079
00080 WvDynBuf keybuf;
00081 if (!WvHexDecoder().flushstrbuf(keystr, keybuf, true) ||
00082 keybuf.used() == 0)
00083 {
00084 seterr("RSA key is not a valid hex string");
00085 return;
00086 }
00087
00088 size_t keylen = keybuf.used();
00089 const unsigned char *key = keybuf.get(keylen);
00090
00091
00092 if (priv)
00093 {
00094 rsa = wv_d2i_RSAPrivateKey(NULL, &key, keylen);
00095 if (rsa != NULL)
00096 {
00097 prv = keystr;
00098 pub = hexifypub(rsa);
00099 }
00100 }
00101 else
00102 {
00103 rsa = wv_d2i_RSAPublicKey(NULL, &key, keylen);
00104 if (rsa != NULL)
00105 {
00106 prv = WvString::null;
00107 pub = keystr;
00108 }
00109 }
00110 if (rsa == NULL)
00111 seterr("RSA key is invalid");
00112 }
00113
00114
00115
00116 WvString WvRSAKey::getpem(bool privkey)
00117 {
00118 FILE *fp = wvtmpfile();
00119 const EVP_CIPHER *enc;
00120
00121 if (!fp)
00122 {
00123 seterr("Unable to open temporary file!");
00124 return WvString::null;
00125 }
00126
00127 if (privkey)
00128 {
00129 enc = EVP_get_cipherbyname("rsa");
00130 PEM_write_RSAPrivateKey(fp, rsa, enc,
00131 NULL, 0, NULL, NULL);
00132 }
00133 else
00134 {
00135 enc = EVP_get_cipherbyname("rsa");
00136 PEM_write_RSAPublicKey(fp, rsa);
00137 }
00138
00139 WvDynBuf b;
00140 size_t len;
00141
00142 rewind(fp);
00143 while ((len = fread(b.alloc(1024), 1, 1024, fp)) > 0)
00144 b.unalloc(1024 - len);
00145 b.unalloc(1024 - len);
00146 fclose(fp);
00147
00148 return b.getstr();
00149 }
00150
00151
00152
00153 WvString WvRSAKey::hexifypub(struct rsa_st *rsa)
00154 {
00155 WvDynBuf keybuf;
00156
00157 assert(rsa);
00158
00159 size_t size = i2d_RSAPublicKey(rsa, NULL);
00160 unsigned char *key = keybuf.alloc(size);
00161 size_t newsize = i2d_RSAPublicKey(rsa, & key);
00162 assert(size == newsize);
00163 assert(keybuf.used() == size);
00164
00165 return WvString(WvHexEncoder().strflushbuf(keybuf, true));
00166 }
00167
00168
00169 WvString WvRSAKey::hexifyprv(struct rsa_st *rsa)
00170 {
00171 WvDynBuf keybuf;
00172
00173 assert(rsa);
00174
00175 size_t size = i2d_RSAPrivateKey(rsa, NULL);
00176 unsigned char *key = keybuf.alloc(size);
00177 size_t newsize = i2d_RSAPrivateKey(rsa, & key);
00178 assert(size == newsize);
00179
00180 return WvString(WvHexEncoder().strflushbuf(keybuf, true));
00181 }
00182
00183
00184
00185
00186 WvRSAEncoder::WvRSAEncoder(Mode _mode, const WvRSAKey & _key) :
00187 mode(_mode), key(_key)
00188 {
00189 if (key.isok() && key.rsa != NULL)
00190 rsasize = RSA_size(key.rsa);
00191 else
00192 rsasize = 0;
00193 }
00194
00195
00196 WvRSAEncoder::~WvRSAEncoder()
00197 {
00198 }
00199
00200
00201 bool WvRSAEncoder::_reset()
00202 {
00203 return true;
00204 }
00205
00206
00207 bool WvRSAEncoder::_encode(WvBuf &in, WvBuf &out, bool flush)
00208 {
00209 if (rsasize == 0)
00210 {
00211
00212 in.zap();
00213 return false;
00214 }
00215
00216 bool success = true;
00217 switch (mode)
00218 {
00219 case Encrypt:
00220 case SignEncrypt:
00221 {
00222
00223 const size_t maxchunklen = rsasize - 12;
00224 size_t chunklen;
00225 while ((chunklen = in.used()) != 0)
00226 {
00227 if (chunklen >= maxchunklen)
00228 chunklen = maxchunklen;
00229 else if (! flush)
00230 break;
00231
00232
00233 const unsigned char *data = in.get(chunklen);
00234 unsigned char *crypt = out.alloc(rsasize);
00235 size_t cryptlen = (mode == Encrypt) ?
00236 RSA_public_encrypt(chunklen,
00237 const_cast<unsigned char*>(data), crypt,
00238 key.rsa, RSA_PKCS1_PADDING) :
00239 RSA_private_encrypt(chunklen,
00240 const_cast<unsigned char*>(data), crypt,
00241 key.rsa, RSA_PKCS1_PADDING);
00242 if (cryptlen != rsasize)
00243 {
00244 out.unalloc(rsasize);
00245 success = false;
00246 }
00247 }
00248 break;
00249 }
00250 case Decrypt:
00251 case SignDecrypt:
00252 {
00253 const size_t chunklen = rsasize;
00254 while (in.used() >= chunklen)
00255 {
00256
00257 const unsigned char *crypt = in.get(chunklen);
00258 unsigned char *data = out.alloc(rsasize);
00259 int cryptlen = (mode == Decrypt) ?
00260 RSA_private_decrypt(chunklen,
00261 const_cast<unsigned char*>(crypt), data,
00262 key.rsa, RSA_PKCS1_PADDING) :
00263 RSA_public_decrypt(chunklen,
00264 const_cast<unsigned char*>(crypt), data,
00265 key.rsa, RSA_PKCS1_PADDING);
00266 if (cryptlen == -1)
00267 {
00268 out.unalloc(rsasize);
00269 success = false;
00270 }
00271 else
00272 out.unalloc(rsasize - cryptlen);
00273 }
00274
00275 if (flush && in.used() != 0)
00276 success = false;
00277 break;
00278 }
00279 }
00280 return success;
00281 }
00282
00283
00284
00285
00286 WvRSAStream::WvRSAStream(WvStream *_cloned,
00287 const WvRSAKey &_my_key, const WvRSAKey &_their_key,
00288 WvRSAEncoder::Mode readmode, WvRSAEncoder::Mode writemode) :
00289 WvEncoderStream(_cloned)
00290 {
00291 readchain.append(new WvRSAEncoder(readmode, _my_key), true);
00292 writechain.append(new WvRSAEncoder(writemode, _their_key), true);
00293 if (_my_key.isok() && _my_key.rsa)
00294 min_readsize = RSA_size(_my_key.rsa);
00295 }