Secure and efficient encryption of a continuous data stream on behalf of a third party using asymmetric cryptography I want to design an API-based system that is able to securely encrypt a stream of data received on behalf of an external user in such a way that the data can only be decrypted using a secret that only the user knows (i.e. after encrypting the data, the server itself would not be able to decrypt it again). Naturally, my first thought was to use asymmetric cryptography for this: 


The server would generate a private/public key pair (e.g. using RSA)
The private key would be securely handed to the user and erased from the server, the public key would be stored on the server.
When new data arrives for the user, the server would generate a random key for a symmetric encryption scheme (e.g. AES) and use this key to encrypt the data. It would then use the users public key to encrypt the symmetric key and store it together with the data on the server.
The user could then decrypt the data by downloading the encrypted data with the corresponding encrypted symmetric keys, decrypting the symmetric keys using his/her private key and finally decrypting the data using the decrypted symmetric keys.


The main challenge is that the data which is received on behalf of the user consists of many small packages that arrive continuously over time. In order to encrypt them following this scheme it would thus be necessary to generate and encrypt a new symmetric key each time a new data package arrives, which is doable. However, the decryption of the data could become very inefficient, as the decryption of an RSA-2048 encrypted message can take several milliseconds on modern hardware, so if there are many thousands or even millions of messages for a single user, their decryption could take hours.

I therefore have two questions:


Is this a reasonable scheme? If now, which elements are missing or would be advisable to implement in addition (HMAC, signing, ...)?
Is there any way to increase the efficiency of the decryption process, preferably one that does not involve storing the symmetric key on the server over an extended period (which would be a security risk)?


Edit

The user does not upload the data, it is generated by a third-party on behalf of the user. The motivation behind the scheme is to provide the third party with a secure, asynchronous channel to store data that a user could securely pick up at a later point in time. The assumption is that the third party is not able or willing to provide the infrastructure for this by themselves and instead want to use an external service.
$\DeclareMathOperator{\X}{X25519}\DeclareMathOperator{\H}{HSalsa20}$Here is a candidate protocol.

I have amended the obviously insensible criterion of having the server hand the user a secret key.  Since you haven't identified your specific performance constraints—how many CPU cycles, nanoseconds, or joules are available in your budget for cryptography per data record, on average and/or in the worst case, for the user and the server?—I picked a widely available, widely accepted composition of specific cryptographic primitives: NaCl crypto_box_curve25519xsalsa20poly1305.

Setup.
The user generates an X25519 secret $u$ and public key $U = \X(u, \underline{9})$, using NaCl crypto_box_keypair, and configures server with $U$.

Data arrival.
On receipt of a set $\{d_0, d_1, \dots, d_{n-1}\}$ of $n$ data records of bounded length at time $t$, the server


generates an X25519 secret $s_t$ and a public key $S_t = \X(s_t, \underline{9})$ using NaCl crypto_box_keypair;
computes the shared secret $k_t = \H(\X(s_t, U))$ using NaCl crypto_box_beforenm;
authenticates and encrypts each record $d_i$ with XSalsa20-Poly1305 under key $k_t$ and nonce $i$ giving authenticated ciphertext $c_i$ using NaCl crypto_box_afternm;
transmits $(S_t, i, c_i)$ to the user for each $i$, which adds 32 + 8 + 16 = 56 bytes of overhead per message; and
erases $k_t$, $s_t$, and each $d_i$.


Data usage.
On receipt of a tuple $(S_t', i', c_i')$, the user


retrieves a cached shared secret $k_t'$ for public key $S_t'$, or computes the shared secret $k_t' = \H(\X(u, S_t'))$ using NaCl crypto_box_beforenm and caches it for subsequent records with $S_t'$;
verifies and decrypts the ciphertext $c_i'$ with XSalsa20-Poly1305 under key $k_t'$ and nonce $i'$—or rejects it if a forgery—giving record $d_i'$ if not forged, using crypto_box_open_afternm; and
processes the record $d_i'$.


(The prime marks are a reminder that what the user receives may be a forgery, not what the server transmitted.  The standard adversary can of course generate their own public key altogether and forge messages using that with wild abandon, but can't selectively modify messages transmitted by the server.  See the caveats below.)

Cost.
The main cost is the $\X(a, B)$ calculation, which is very roughly about half a million CPU cycles on typical widely available hardware, or half a millisecond at 1 GHz.  See https://bench.cr.yp.to/impl-dh/curve25519.html for more detailed measurements on specific hardware, and https://bench.cr.yp.to/results-dh.html for comparison of different DH functions (warning: not all DH functions listed there have the same security level or defense against side channel attacks).

Sharing the key between multiple data records, and caching it when processing nearby data records, may significantly reduce the time and/or energy cost—under certain usage patterns.

Can the server work on records in batches, or must it lose its ability to decrypt each individual record the moment it transmits that record to the user?  If the largest batch of records the server can sensibly ingest is $n = 1$, then you can simplify the protocol but there's no faster option short of picking a different DH function or KEM, which will invariably be less widely adopted, such as FourQ.  But if the server can work on larger batches, then it can save time and/or energy by reusing each shared secret for multiple records.

If the server can work in batches, does the user process nearby records together, or are the access patterns uniformly distributed?  If the user processes nearby records, then the user can save time and/or energy by caching the shared secrets in a memo table and skipping X25519 computations.

Note that if the user processes records strictly sequentially, then you can save much more time and energy by eliding the public-key business altogether with a method left as an exercise for the reader.

Caveats.


Don't use the same key material for anything else.  If you are tempted to do so, study domain separation.
The standard adversary—who can adaptively control the data and control the channel from server to user—can't decrypt records or partially modify records, but can forge completely new records, and can block records of their choice, and can waste the user's memory up to the longest data record size by transmitting an attempted forgery of that size.  It is left as an exercise for the reader to identify exactly what potentially relevant security properties this protocol does and doesn't provide.


Payment.
Please send payment for this cryptography engineering consulting work to


  Mx. Squeamish Ossifrage
  Room 641A
  521 Mersenne Curve
  Anytown, ST 25519
  Untied Steaks of Armorica