Encryption and authentication for client-server application where clients are known - java

I want to write a secure client-server application where only a few (say, five) clients exchange data with a server via TCP sockets. All clients are known in advance and off-line sharing of keys etc. is possible.
I want three things:
The clients need to be sure they talk to the right server
The server needs to be sure it only talks to these five clients
The communication needs to be encrypted
How should such a setup be realized?
My first thought was SSL/TLS enabled sockets, but after thinking about it for some time, I feel the exchange of keys in the handshake is something I don't really need. Also, the whole certificate authority business that needs to be worked around for self-signed certificates seems out of place.
Another options seems to be to do regular socket communication, and carry out encryption/decryption and signing on both ends. Similar to a gpg-based e-mail setup, I could create key pairs for the server and each client, and make sure the server has all public keys of all clients and each client has the server's public key. Because I can copy files locally to each machine, this key exchange can be assumed to be secure.
Or should I even just use symmetric encryption, with a single secret key known to all clients and the server?
Almost everything I could find on the web was about the "classical" setup where the server authenticates itself to many arbitrary clients, via a certification authority, i.e., HTTPS-like setups.
I plan to write it in Java, but actually I think my question is language-independent.

I suggest you to use TLS. It contains a lot of so called cipher suites, which are predefined combinations of included cryptographic algorithms, and they ensure peer authentication, asymmetric key exchange, symmetric encryption and message authentication. They are battle-tested in the real world.
Using certificates:
Create a self-signed CA cert and sign all clients and server certs with it.
Configure them to accept only opposite parties authenticated with cert signed by your CA.
Or, if you are uneasy with certificates, there are also cipher suites which uses preshared key authentication (look for PSK and SRP).

Related

Securely transmitting password over TCP Socket in Java

I want to write a secure method of authentication over TCP sockets in Java. I've read reasonably extensively on the subject, but I am by no means an expert. There seems to be a bit of variance in opinion on how this is best done.
I know pretty well had to generate my password hashes, but that doesn't do me a whole lot of good if an attacker can simply glean the passwords/password hashes while in transit. So I want to create a reasonably secure method of sending this data across.
The most popular method seems to be using SSL sockets. However, my code will not be used as a single server (as an online game might be) but instead will have many instances run by various consumers. I personally don't have a means to purchase an SSL certificate, and I can't really ask my consumers to do that either. Creating self-signed certificates and then installing them in a keystore for each client seems both difficult and a little insecure. If I were handling all server instances, this would be a much more viable option, since I would only need one certificate, but as it stands now
So I worked on simply securing the TCP socket while performing log ins. I can do this pretty well using a Diffie-Hellman algorithm. However, as I research this, people kept saying to use SSL instead.
How can I securely transmit passwords over Java TCP sockets in an efficient but portable manner?
You can use the Diffie-Hellman key exchange algorithm. This is exactly for your use case, to exchange keys over a public network. See the Oracle Diffie-Hellman example.
Have you considered RSA encryption? RSA encryption is the same encryption that SSL uses:
https://en.wikipedia.org/wiki/RSA_(cryptosystem)

JSSE SSL: Get algorithm that is used for encryption and Integrity

I'm using Java JSSE SSL to implement a simple secure application. Every thing is working fine. But SSL negotiate algorithm between client and server and they choose algorithms that they support, I dont know which algorithm they chosen. I just need to know:
For Authentication:
- Which algorithm client and server have chosen, for example, Diffie-Hellman.
Is there away also to force client and server to use certain algorithm.
For Integrity (hashing):
- Which algorithm client and server have chosen, for example, SHA-1.
Is there away also to force client and server to use certain algorithm.
For Confidentiality (encryption):
- Which algorithm client and server have chosen, for example, DES.
Is there away also to force client and server to use certain algorithm.
All these things are specified in the various parts of the cipher suite name, which you can get via the SSLSession. You can affect which cipher suites are enabled via SSLSocket.setEnabledCipherSuites(), but only if the peer has those ones enabled as well. In general it's not a good idea to do this. Typically the cipher suites are restricted at the server only.

