+ /*
+ * RSA is vulnerable to timing attacks. Generate a random blinding
+ * factor to protect against this kind of attack.
+ */
+ ret = -E_BLINDING;
+ if (RSA_blinding_on(priv->rsa, NULL) == 0)
+ goto out;
+ ret = RSA_private_decrypt(inlen, inbuf, outbuf, priv->rsa,
+ RSA_PKCS1_OAEP_PADDING);
+ RSA_blinding_off(priv->rsa);
+ if (ret <= 0)
+ ret = -E_DECRYPT;
+out:
+ free_asymmetric_key(priv);
+ return ret;
+}
+
+int pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf,
+ unsigned len, unsigned char *outbuf)
+{
+ int ret, flen = len; /* RSA_public_encrypt expects a signed int */
+
+ if (flen < 0)
+ return -E_ENCRYPT;
+ ret = RSA_public_encrypt(flen, inbuf, outbuf, pub->rsa,
+ RSA_PKCS1_OAEP_PADDING);
+ return ret < 0? -E_ENCRYPT : ret;
+}
+
+struct stream_cipher {
+ bool use_aes;
+ union {
+ RC4_KEY rc4_key;
+ EVP_CIPHER_CTX *aes;
+ } context;
+};
+
+struct stream_cipher *sc_new(const unsigned char *data, int len,
+ bool use_aes)
+{
+ struct stream_cipher *sc = para_malloc(sizeof(*sc));
+
+ sc->use_aes = use_aes;
+ if (!use_aes) {
+ RC4_set_key(&sc->context.rc4_key, len, data);
+ return sc;
+ }
+ assert(len >= 2 * AES_CRT128_BLOCK_SIZE);
+ sc->context.aes = EVP_CIPHER_CTX_new();
+ EVP_EncryptInit_ex(sc->context.aes, EVP_aes_128_ctr(), NULL, data,
+ data + AES_CRT128_BLOCK_SIZE);
+ return sc;
+}
+
+void sc_free(struct stream_cipher *sc)
+{
+ if (!sc)
+ return;
+ EVP_CIPHER_CTX_free(sc->context.aes);
+ free(sc);