Java SSL代码抛出NoSuchAlgorithException
我正在做一个我想添加SSL的项目,所以我创建了一个简单的客户机/服务器测试实现,看看它是否有效,我得到了一个NoSuchAlgorithmException。以下是引发异常的服务器代码:Java SSL代码抛出NoSuchAlgorithException,java,ssl,Java,Ssl,我正在做一个我想添加SSL的项目,所以我创建了一个简单的客户机/服务器测试实现,看看它是否有效,我得到了一个NoSuchAlgorithmException。以下是引发异常的服务器代码: import java.io.*; import java.net.*; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; imp
import java.io.*;
import java.net.*;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.net.ssl.*;
public class SslServer
{
private static final int PORT = 5555;
public static void main(String[] args)
{
SecureRandom sr = new SecureRandom();
sr.nextInt();
try {
//client.public is the keystore file that holds the client's public key (created with keytool)
KeyStore clientKeyStore = KeyStore.getInstance("JKS");
clientKeyStore.load(new FileInputStream("client.public"), "clientpublicpw".toCharArray());
//server.private is the key pair for the server (created with keytool)
KeyStore serverKeyStore = KeyStore.getInstance("JKS");
clientKeyStore.load(new FileInputStream("server.private"), "serverprivatepw".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(clientKeyStore);
//This next line is where the exception occurs
KeyManagerFactory kmf = KeyManagerFactory.getInstance("TLS");
kmf.init(serverKeyStore, "serverprivatepw".toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), sr);
SSLServerSocketFactory sf = sslContext.getServerSocketFactory();
SSLServerSocket ss = (SSLServerSocket)sf.createServerSocket(SslServer.PORT);
ss.setNeedClientAuth(true);
BufferedReader in = new BufferedReader(new InputStreamReader(ss.accept().getInputStream()));
String line = null;
while((line = in.readLine()) != null)
{
System.out.println(line);
}
in.close();
ss.close();
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
}
}
我得到的stacktrace是:
java.security.NoSuchAlgorithmException: TLS KeyManagerFactory not available
at sun.security.jca.GetInstance.getInstance(Unknown Source)
at javax.net.ssl.KeyManagerFactory.getInstance(Unknown Source)
at SslServer.main(SslServer.java:32)
我尝试用“SSL”替换“TLS”,但仍然得到相同的异常。那对我来说没有意义。如何不支持TLS和SSL?这是我第一次尝试实现SSL,似乎很难找到关于这方面的好资源,因为代码示例已经很好地解释过了。有人能告诉我为什么会出现这种异常,或者指出我的代码有问题吗?有很多问题:
- 它被称为
(传输层安全性),而不是TLS
(用于TSL
)SSLContext
- 我建议在这里使用默认值:
(Oracle JRE上的默认值将是TrustManagerFactory tmf=TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
)PKIX
- (编辑:)默认的
是KeyManagerFactory
(SunX509
在这里不存在)。再次使用TLS
getDefaultAlgorithm()
- 阅读完
文件输入流后,应关闭它们
- 不清楚为什么客户机和服务器密钥库都在同一个位置。这应该是两个程序:一个用于客户端和服务器(并且
仅在服务器端有用)。如果它实际上是您的密钥库,那么将其称为“客户机存储”以外的东西会更清楚。(此外,由于您似乎正在学习如何实现这一点,我建议您首先尝试不使用客户端证书身份验证,在这种情况下,服务器将不需要信任库:使用setNeedClientAuth(true)
作为null
的第二个参数以使用默认值。)SSLContext.init(…)
- 不要将服务器密钥库提供给客户端。仅将其证书导出到将用作信任存储的新密钥库中。每个实体(客户端和服务器)都应该保持自己的私钥私有
- 这与其说是您希望信任存储中的远程方的公钥(仅此),还不如说是它的证书。确保您不仅导入了它的公钥,而且还导入了整个证书
- 为了澄清,请为文件保留适当的扩展名:使用
作为.jks
密钥库,这将为以后的工作省去麻烦jks
- 您可以对
中的SSLContext.init(…)
使用SecureRandom
:这将根据安全提供程序使用默认值null
KeyStore trustStore = KeyStore.getInstance("JKS");
InputStream tsis = new FileInputStream("trustedcerts.jks");
trustStore.load(tsis, "clientpublicpw".toCharArray());
tsis.close();
KeyStore serverKeyStore = KeyStore.getInstance("JKS");
InputStream ksis = new FileInputStream("server.jks");
clientKeyStore.load(ksis.close(), "serverprivatepw".toCharArray());
ksis.close();
TrustManagerFactory tmf =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
KeyManagerFactory kmf =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(serverKeyStore, "serverprivatepw".toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLServerSocketFactory sf = sslContext.getServerSocketFactory();
SSLServerSocket ss = (SSLServerSocket)sf.createServerSocket(SslServer.PORT);
ss.setNeedClientAuth(true);
正确的SSLContext名称为“TLS”。可以找到标准算法名称的列表请参见示例,并获取受支持算法的名称。似乎“SunX509”和“NewSunX509”是KeyManagerFactory支持的算法。协议名为TLS,而不是TSL。k我编辑了我的帖子,添加了这一更改。即使在我使用“TLS”时,我仍然会遇到同样的异常。如果你真的担心密码,你应该直接使用
char[]
或作为密码回调,并且在实际应用程序中永远不要硬编码你的密码(请参阅)。作为旁注,等待readLine
返回null
并不是知道何时停止读取(从任何类型的套接字)的好方法,请参阅此处的讨论:我将代码更改为使用TrustManagerFactory.getDefaultAlgorithm()和KeyManagerFactory.getDefaultAlgorithm(),这使它正常工作。我之所以在这里同时拥有这两个密钥库,是因为服务器有:server.private和client.public,而客户端有client.private和server.public。顺便说一句,我用这个网站作为我代码的参考,不确定它有多可靠,但它是我能找到的最好的:www.ibm.com/developerworks/java/tutorials/j-jsse/index.htmlIt确实说过KMF的SunX509
,而不是TLS
。它还使用了相当旧的Java版本,TMF的新默认值是PKIX
。(我仍然不相信本文中的密钥库文件命名约定。)这是一个错误类型,已修复。我仍然得到例外与“TLS”见布鲁诺的编辑,他的答案关于KeyManagerFactory,这将是你的另一个问题。再次,这是一个错误的类型,并已修复。我仍然得到例外的“TLS”你读过我的答案吗?似乎“SunX509”和“NewSunX509”是KeyManagerFactory.+1'ed支持的算法(正如我在最初的回答中键入的那样)@MattL922:getDefaultAlgorithm()
通常是最安全的赌注。