Do Java SSLSockets require a supplied SSL Certificate?

In HTTPS technology, an SSL certificate is required for a secure connection. This certificate must be acquired through self-generation, or through a certificate authority (CA).
In Java, an SSLSocket to SSLSocket connection promises the same security as an HTTPS connection (No man-in-the-middle, encryption, etc).
When connecting two SSLSockets instantiated in two separate, stand-alone Java programs (One client, one server), is it necessary to supply Java (The server) with a valid certificate?
What are the methods used to specify which certificate to use? The documentation doesn't seem to have anything to say about this.
I'm talking about pure Java here. I'm not talking about using Java to connect to a web service via HTTPS.
The purpose of these sockets is to send user names and passwords from one Java application (The client) to another (The server) for identity verification purposes, so it is imperative that they are as secure as possible.
When connecting two SSLSockets instantiated in two separate, stand-alone Java programs (One client, one server), is it necessary to supply Java (The server) with a valid certificate?
In normal usage the server (the end with the SSLServerSocket) needs a certificate that is trusted by the peer.
The client only needs a certificate if the server is configured to require it, which is not the default.
What are the methods used to specify which certificate to use? The documentation doesn't seem to have anything to say about this.
See the JSSE Reference Guide. You can do this via system properties. You can also write a foot or so of code, but it isn't necessary.
If you want to have a secure encryption you need to have either a pre-shared key only known to both parties or you have to do some kind of key exchange to compute the encryption key. Key Exchange requires proper identification, otherwise a man-in-the-middle attack would be possible and you would not have secure end-to-end encryption anymore.
For use of pre-shared key look out for TLS-PSK. When googling for it it looks like that there are some hits for Android implementations but mostly it is people asking if it is possible. It might be possible to do this with the alternative SSL implementation BouncyCastle.
If not using PSK you might try to use anonymous ciphers (ADH). I don't know if they are supported by Java but in any case you would still need to have some kind of identification to make sure you are talking to the expected server.
And then there are of course certificates. You might use self-signed certificates together with public key pinning if you don't want to use public certificates for your application.
In HTTPS technology, an SSL certificate is required for a secure
connection. This certificate must be acquired through self-generation,
or through a certificate authority (CA). In Java, an SSLSocket to
SSLSocket connection promises the same security as an HTTPS connection
(No man-in-the-middle, encryption, etc).
No : HTTPS = HTTP traffic going through an SSL socket.
When connecting two SSLSockets instantiated in two separate,
stand-alone Java programs (One client, one server), is it necessary to
supply Java (The server) with a valid certificate?
Yes - Certificate and private key. If you want two way SSL, client would also need its own set of key/cert
What are the methods used to specify which certificate to use? The
documentation doesn't seem to have anything to say about this.
There's a lot of ground to cover. I'm not sure how much you already know, the things that you need to read up on include keytool, KeyStore, SSLContext, SSLServerSocketFactory, KeyManager.
Or you could directly go to examples like this

Using the same private key on both the client and Server side for a SSL connection

