I would like to give our users the ability to access to private data using an API.

  • I don't want to store the API credentials in my database. (Same reason I don't store the password in plain in the database.

  • I have no problem that others will be able to read the data that sent to our server.

  • I don't want the credentials to be sent to our server because others will be able to clone the credentials.

  • I do not trust SSL. (Some users may have untrusted root certificates)

  • I want to ensure that if someone has read access to the server, he can't generate new messages on behalf of other client.s

What others did, was using api_key and secret. They used the secret to sign the message. (See Bitfinex for example https://docs.bitfinex.com/v1/docs/rest-auth)

I thought that it is more secure to use RSA. Each user will get a private key (we will not store it). They will use it to encrypt the message (using nonce), We will use a public key to decrypt it.

I know that there are a performance issue with RSA, but it is for very short messages, so it is not concerning me.

Why others not doing it? There is any security issue with it?

  • 1
    "I do not trust SSL. (Some users may have untrusted root certificates)" Don't confuse SSL with the Public CA system. You can issue user credentials from a private root so that you don't need to trust any Public CA. Since you control the server side (which is the relying party in this case), it's irrelevant what roots are installed in your user's system.
    – Lie Ryan
    Jan 10 '18 at 11:15
  • 2
    Do you realize that what you're suggesting is exactly the same thing as TLS+Client authentication exacte you're limiting yourself to RSA? This is clarly a case where you shouldn't try to reinvent the wheel: use TLS and client auth.
    – Stephane
    Jan 10 '18 at 11:18
  • @LieRyan I'm not trusting SSL, because there may be a MITM attack. I will not see the user using untrusted certificate. Jan 10 '18 at 11:42
  • 2
    Its far from clear what you are trying to achieve here. There seems to be elements of assuring confidentiality, providing a way for the client to authenticate the server, and for the server to authenticate the client. But without any explanation of priorities, risks or threat models. Rolling your own solution is almost always the wrong approach.
    – symcbean
    Jan 10 '18 at 12:18
  • @Aminadav MITM attack against TLS will not work when you're using client certificate authentication (unless they can ALSO plant a CA on your server)
    – Stephane
    Jan 10 '18 at 14:31

It is possible to create a secure system this way using RSA, but you're looking for a world of pain and it's likely you'll end up creating an insecure system.

RSA is a very low level cryptographic primitive, it's way too low level for an application developer to work with and using it exposes you to a lot of vulnerabilities if not used correctly. Leave writing cryptographic code to the experts and use higher level cryptography, either TLS or OpenPGP should be the level that you're looking at, not RSA.

I know that there are a performance issue with RSA, but it is for very short messages, so it is not concerning me.

The issue with RSA isn't just performance. RSA cannot be used to encrypt data larger than the key size minus any paddings, which means that a 2048-bit RSA key has a maximum input size of 256 bytes (or 245 bytes if you use v1.5 padding). This means that if you want to encrypt data larger than this size, you need to implement a chaining mode, and chaining mode is one of the most easy things to get wrong when implementing cryptography. Additionally nobody had ever implemented or does any cryptoanalysis on RSA chaining mode (most chaining mode are analysed for symmetric ciphers), so you are on your own there.

Another problem is that all cryptographic primitives eventually need to be replaced as computers get stronger and vulnerabilities are find in these primitives. Therefore, all practical cryptography applications need to add metadata that allow negotiation and replacement of the encryption primitives and its parameters. TLS, S/MIME, OpenPGP, and the crypt password hash format all have this capability built into the protocol. This is also another aspect that's easy to get wrong.

Another issue that plain RSA doesn't do is replay prevention. For this, you need to add a salt or IV, and possibly a challenge. And the order you layer signing and encryption also comes with their own pitfalls.

I could go all days explaining the various pitfalls if you're trying to use plain RSA to implement any cryptography system.

High level protocols like OpenPGP and TLS uses RSA as the underlying primitive but when you use a high level cryptographic protocols, those issues have been thought out for you by expert cryptographers and their implementations have been highly scrutinized as well. All the remaining issues are either resolved or it's fairly easy to configure the system when there's a trade off.

OpenPGP in particular have a signing mode, which effectively does what you mentioned, using private key to sign a data to prove authorship, though in more sophisticated ways. An OpenPGP signature is created by encrypting a hash of the message rather than the message itself, thus avoiding the need to do chaining and it adds a number of metadata to protect against various attacks. TLS have similar properties during handshake if you use Mutual Authentication but they are implicit in the connection, so it may not be suitable if you want to store and/or forward the proof of authorship to another entity.

TL;DR Don't roll your own cryptography. If you need to persist the proof of authorship, use OpenPGP signature; otherwise just wrap the communication in TLS using Mutual Authentication.

Why others not doing it? There is any security issue with it?

Because it's stupidly complicated to get it right, when you can just use TLS mutual authentication with just a few lines of code. Unless your scheme is going to be as massively scrutinized as TLS and OpenPGP, I can assure you your scheme will have weaknesses you would have practically no chance to discover.


We will use a public key to decrypt it.

What you propose is to switch the meaning of private and public within an RSA key pair. The public key is considered public since knowledge of it by an attacker is not a security issue. But, since you propose to encrypt with the private key and decrypt with the public key the latter one is actually the one which need to be protected - i.e. your public key need to be kept private while the associated private key could actually be published.

In other words: an attacker which gets access to the server can decrypt any messages which are sent to the server by only using information found on the server (i.e. your "public" keys). And this is exactly what you've tried to prevent in the first place.

  • I have no problem, that people will be able to read data that sent to the server. I have a problem if someone can use this data to access the server. Because the private key never leaves the client computer, a hacker will not be able to create a new message using the public key. Jan 10 '18 at 11:40
  • 1
    @Aminadav: if all you need is authenticating the client - then why not use established signatures? This is similar to encryption with private key (at least for RSA). Note that the client should better sign a challenge sent by the server (and not the API key) so that no replay is possible. Jan 10 '18 at 12:29

Not the answer you're looking for? Browse other questions tagged or ask your own question.