登录后台

页面导航

本文编写于 760 天前,最后修改于 164 天前,其中某些信息可能已经过时。

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