سؤال

I'm trying to communicate using RSA preshared keys and, ideally, without involving truststore shenanigans

The setup is basically like this:

There's an applet on client side and a servlet on server side (duh :) )

The applet has servlet's RSA public key (Spub) hardcoded.

The servlet has it's own RSA private key (Spriv) hardcoded.

They applet generates a random AES 256 key (session key), encrypts it with servlet's public key (which it has hardcoded), connects to the servlet over a TCP socket and sends the RSA-encrypted key to the servlet, which proceeds to decrypt the session key and use it for any further communication with this applet as long as this socket connection lasts.

I would rather do this all without messing with truststore and such (after all, it's a relatively straightforward setup which allows for a pre-shared hardcoded public key)

Any suggestions in regards to where I should start looking to educate myself ?

هل كانت مفيدة؟

المحلول

I would agree with the comments that SSL is a decent way to go, but to answer your direct question, the scheme you described is fairly simple and doesn't appear to give away any secrets. Here's an implementation of the RSA portion of the client, based on a hard-coded public key.

// Hardcoded values extracted from getModulus of a generated KeySpec.
private static BigInteger mod = new BigInteger("113...");
private static BigInteger exp = new BigInteger("217...");

private PublicKey hardCodedKey() {
    RSAPublicKeySpec keySpec = new RSAPublicKeySpec(mod, exp);
    KeyFactory keyFactory = null;
    PublicKey rsaKey = null;
    try {
        keyFactory = KeyFactory.getInstance("RSA");
        rsaKey = keyFactory.generatePublic(keySpec);
    } catch (Exception ex) {
        throw new IllegalStateException(ex);
    }
    return rsaKey;
}

private byte[] encrypt(PublicKey pubKey, byte[] plaintext) {
    try {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        return cipher.doFinal(plaintext);
    } catch (Exception ex) {
        throw new IllegalStateException(ex);
    }
}

نصائح أخرى

Although you can use lower-level cryptographic functions by building your PublicKey and using Cipher, it's worth considering using JSSE: it will provide all that within the context of sockets. In addition, the encryption provided by SSL/TLS is done via shared keys negotiated during the handshake (amongst other things, it's faster than asymmetric crypto).

You could build a truststore with a self-signed certificate for pre-sharing that public key. You can load it as follows (note that the InputStream doesn't have to be a FileInputStream, you can read the content from memory for example):

TrustManagerFactory tmf = TrustManagerFactory
    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance("JKS");
InputStream is = ...
ks.load(is, null);
// or ks.load(is, "thepassword".toCharArray());
is.close();

tmf.init(ks);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);

SSLSocketFactory = sslContext.getSocketFactory();
// ...

That's the normal way of using the JSSE. If you wanted to use SSL/TLS with your explicit RSA public key, you would have to implement your own TrustManager do make the explicit comparison (instead of using the TrustManagerFactory): that would certainly make the code a bit longer and more complex.

If you run all this within an applet, you may still have problems regarding the applet permissions system, to make socket connections. See What Applets Can and Cannot Do.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top