我正在尝试使用RSA预共享密钥进行通信,理想情况下,没有涉及信任库欺骗
设置基本上是这样的:
客户端有一个applet,服务器端有一个servlet(duh :))
applet有servlet的RSA公钥(Spub)硬编码。
servlet有自己的RSA私钥(Spriv)硬编码。
他们的applet生成一个随机的AES 256密钥(会话密钥),使用servlet的公钥(它已经硬编码)对其进行加密,通过TCP套接字连接到servlet,并将RSA加密的密钥发送到servlet ,只要此套接字连接持续,就会继续解密会话密钥并将其用于与此applet的任何进一步通信。
我宁愿这样做而不会弄乱信任库等(毕竟,它是一个相对简单的设置,允许预先共享的硬编码公钥)
关于我应该从哪里开始教育自己的任何建议?
答案 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。