Java-使用预共享公钥对流量进行非对称加密,并且不存在信任存储问题

Java-使用预共享公钥对流量进行非对称加密,并且不存在信任存储问题,java,encryption,cryptography,encryption-asymmetric,truststore,Java,Encryption,Cryptography,Encryption Asymmetric,Truststore,我正在尝试使用RSA预共享密钥进行通信,理想情况下,不涉及truststore骗局 设置基本上如下所示: 客户端有一个小程序,服务器端有一个servlet(duh:) 小程序具有servlet的RSA公钥(Spub)硬编码 servlet有自己的RSA私钥(Spriv)硬编码 小程序生成一个随机AES 256密钥(会话密钥),用servlet的公钥(已硬编码)加密,通过TCP套接字连接到servlet,并将RSA加密密钥发送到servlet,它继续解密会话密钥,并将其用于与此小程序的任何进一步通

我正在尝试使用RSA预共享密钥进行通信,理想情况下,不涉及truststore骗局

设置基本上如下所示:

客户端有一个小程序,服务器端有一个servlet(duh:)

小程序具有servlet的RSA公钥(Spub)硬编码

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

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

我宁愿这样做,也不要弄乱truststore之类的东西(毕竟,这是一个相对简单的设置,允许预共享硬编码公钥)


关于我应该从哪里开始自学,有什么建议吗?

我同意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);
    }
}

我同意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);
    }
}

尽管您可以通过构建
公钥和使用
密码来使用较低级别的加密函数,但值得考虑使用JSSE:它将在套接字上下文中提供所有这些功能。此外,SSL/TLS提供的加密是通过握手期间协商的共享密钥完成的(除其他外,它比非对称加密更快)

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

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


如果在小程序中运行所有这些操作,则可能仍然存在有关小程序权限系统的问题,无法进行套接字连接。请参阅。

尽管您可以通过构建
公钥和使用
密码来使用较低级别的加密函数,但值得考虑使用JSSE:它将在套接字上下文中提供所有这些功能。此外,SSL/TLS提供的加密是通过握手期间协商的共享密钥完成的(除其他外,它比非对称加密更快)

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

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


如果在小程序中运行所有这些操作,则可能仍然存在有关小程序权限系统的问题,无法进行套接字连接。请参阅。

小程序是否通过HTTPS下载?否。但是,它是一个已签名的小程序。为什么?:)如果只需为客户端和服务器创建自签名证书,就可以使用内置SSL(JSSE)。Java SSL有很多扩展点,您也可以简单地在内存中创建信任库。正如owlstead所说,您可以使用类似于
keystore ks=keystore.getInstance(keystore.getDefaultType())
的东西来使用内存中的密钥库,然后导入硬编码密钥/证书。哇,我不知道我可以做一个内存密钥库。谢谢猫头鹰和DNA!小程序是否通过HTTPS下载?否。但是,它是一个已签名的小程序。为什么?:)如果只需为客户端和服务器创建自签名证书,就可以使用内置SSL(JSSE)。Java SSL有很多扩展点,您也可以简单地在内存中创建信任库。正如owlstead所说,您可以使用类似于
keystore ks=keystore.getInstance(keystore.getDefaultType())
的东西来使用内存中的密钥库,然后导入硬编码密钥/证书。哇,我不知道我可以做一个内存密钥库。谢谢猫头鹰和DNA!谢谢!我想我会试试这个,然后试试内存中的信任库(没有意识到可以这么做),看看是否有任何理由使用其中一个。非常感谢!我想我会试试这个,然后试试内存中的信任库(没有意识到可以这么做),看看是否有任何理由使用其中一个。