2

I am developing an android application which needs to communicate with a web server. Instead of using common SSL I would like to save my custom public key in resource folders of the application(APK installation file) so before starting sending or receiving data to the device, first server asks for a secret shared key from device which is encrypted via public key. Is man in the attack possible in this scenario?

Update: The method which I want to use is called "certificate pinning" and is common is some use cases. https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning

Ali
  • 21
  • 3

3 Answers3

1

What you are asking is basically redefining the "common SSL". However, you are basing trust on the server only, whereas in SSL the trust is delegated to a third party. Moreover, in SSL certificates are signed, therefore you can verify their authenticity.

So yes, the scenario will be able to prevent MitM attack (in a way), but the user loses some trust in the process (compared to SSL) because:

  • there is no more verification of the key
  • there is no one to vouch for your identity as a certification authority would do

A scenario that could be devised to perform MitM would be someone tampering with the APK to change the public key to replace it with another he has control on. This is probably not technically easy but not impossible either.

Finally, you would be better using a recent version of the SSL/TLS suite rather than developing your own protocol.

M'vy
  • 13,033
  • 3
  • 47
  • 69
  • As mentioned as a comment to the original question by @Stephane certificate pinning basically lets you hard-code the public key in the application for use trough TLS/SSL. Which gives you the benefit of using TLS-libraries while hard-coding which key that should be acceptet. See more on https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning – vidar Apr 20 '15 at 13:37
1

You're overcomplicating things and reducing security for no reason. Do use SSL¹ — why on earth would you not use it? The whole point of SSL is to avoid MitM attacks.

If I understand your protocol correctly:

  1. When the application is installed, it sets up a per-device secret key which it shares with the server. You haven't said how — are you going to use SSL there?
    Note that you need a per-device shared secret, otherwise anyone with a copy of your application can impersonate every other user of the application.
  2. When the client application starts a connection to the server, it sends the shared secret to the server, encrypted with a public key for which the server knows the public key. The server authenticates the client device by checking that the secret is the right one. The secret isn't in fact used as a key here, but as a password.
  3. The rest of the connection needs to be encrypted and authenticated, otherwise the MitM can relay the first packets in the connection unmodified and snoop or modify the rest. You still need to devise a protocol for that part. You can use the shared secret as an encryption and authentication key (don't forget authentication!).

SSL does this all better.

  1. There is no need to exchange secret keys. The client verifies that it's talking to the expected server by verifying the server's certificate: either the server's public key is hard-coded in the application package (pinned certificate), or the server's name is hard-coded in the application package and the application (via the OS libraries) verifies that the server presents a valid certificate that ties its public key with that name.
    No man-in-the-middle attack is possible because the SSL protocol requires that the server proves to the client that it possesses the private key associated with its certificate. A MitM would not be able to respond to this challenge, so the client would detect the attack.
  2. In many uses of SSL, the server doesn't care which client connects to it. If you do want the server to authenticate the client, there's an optional feature in SSL for that: client authentication. Generate a key pair on the client side, and have it enroll the public key on the server.
  3. The rest of the connection is properly encrypted and authenticated. SSL even gives you the option of choosing a cipher suite that guarantees forward secrecy (an adversary will not be able to recover the session key and thus decrypt the traffic if they compromise either participant after the session is over, at the cost of a slightly slower connection establishment).

¹ By “SSL”, I mean a non-deprecated version of the protocol — that's TLS 1.0 or above. Any current library version should use TLS 1.0 or above by default nowadays, just make sure you aren't using it in an SSL ≤3.0 backward compatibility mode.

Gilles 'SO- stop being evil'
  • 50,912
  • 13
  • 120
  • 179
1

What you're suggesting is completely compatible with the Android TLS framework.

When you create a connection to a remote server, you can specify your own trusted CA list. This means that instead of using the default CA store trusted by the OS, for this connection you trust only certificates signed by the CAs you specify, which don't need to be known to anyone else.

Likewise, you can ship client certificates which will be requested by, and verified by the server upon connection. This is all part of the spec, so nothing you want to do needs to be custom-implemented. You can rely on established and tested protocols and code.

If connections to your service will only be made by clients you ship, then this is actually a well-established best-practice. There's no reason to get your certificates signed by a globally trusted CA if you're the only one who will be trusting them, and there's no reason to trust the common CAs if you know your certificate will not be signed by them.

Again, use the built-in stuff. Rule number one of crypto is don't build your own. It won't go well if you do.

tylerl
  • 82,225
  • 25
  • 148
  • 226