Java - 使用预共享公钥并且没有信任存储麻烦的流量的非对称加密

时间:2012-07-06 19:33:27

标签: java encryption cryptography encryption-asymmetric truststore

我正在尝试使用RSA预共享密钥进行通信,理想情况下,没有涉及信任库欺骗

设置基本上是这样的:

客户端有一个applet,服务器端有一个servlet(duh :))

applet有servlet的RSA公钥(Spub)硬编码。

servlet有自己的RSA私钥(Spriv)硬编码。

他们的applet生成一个随机的AES 256密钥(会话密钥),使用servlet的公钥(它已经硬编码)对其进行加密,通过TCP套接字连接到servlet,并将RSA加密的密钥发送到servlet ,只要此套接字连接持续,就会继续解密会话密钥并将其用于与此applet的任何进一步通信。

我宁愿这样做而不会弄乱信任库等(毕竟,它是一个相对简单的设置,允许预先共享的硬编码公钥)

关于我应该从哪里开始教育自己的任何建议?

2 个答案:

答案 0 :(得分:2)

我同意SSL是一个不错的方式,但回答你的直接问题,你所描述的方案相当简单,似乎没有泄露任何秘密。这是基于硬编码公钥的客户端RSA部分的实现。

// 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);
    }
}

答案 1 :(得分:2)

虽然您可以通过构建PublicKey并使用Cipher来使用较低级别的加密函数,但是值得考虑使用JSSE:它将提供套接字上下文中的所有内容。此外,SSL / TLS提供的加密是通过握手期间协商的共享密钥完成的(除此之外,它比非对称加密更快)。

您可以使用自签名证书构建信任库,以便预共享该公钥。您可以按如下方式加载它(请注意,InputStream不必是FileInputStream,您可以从内存中读取内容,例如):

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();
// ...

这是使用JSSE的正常方式。如果您希望将SSL / TLS与显式RSA公钥一起使用,则必须实现自己的TrustManager做明确比较(而不是使用TrustManagerFactory):这肯定会使代码更长,更复杂。

如果你在applet中运行所有这些,你可能仍然有关于applet权限系统的问题,以建立套接字连接。请参阅What Applets Can and Cannot Do