I am working on a board that collects environmental information and sends it's data back to a single server to be processed. The only connections to this server will be made by the boards that will eventually be put out into the field. Most of the development is done, but now I would like to try to secure all of the connections. Speed is critical because the data is real time sensitive and the board has a fairly small processor on it (8Mhz). Since I have such tight control over it all I would like to share the same private key between the WiFi Chip and the Java based server that is accepting the connections. This would hopefully allow me to decrypt and encrypt messages over SSL without having to go through the handshake process each time one of the boards connects. Correct?
I have been experimenting for a few days with no luck. But before I dig deep into the rabbit hole I wanted to make sure that this is even possible. Thanks, any suggestions would be very appreciated.
You seem to be confused regarding the whay SSL/TLS works.
During the handshake, the server presents its certificate (unless an anonymous cipher suite is used) to prove its identity to the client, and then agrees on shared keys (via the exchange of a pre-master secret) with the client. Once the handshake has completed, only shared keys are used for the encryption. (More details here.)
The server's private key is used to prove its identity to the client (via its certificate). The purpose of this is to prevent MITM attacks.
Giving the server's private key to the client would achieve nothing but allowing any client to impersonate the server.
You can't really avoid the handshake, also you may be able to use session resumption if you make multiple successive connections.
You may also be able to use TLS PSK (Pre-Shared Keys) cipher suites (sharing the symmetric key, not the private key), but they're not available in the Oracle JSSE provider.

Java SSL sockets without authentication or stores?

I have two java applications that need to talk to each other over an encrypted TCP socket, but they don't need to authenticate each other (one will accept() a connection from the other). Can anyone point me to a tutorial/code-snippet that will help me set these up?
I'm looking for something fairly simple and I'd like to not have to supply any keystore or truststore material.
EDIT: I should be more specific here. I meant that they don't have to authenticate each other via SSL. I have some non-trivial authentication that I have to do at the application level, so I can't use any sort of SSL-based authentication scheme.
Also, some of the links in the answers posted so far (as of noon 3/10/2010) require keystore files. Is there a simple way I can programmatically generate the keys I need?
To reiterate Chris Jester-Young's advice - if you don't have authentication, then you might be communicating securely, but you have no idea who you're communicating securely with. You could simply be communicating very securely with the bad guy himself (who is relaying everything you're saying onto the person you hoped you were talking directly to).
However, there is a quite lightweight authentication scheme that might suit your purposes, called TOFU (Trust On First Use). This is where you use SSL and generate self-signed certificates for each side - however you do not skip certificate validation. Instead, on the first connection with a given peer you accept any certificate and store it locally; on subsequent connections with that peer, you only accept that saved certificate. This is similar to the way that ssh works by default for host authentication, and provides authentication of the "the guy I'm talking to now is the same guy I was talking to yesterday" variety.
You can use the anonymous Diffie-Hellman ciphersuites if you insist on ignoring Chris Jester-Young's sage advice. Those ciphersuites are not enabled by default, you have to explicitly enable them, for example by using the SSLSocket.setEnabledCipherSuites() method.
If you absolutely do not want to use SSL with certificates, you can roll your own, though it won't be as secure obviously. I'm just improvising here, mixing a little asymmetric crypto with port-knocking.
First, create a random RSA key pair in the client, in-memory, no need to store it anywhere. Client then connects to server using a plain Socket, and upon connection, sends the server the public key (encode as you wish, so that you can read it easily on the server). Server then generates a random 128-bit key, starts ANOTHER ServerSocket in a random port, and encrypts the 128-bit key and the new server port number, using the client's public key, and sends the data back to the client. Server must wait for a short period of time to receive a connection from the same client on the new port.
Client closes connection, deciphers data, and opens a new Socket to the server on the specified port. Then both client and server must wrap the socket's InputStream and OutputStream on a CipherInputStream and CipherOutputStream using AES/CBC/PKCS5Padding (or RC4 if you prefer) with the specified 128-bit key. Voilá, you have a secure connection between client and server, without any authentication.
If you want to handle authentication you can do so over the secure connection, or on the first connection the server can have RSA key pair as well, they exchange keys and the server can send a challenge to the client (the server sends the challenge to the client using the client's public key and the client responds to the challenge using the server's public key). But that's unnecessarily complicated and I think you'd be better off using standard SSL with keystores anyway... perhaps you can get create an in-memory KeyStore on the client and send it to the server as explained above using the first connection (encrypt the keystore with the server's public key) and then you can set up the second connection to use SSL with that keystore which is temporary and will be discarded when the client disconnects.

Categories