本文编写于 2026 天前,最后修改于 1430 天前,其中某些信息可能已经过时。
JAVA 做服务端,读取 pem 格式的证书和秘钥
public class SocketServer extends Thread{
private static final int SERVER_PORT = 10002;
private SSLServerSocket serverSocket;
public SocketServer() {
// Initialize SSLServer
try {
//Load KeyStore And TrustKeyStore
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
//保存服务端的私钥
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, null);
// // 读入服务端证书
PEMReader cacertfile = new PEMReader(new InputStreamReader(
new FileInputStream("d:/cacert.pem")));
X509Certificate cacert = (X509Certificate) cacertfile.readObject();
Certificate[] certChain = new Certificate[1];
certChain[0] = cacert;
cacertfile.close();
// 读入私钥
PEMReader kr = new PEMReader(new InputStreamReader(new FileInputStream("d:/privkey.pem")));
KeyPair key = (KeyPair) kr.readObject();
kr.close();
// 导入服务端端私钥和证书
keyStore.setKeyEntry("serverkey", key.getPrivate(), new char[]{}, certChain );
keyStore.setCertificateEntry("servercert", cacert);
//Initialize KeyStore Factory 创建用于管理JKS密钥库的X.509密钥管理器
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
keyManagerFactory.init(keyStore, "".toCharArray());
//Initialize SSLContext
SSLContext context = SSLContext.getInstance("TLSv1");
//授权的密钥管理器,用来授权验证,
context.init(keyManagerFactory.getKeyManagers(), null, null);
//Set up Server Socket
serverSocket = (SSLServerSocket) context.
getServerSocketFactory().createServerSocket(SERVER_PORT);
serverSocket.setWantClientAuth(false); //不需要客户端证书
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run() {
if(serverSocket == null){
System.out.println("Null server socket");
return;
}
try {
Socket socket = serverSocket.accept();
//Receive From Client
InputStream input = socket.getInputStream();
System.out.println("------Receive------");
//use byte array to initialize the output string
System.out.println(new String(StreamToByteArray(input)));
if(!socket.isClosed()){
//Response To Client
OutputStream output = socket.getOutputStream();
output.write("服务端发送123".getBytes());
output.flush();
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* convert stream to Byte Array
* @param inputStream
* @return
* @throws IOException
*/
public byte[] StreamToByteArray(InputStream inputStream) throws IOException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int readIndex = inputStream.read(buffer);
bout.write(buffer, 0, readIndex);
bout.flush();
bout.close();
//inputStream.close();
return bout.toByteArray();
}
public static void main(String[] args){
System.out.println("=======Start Server !======");
new SocketServer().run();
}
}
JAVA 做客户端,读取 pem 格式的证书和秘钥
public class SocketClient2 {
private Logger logger = LoggerFactory.getLogger(SocketClient2.class);
private String tpath = Tools.getConfig("KeyPath");// 证书路径
private String ip = Tools.getConfig("ip");// 服务端ip
private int port = Integer.parseInt(Tools.getConfig("port"));// 端口
public static List<SSLSocket> socketList = new ArrayList<SSLSocket>();
public SSLSocket getSSlSocket() {
SSLContext context = null;
context = this.getSSLcontext();
SSLSocketFactory ssf = context.getSocketFactory();
try {
SSLSocket ss = (SSLSocket) ssf.createSocket("127.0.0.1", 10002);
String[] protocols = { "TLSv1" }; //设置客户端协议
ss.setEnabledProtocols(protocols);
return ss;
} catch (UnknownHostException e) {
logger.error("a{}", e);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private SSLContext getSSLcontext() {
SSLContext sslContext = null;
try {
// 设定Security的Provider提供程序
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// System.setProperty("https.protocols", "SSLv3,SSLv2Hello");
// 建立空BKS,android只能用BKS(BouncyCastle密库),一般java应用参数传JKS(java自带密库)
//访问Java密钥库,JKS是keytool创建的Java密钥库,保存密钥。
KeyStore ksKeys = KeyStore.getInstance("JKS");
ksKeys.load(null, null);
// 读入客户端证书
PEMReader cacertfile = new PEMReader(new InputStreamReader(
new FileInputStream("d:/cacert.pem")));
X509Certificate cacert = (X509Certificate) cacertfile.readObject();
cacertfile.close();
// 导入根证书作为trustedEntry
//KeyStore.TrustedCertificateEntry 保存可信的 Certificate 的 KeyStore 项。
KeyStore.TrustedCertificateEntry trustedEntry = new KeyStore.TrustedCertificateEntry(
cacert);
//用指定别名保存 keystore Entry。
ksKeys.setEntry("ca_root", trustedEntry, null);
// 构建TrustManager 创建用于管理JKS密钥库的X.509密钥管理器。
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");// 密钥管理器
tmf.init(ksKeys);
// 构建SSLContext,此处传入参数为TLS,也可以为SSL
sslContext = SSLContext.getInstance("TLSv1");
sslContext.init(null, tmf.getTrustManagers(), null);
} catch (Exception e) {
e.printStackTrace();
}
return sslContext;
}
public static void main(String[] args) {
SocketClient2 client = new SocketClient2();
SSLSocket ss =client.getSSlSocket();
try {
ss.setSoTimeout(2000);
OutputStream socketOut = null;
if (ss != null && !ss.isClosed()) {
socketOut = ss.getOutputStream();
socketOut.write("客户端发送".getBytes());
socketOut.flush();
}
if (ss != null && !ss.isClosed()) {
InputStream in;
in = ss.getInputStream();
//input中的数据只能读取一次
System.out.println(new String(StreamToByteArray(in)));
}
ss.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* convert stream to Byte Array
* @param inputStream
* @return
* @throws IOException
*/
public static byte[] StreamToByteArray(InputStream inputStream) throws IOException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int readIndex = inputStream.read(buffer);
bout.write(buffer, 0, readIndex);
bout.flush();
bout.close();
return bout.toByteArray();
}
}
存在的问题
网上查找过相应的代码,确实给的 DEMO 是可行的,但是只是限于一定的加密算法维度,比如说 RSA4096 就不行了。
贴出相应的代码,供参考:
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public static String str_pubK = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqPvovSfXcwBbW8cKMCgwqNpsYuzF8RPAPFb7LGsnVo44JhM/xxzDyzoYtdfNmtbIuKVi9PzIsyp6rg+09gbuI6UGwBZ5DWBDBMqv5MPdOF5dCQkB2Bbr5yPfURPENypUz+pBFBg41d+BC+rwRiXELwKy7Y9caD/MtJyHydj8OUwIDAQAB";
/**
* 使用getPublicKey得到公钥,返回类型为PublicKey
* @param base64 String to PublicKey
* @throws Exception
*/
public static PublicKey getPublicKey(String key) throws Exception {
byte[] keyBytes;
keyBytes = (new BASE64Decoder()).decodeBuffer(key);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
}
试试这个公钥:
MIIDBTCCAe2gAwIBAgIKb0XKECkuAA7bcjANBgkqhkiG9w0BAQsFADAlMRUwEwYDVQQDDAxBQkMgVEVTVCBDQTIxDDAKBgNVBAoMA0FCQzAeFw0xNzEyMjQyMTE0MDBaFw0yMjEyMjQyMTE0MDBaME4xLzAtBgNVBAMMJjQ0OTk0NDIxMzAwLjAwMDEuMDAwMC42NjQ0NTAyNTY2MjY5MzAwMQ0wCwYDVQQLDARVd2luMQwwCgYDVQQKDANBQkMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJPVlBDFMqpzYWbdGe5dkiw2uRuq6Kd9/e7TZDfwS0L3mf5/kaDs93oRSqWr497SBliQeEbA3cHphWpceUpBu7DreYvH+scSsLrR8D6t7pcVQacIqL7YDYNsCpjrmZ/DQh9Ci7AZckYVu6TzojVwbbmbjo/0C3tdfWEzSq10LM51AgMBAAGjgZEwgY4wHwYDVR0jBBgwFoAUErtyLm5Iqy6z01KtzsJ33EmoKtIwCQYDVR0TBAIwADBBBgNVHR8EOjA4MDagNKAypDAwLjEQMA4GA1UEAwwHY3JsNDQ3NDEMMAoGA1UECwwDY3JsMQwwCgYDVQQKDANBQkMwHQYDVR0OBBYEFPAOIJAri/gehQGw4RtVaqa+v2mGMA0GCSqGSIb3DQEBCwUAA4IBAQCd9ofET3kZmU0932OGIZHdqDdMhrfESmM6dTutg8SfuTnniA43qYHDZFpNa86rl4Sox0lVyIx5mhRM4edSVzfYaX0WNtYlYDqkJONcn0yRenKwjrhpnyqFM3uQsMDW0VL0+Is8PKZqiaIfjPXY2a+OqY6zGN6vpUpkM0eT2GdJLZrIKM6ufKov7cTtRDfslFBmNh6N9LWqQPsItmDyXDeUIh5IKeHn+xwaL9MjYgxYhWpkMWmRbmp0o8Vf3qKLJ0wxptjGx0dhF1CcFbv5KzJRS3DLqKJAT0N1BWI8lJDkI5B553ouPMbQmOFAMgRp0eFR++Fm0aLPlyaGBZOWzrZy
参考文章:https://www.cnblogs.com/KKatherine/p/4128444.html
在测试自己的公钥时,出现 X509.ObjectIdentifier() – data isn’t an object ID (tag = -96) error
,在 https://samebug.io/exceptions/93395/java.security.InvalidKeyException/ioexception-detect-premature-eof 或许有你需要的答案,-96的错误没具体查,但是在 https://stackoverflow.com/questions/18856431/rsa-keys-transformation-for-java-clarification-needed 上的解决方法倒是提醒了我,我有了证书,为什么不直接获取公钥了?
从证书中获取
从证书文件流中获取
InputStream inStream = null;
try {
inStream = new FileInputStream("fileName-of-cert");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream);
} finally {
if (inStream != null) {
inStream.close();
}
}
直接获取
PublicKey myPubKey = cert.getPublicKey();
参考:https://stackoverflow.com/questions/18856431/rsa-keys-transformation-for-java-clarification-needed
本文转载自:https://blog.csdn.net/dingchenxixi/article/details/79030448