Java实现HTTPS加密、解密过程

1.HTTPS握手过程模拟

以下文章来自:http://kingj.iteye.com/blog/2103662

1.1准备工作

  1、创建java证书:

   C:\> keytool -genkey -alias wangyi -keypass wangyi -keyalg RSA -keysize 1024 -keystore https.keystore -storepass wangyi

  

2、将创建的证书保存到C盘(为了方便演示)

C:\>keytool -export -keystore https.keystore -alias wangyi -file https.crt -storepass wangyi

 

1.2类的说明

代码包含6个类,分别为:

名称 说明
CertifcateUtils 证书操作类
DesCoder Des对称加密和解密工具类
HttpsMockBase https父类
HttpsMockClient client类
HttpsMockServer 服务器类
SocketUtils socket工具类

CertifacateUtils.java

package httpsmock;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
/**
 * Created by kingj on 2014/8/13.
 */
public class CertifcateUtils {
    public static byte[] readCertifacates() throws Exception{
        CertificateFactory factory=CertificateFactory.getInstance("X.509");
        InputStream in=new FileInputStream("c:/https.crt");
        java.security.cert.Certificate cate=factory.generateCertificate(in);
        return cate.getEncoded();
    }

    public static byte[] readPrivateKey() throws  Exception{
        KeyStore store=KeyStore.getInstance("JKS");
        InputStream in=new FileInputStream("c:/https.keystore");
        store.load(in,"wangyi".toCharArray());
        PrivateKey pk=(PrivateKey)store.getKey("wangyi","wangyi".toCharArray());
        return pk.getEncoded();
    }

    public static PrivateKey readPrivateKeys() throws  Exception{
        KeyStore store=KeyStore.getInstance("JKS");
        InputStream in=new FileInputStream("c:/https.keystore");
        store.load(in,"wangyi".toCharArray());
        PrivateKey pk=(PrivateKey)store.getKey("wangyi","wangyi".toCharArray());
        return pk;
    }

    public static PublicKey readPublicKeys() throws  Exception{
        CertificateFactory factory=CertificateFactory.getInstance("X.509");
        InputStream in=new FileInputStream("c:/https.crt");
        java.security.cert.Certificate cate=factory.generateCertificate(in);
        return cate.getPublicKey();
    }

    public static  java.security.cert.Certificate createCertiface(byte b[]) throws Exception{
        CertificateFactory factory=CertificateFactory.getInstance("X.509");
        InputStream in=new ByteArrayInputStream(b);
        java.security.cert.Certificate cate=factory.generateCertificate(in);
        return cate;
    }

    public static String byte2hex(byte[] b) {
        String hs = "";
        String stmp = "";
        for (int n = 0; n < b.length; n++) {
            stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
            if (stmp.length() == 1) {
                hs = hs + "0" + stmp;
            } else {
                hs = hs + stmp;
            }
        }
        return hs.toUpperCase();
    }
}

DesCoder.java

package httpsmock;

/**
 * Created by kingj on 2014/8/13.
 */
import org.apache.commons.codec.binary.Hex;

import java.security.Key;
import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

/**
 * DES Coder
* secret key length: 56 bit, default: 56 bit
* mode: ECB/CBC/PCBC/CTR/CTS/CFB/CFB8 to CFB128/OFB/OBF8 to OFB128
* padding: Nopadding/PKCS5Padding/ISO10126Padding/ * @author Aub * */ public class DesCoder { /** * 密钥算法 */ private static final String KEY_ALGORITHM = "DES"; private static final String DEFAULT_CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding"; // private static final String DEFAULT_CIPHER_ALGORITHM = "DES/ECB/ISO10126Padding"; /** * 初始化密钥 * * @return byte[] 密钥 * @throws Exception */ public static byte[] initSecretKey(SecureRandom random) throws Exception{ //返回生成指定算法的秘密密钥的 KeyGenerator 对象 KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM); //初始化此密钥生成器,使其具有确定的密钥大小 kg.init(random); //生成一个密钥 SecretKey secretKey = kg.generateKey(); return secretKey.getEncoded(); } /** * 转换密钥 * * @param key 二进制密钥 * @return Key 密钥 * @throws Exception */ public static Key toKey(byte[] key) throws Exception{ //实例化DES密钥规则 DESKeySpec dks = new DESKeySpec(key); //实例化密钥工厂 SecretKeyFactory skf = SecretKeyFactory.getInstance(KEY_ALGORITHM); //生成密钥 SecretKey secretKey = skf.generateSecret(dks); return secretKey; } /** * 加密 * * @param data 待加密数据 * @param key 密钥 * @return byte[] 加密数据 * @throws Exception */ public static byte[] encrypt(byte[] data,Key key) throws Exception{ return encrypt(data, key,DEFAULT_CIPHER_ALGORITHM); } /** * 加密 * * @param data 待加密数据 * @param key 二进制密钥 * @return byte[] 加密数据 * @throws Exception */ public static byte[] encrypt(byte[] data,byte[] key) throws Exception{ return encrypt(data, key,DEFAULT_CIPHER_ALGORITHM); } /** * 加密 * * @param data 待加密数据 * @param key 二进制密钥 * @param cipherAlgorithm 加密算法/工作模式/填充方式 * @return byte[] 加密数据 * @throws Exception */ public static byte[] encrypt(byte[] data,byte[] key,String cipherAlgorithm) throws Exception{ //还原密钥 Key k = toKey(key); return encrypt(data, k, cipherAlgorithm); } /** * 加密 * * @param data 待加密数据 * @param key 密钥 * @param cipherAlgorithm 加密算法/工作模式/填充方式 * @return byte[] 加密数据 * @throws Exception */ public static byte[] encrypt(byte[] data,Key key,String cipherAlgorithm) throws Exception{ //实例化 Cipher cipher = Cipher.getInstance(cipherAlgorithm); //使用密钥初始化,设置为加密模式 cipher.init(Cipher.ENCRYPT_MODE, key); //执行操作 return cipher.doFinal(data); } /** * 解密 * * @param data 待解密数据 * @param key 二进制密钥 * @return byte[] 解密数据 * @throws Exception */ public static byte[] decrypt(byte[] data,byte[] key) throws Exception{ return decrypt(data, key,DEFAULT_CIPHER_ALGORITHM); } /** * 解密 * * @param data 待解密数据 * @param key 密钥 * @return byte[] 解密数据 * @throws Exception */ public static byte[] decrypt(byte[] data,Key key) throws Exception{ return decrypt(data, key,DEFAULT_CIPHER_ALGORITHM); } /** * 解密 * * @param data 待解密数据 * @param key 二进制密钥 * @param cipherAlgorithm 加密算法/工作模式/填充方式 * @return byte[] 解密数据 * @throws Exception */ public static byte[] decrypt(byte[] data,byte[] key,String cipherAlgorithm) throws Exception{ //还原密钥 Key k = toKey(key); return decrypt(data, k, cipherAlgorithm); } /** * 解密 * * @param data 待解密数据 * @param key 密钥 * @param cipherAlgorithm 加密算法/工作模式/填充方式 * @return byte[] 解密数据 * @throws Exception */ public static byte[] decrypt(byte[] data,Key key,String cipherAlgorithm) throws Exception{ //实例化 Cipher cipher = Cipher.getInstance(cipherAlgorithm); //使用密钥初始化,设置为解密模式 cipher.init(Cipher.DECRYPT_MODE, key); //执行操作 return cipher.doFinal(data); } private static String showByteArray(byte[] data){ if(null == data){ return null; } StringBuilder sb = new StringBuilder("{"); for(byte b:data){ sb.append(b).append(","); } sb.deleteCharAt(sb.length()-1); sb.append("}"); return sb.toString(); } }

HttpsMockBase.java

package httpsmock;

import com.sun.org.apache.bcel.internal.generic.NEW;

import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.util.Random;

/**
 * Created by kingj on 2014/8/13.
 */
public class HttpsMockBase {
    static PrivateKey privateKey;
    static PublicKey publicKey;


    public static boolean byteEquals(byte a[],byte[] b){
        boolean equals=true;
        if(a==null || b==null){
            equals=false;
        }

        if(a!=null && b!=null){
            if(a.length!=b.length){
                equals=false;
            }else{
                for(int i=0;i

HttpsMockClient.java

package httpsmock;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.security.Key;
import java.security.SecureRandom;

/**
 * Created by kingj on 2014/8/13.
 */
public class HttpsMockClient extends  HttpsMockBase {
    static DataInputStream in;
    static DataOutputStream out;
    static Key key;
    public static void main(String args[]) throws  Exception{
        int port=80;
        Socket s=new Socket("localhost",port);
        s.setReceiveBufferSize(102400);
        s.setKeepAlive(true);
        in=new DataInputStream(s.getInputStream());
        out=new DataOutputStream(s.getOutputStream());
        shakeHands();

        System.out.println("------------------------------------------------------------------");
        String name="duck";
        writeBytes(name.getBytes());

        int len=in.readInt();
        byte[] msg=readBytes(len);
        System.out.println("服务器反馈消息:"+byte2hex(msg));
        Thread.sleep(1000*100);


    }

    private static void shakeHands() throws Exception {
        //第一步 客户端发送自己支持的hash算法
        String supportHash="SHA1";
        int length=supportHash.getBytes().length;
        out.writeInt(length);
        SocketUtils.writeBytes(out, supportHash.getBytes(), length);

        //第二步 客户端验证服务器端证书是否合法
        int skip=in.readInt();
        byte[] certificate=SocketUtils.readBytes(in,skip);
        java.security.cert.Certificate cc= CertifcateUtils.createCertiface(certificate);

        publicKey=cc.getPublicKey();
        cc.verify(publicKey);
        System.out.println("客户端校验服务器端证书是否合法:" +true);

        //第三步  客户端校验服务器端发送过来的证书成功,生成随机数并用公钥加密
        System.out.println("客户端校验服务器端发送过来的证书成功,生成随机数并用公钥加密");
        SecureRandom seed=new SecureRandom();
        int seedLength=2;
        byte seedBytes[]=seed.generateSeed(seedLength);
        System.out.println("生成的随机数为 : " + byte2hex(seedBytes));
        System.out.println("将随机数用公钥加密后发送到服务器");
        byte[] encrptedSeed=encryptByPublicKey(seedBytes, null);
        SocketUtils.writeBytes(out,encrptedSeed,encrptedSeed.length);

        System.out.println("加密后的seed值为 :" + byte2hex(encrptedSeed));

        String message=random();
        System.out.println("客户端生成消息为:"+message);

        System.out.println("使用随机数并用公钥对消息加密");
        byte[] encrpt=encryptByPublicKey(message.getBytes(),seed);
        System.out.println("加密后消息位数为 : " +encrpt.length);
        SocketUtils.writeBytes(out,encrpt,encrpt.length);

        System.out.println("客户端使用SHA1计算消息摘要");
        byte hash[]=cactHash(message.getBytes());
        System.out.println("摘要信息为:"+byte2hex(hash));

        System.out.println("消息加密完成,摘要计算完成,发送服务器");
        SocketUtils.writeBytes(out,hash,hash.length);


        System.out.println("客户端向服务器发送消息完成,开始接受服务器端发送回来的消息和摘要");
        System.out.println("接受服务器端发送的消息");
        int serverMessageLength=in.readInt();
        byte[] serverMessage=SocketUtils.readBytes(in,serverMessageLength);
        System.out.println("服务器端的消息内容为 :" + byte2hex(serverMessage));

        System.out.println("开始用之前生成的随机密码和DES算法解密消息,密码为:"+byte2hex(seedBytes));
        byte[] desKey= DesCoder.initSecretKey(new SecureRandom(seedBytes));
        key=DesCoder.toKey(desKey);

        byte[] decrpytedServerMsg=DesCoder.decrypt(serverMessage, key);
        System.out.println("解密后的消息为:"+byte2hex(decrpytedServerMsg));

        int serverHashLength=in.readInt();
        byte[] serverHash=SocketUtils.readBytes(in,serverHashLength);
        System.out.println("开始接受服务器端的摘要消息:"+byte2hex(serverHash));

        byte[] serverHashValues=cactHash(decrpytedServerMsg);
        System.out.println("计算服务器端发送过来的消息的摘要 : " +byte2hex(serverHashValues));

        System.out.println("判断服务器端发送过来的hash摘要是否和计算出的摘要一致");
        boolean isHashEquals=byteEquals(serverHashValues,serverHash);

        if(isHashEquals){
            System.out.println("验证完成,握手成功");
        }else{
            System.out.println("验证失败,握手失败");
        }
    }


    public static byte[] readBytes(int length) throws  Exception{
        byte[] undecrpty=SocketUtils.readBytes(in,length);
        System.out.println("读取未解密消息:"+byte2hex(undecrpty));
        return DesCoder.decrypt(undecrpty,key);
    }

    public static void writeBytes(byte[] data) throws  Exception{
        byte[] encrpted=DesCoder.encrypt(data,key);
        System.out.println("写入加密后消息:"+byte2hex(encrpted));
        SocketUtils.writeBytes(out,encrpted,encrpted.length);
    }
}

HttpsMockServer.java

package httpsmock;

import javax.net.ServerSocketFactory;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.Key;
import java.security.SecureRandom;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by kingj on 2014/8/13.
 */
public class HttpsMockServer extends HttpsMockBase {
    static DataInputStream in;
    static DataOutputStream out;
    static String hash;
    static Key key;
    static ExecutorService executorService= Executors.newFixedThreadPool(20);
    public static void main(String args[]) throws Exception{
        int port=80;
        ServerSocket ss= ServerSocketFactory.getDefault().createServerSocket(port);
        ss.setReceiveBufferSize(102400);
        ss.setReuseAddress(false);
        while(true){
            try {
                final Socket s = ss.accept();
                doHttpsShakeHands(s);
                executorService.execute(new Runnable() {
                    @Override
                    public void run() {
                        doSocketTransport(s);
                    }
                });

            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    private static void doSocketTransport(Socket s){
        try{
            System.out.println("--------------------------------------------------------");
            int length=in.readInt();
            byte[] clientMsg=readBytes(length);
            System.out.println("客户端指令内容为:" + byte2hex(clientMsg));

            writeBytes("服务器已经接受请求".getBytes());
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }

    public static byte[] readBytes(int length) throws  Exception{
        byte[] undecrpty=SocketUtils.readBytes(in,length);
        System.out.println("读取未解密消息:"+byte2hex(undecrpty));
        return DesCoder.decrypt(undecrpty,key);
    }

    public static void writeBytes(byte[] data) throws  Exception{
        byte[] encrpted=DesCoder.encrypt(data,key);
        System.out.println("写入加密后消息:"+byte2hex(encrpted));
        SocketUtils.writeBytes(out,encrpted,encrpted.length);
    }

    private static void doHttpsShakeHands(Socket s) throws Exception {
         in=new DataInputStream(s.getInputStream());
         out=new DataOutputStream(s.getOutputStream());

        //第一步 获取客户端发送的支持的验证规则,包括hash算法,这里选用SHA1作为hash
        int length=in.readInt();
        in.skipBytes(4);
        byte[] clientSupportHash=SocketUtils.readBytes(in,length);
        String clientHash=new String(clientSupportHash);
        hash=clientHash;
        System.out.println("客户端发送了hash算法为:"+clientHash);

        //第二步,发送服务器证书到客户端
        byte[] certificateBytes=CertifcateUtils.readCertifacates();
        privateKey=CertifcateUtils.readPrivateKeys();
        System.out.println("发送证书给客户端,字节长度为:"+certificateBytes.length);
        System.out.println("证书内容为:" + byte2hex(certificateBytes));
        SocketUtils.writeBytes(out, certificateBytes, certificateBytes.length);

        System.out.println("获取客户端通过公钥加密后的随机数");
        int secureByteLength=in.readInt();
        byte[] secureBytes=SocketUtils.readBytes(in, secureByteLength);

        System.out.println("读取到的客户端的随机数为:"+byte2hex(secureBytes));
        byte secureSeed[]=decrypt(secureBytes);
        System.out.println("解密后的随机数密码为:" +byte2hex(secureSeed));

        //第三步 获取客户端加密字符串
        int skip=in.readInt();
        System.out.println("第三步 获取客户端加密消息,消息长度为 :" +skip);
        byte[] data=SocketUtils.readBytes(in,skip);

        System.out.println("客户端发送的加密消息为 : " +byte2hex(data));
        System.out.println("用私钥对消息解密,并计算SHA1的hash值");
        byte message[] =decrypt(data,new SecureRandom(secureBytes));
        byte serverHash[]=cactHash(message);


        System.out.println("获取客户端计算的SHA1摘要");
        int hashSkip=in.readInt();
        byte[] clientHashBytes=SocketUtils.readBytes(in,hashSkip);
        System.out.println("客户端SHA1摘要为 : " + byte2hex(clientHashBytes));

        System.out.println("开始比较客户端hash和服务器端从消息中计算的hash值是否一致");
        boolean isHashEquals=byteEquals(serverHash,clientHashBytes);
        System.out.println("是否一致结果为 : " + isHashEquals);



        System.out.println("第一次校验客户端发送过来的消息和摘译一致,服务器开始向客户端发送消息和摘要");
        System.out.println("生成密码用于加密服务器端消息,secureRandom : "+byte2hex(secureSeed));
        SecureRandom secureRandom=new SecureRandom(secureSeed);

        String randomMessage=random();
        System.out.println("服务器端生成的随机消息为 : "+randomMessage);

        System.out.println("用DES算法并使用客户端生成的随机密码对消息加密");
        byte[] desKey=DesCoder.initSecretKey(secureRandom);
        key=DesCoder.toKey(desKey);

        byte serverMessage[]=DesCoder.encrypt(randomMessage.getBytes(), key);
        SocketUtils.writeBytes(out,serverMessage,serverMessage.length);
        System.out.println("服务器端发送的机密后的消息为:"+byte2hex(serverMessage)+",加密密码为:"+byte2hex(secureSeed));

        System.out.println("服务器端开始计算hash摘要值");
        byte serverMessageHash[]=cactHash(randomMessage.getBytes());
        System.out.println("服务器端计算的hash摘要值为 :" +byte2hex(serverMessageHash));
        SocketUtils.writeBytes(out,serverMessageHash,serverMessageHash.length);

        System.out.println("握手成功,之后所有通信都将使用DES加密算法进行加密");
    }

}

SocketUtils.java

package httpsmock;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Arrays;

/**
 * Created by kingj on 2014/8/13.
 */
public class SocketUtils {
    public static void close(Socket s){
        try {
            s.shutdownInput();
            s.shutdownOutput();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



    public static byte[] readBytes(DataInputStream in,int length) throws IOException {
        int r=0;
        byte[] data=new byte[length];
        while(r

测试证书下载地址: https-keys.zip

2.Java加密解密算法工具类实现

以下文章来自:http://snowolf.iteye.com/blog/397693

2.1加密解密基础工具类

Coder.java

import java.security.MessageDigest;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * 基础加密组件
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public abstract class Coder {
	public static final String KEY_SHA = "SHA";
	public static final String KEY_MD5 = "MD5";

	/**
	 * MAC算法可选以下多种算法
	 * 
	 * 
	 * HmacMD5 
	 * HmacSHA1 
	 * HmacSHA256 
	 * HmacSHA384 
	 * HmacSHA512
	 * 
*/ public static final String KEY_MAC = "HmacMD5"; /** * BASE64解密 * * @param key * @return * @throws Exception */ public static byte[] decryptBASE64(String key) throws Exception { return (new BASE64Decoder()).decodeBuffer(key); } /** * BASE64加密 * * @param key * @return * @throws Exception */ public static String encryptBASE64(byte[] key) throws Exception { return (new BASE64Encoder()).encodeBuffer(key); } /** * MD5加密 * * @param data * @return * @throws Exception */ public static byte[] encryptMD5(byte[] data) throws Exception { MessageDigest md5 = MessageDigest.getInstance(KEY_MD5); md5.update(data); return md5.digest(); } /** * SHA加密 * * @param data * @return * @throws Exception */ public static byte[] encryptSHA(byte[] data) throws Exception { MessageDigest sha = MessageDigest.getInstance(KEY_SHA); sha.update(data); return sha.digest(); } /** * 初始化HMAC密钥 * * @return * @throws Exception */ public static String initMacKey() throws Exception { KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_MAC); SecretKey secretKey = keyGenerator.generateKey(); return encryptBASE64(secretKey.getEncoded()); } /** * HMAC加密 * * @param data * @param key * @return * @throws Exception */ public static byte[] encryptHMAC(byte[] data, String key) throws Exception { SecretKey secretKey = new SecretKeySpec(decryptBASE64(key), KEY_MAC); Mac mac = Mac.getInstance(secretKey.getAlgorithm()); mac.init(secretKey); return mac.doFinal(data); } }

CoderTest.java

import static org.junit.Assert.*;

import org.junit.Test;

/**
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public class CoderTest {

	@Test
	public void test() throws Exception {
		String inputStr = "简单加密";
		System.err.println("原文:\n" + inputStr);

		byte[] inputData = inputStr.getBytes();
		String code = Coder.encryptBASE64(inputData);

		System.err.println("BASE64加密后:\n" + code);

		byte[] output = Coder.decryptBASE64(code);

		String outputStr = new String(output);

		System.err.println("BASE64解密后:\n" + outputStr);

		// 验证BASE64加密解密一致性
		assertEquals(inputStr, outputStr);

		// 验证MD5对于同一内容加密是否一致
		assertArrayEquals(Coder.encryptMD5(inputData), Coder
				.encryptMD5(inputData));

		// 验证SHA对于同一内容加密是否一致
		assertArrayEquals(Coder.encryptSHA(inputData), Coder
				.encryptSHA(inputData));

		String key = Coder.initMacKey();
		System.err.println("Mac密钥:\n" + key);

		// 验证HMAC对于同一内容,同一密钥加密是否一致
		assertArrayEquals(Coder.encryptHMAC(inputData, key), Coder.encryptHMAC(
				inputData, key));

		BigInteger md5 = new BigInteger(Coder.encryptMD5(inputData));
		System.err.println("MD5:\n" + md5.toString(16));

		BigInteger sha = new BigInteger(Coder.encryptSHA(inputData));
		System.err.println("SHA:\n" + sha.toString(32));

		BigInteger mac = new BigInteger(Coder.encryptHMAC(inputData, inputStr));
		System.err.println("HMAC:\n" + mac.toString(16));
	}
}

2.2证书组件工具类

CertificateCoder.java

import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;

import javax.crypto.Cipher;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;

/**
 * 证书组件
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public abstract class CertificateCoder extends Coder {

	/**
	 * Java密钥库(Java Key Store,JKS)KEY_STORE
	 */
	public static final String KEY_STORE = "JKS";

	public static final String X509 = "X.509";
	public static final String SunX509 = "SunX509";
	public static final String SSL = "SSL";

	/**
	 * 由KeyStore获得私钥
	 * 
	 * @param keyStorePath
	 * @param alias
	 * @param password
	 * @return
	 * @throws Exception
	 */
	private static PrivateKey getPrivateKey(String keyStorePath, String alias,
			String password) throws Exception {
		KeyStore ks = getKeyStore(keyStorePath, password);
		PrivateKey key = (PrivateKey) ks.getKey(alias, password.toCharArray());
		return key;
	}

	/**
	 * 由Certificate获得公钥
	 * 
	 * @param certificatePath
	 * @return
	 * @throws Exception
	 */
	private static PublicKey getPublicKey(String certificatePath)
			throws Exception {
		Certificate certificate = getCertificate(certificatePath);
		PublicKey key = certificate.getPublicKey();
		return key;
	}

	/**
	 * 获得Certificate
	 * 
	 * @param certificatePath
	 * @return
	 * @throws Exception
	 */
	private static Certificate getCertificate(String certificatePath)
			throws Exception {
		CertificateFactory certificateFactory = CertificateFactory
				.getInstance(X509);
		FileInputStream in = new FileInputStream(certificatePath);

		Certificate certificate = certificateFactory.generateCertificate(in);
		in.close();

		return certificate;
	}

	/**
	 * 获得Certificate
	 * 
	 * @param keyStorePath
	 * @param alias
	 * @param password
	 * @return
	 * @throws Exception
	 */
	private static Certificate getCertificate(String keyStorePath,
			String alias, String password) throws Exception {
		KeyStore ks = getKeyStore(keyStorePath, password);
		Certificate certificate = ks.getCertificate(alias);

		return certificate;
	}

	/**
	 * 获得KeyStore
	 * 
	 * @param keyStorePath
	 * @param password
	 * @return
	 * @throws Exception
	 */
	private static KeyStore getKeyStore(String keyStorePath, String password)
			throws Exception {
		FileInputStream is = new FileInputStream(keyStorePath);
		KeyStore ks = KeyStore.getInstance(KEY_STORE);
		ks.load(is, password.toCharArray());
		is.close();
		return ks;
	}

	/**
	 * 私钥加密
	 * 
	 * @param data
	 * @param keyStorePath
	 * @param alias
	 * @param password
	 * @return
	 * @throws Exception
	 */
	public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath,
			String alias, String password) throws Exception {
		// 取得私钥
		PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);

		// 对数据加密
		Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
		cipher.init(Cipher.ENCRYPT_MODE, privateKey);

		return cipher.doFinal(data);

	}

	/**
	 * 私钥解密
	 * 
	 * @param data
	 * @param keyStorePath
	 * @param alias
	 * @param password
	 * @return
	 * @throws Exception
	 */
	public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath,
			String alias, String password) throws Exception {
		// 取得私钥
		PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);

		// 对数据加密
		Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
		cipher.init(Cipher.DECRYPT_MODE, privateKey);

		return cipher.doFinal(data);

	}

	/**
	 * 公钥加密
	 * 
	 * @param data
	 * @param certificatePath
	 * @return
	 * @throws Exception
	 */
	public static byte[] encryptByPublicKey(byte[] data, String certificatePath)
			throws Exception {

		// 取得公钥
		PublicKey publicKey = getPublicKey(certificatePath);
		// 对数据加密
		Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);

		return cipher.doFinal(data);

	}

	/**
	 * 公钥解密
	 * 
	 * @param data
	 * @param certificatePath
	 * @return
	 * @throws Exception
	 */
	public static byte[] decryptByPublicKey(byte[] data, String certificatePath)
			throws Exception {
		// 取得公钥
		PublicKey publicKey = getPublicKey(certificatePath);

		// 对数据加密
		Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
		cipher.init(Cipher.DECRYPT_MODE, publicKey);

		return cipher.doFinal(data);

	}

	/**
	 * 验证Certificate
	 * 
	 * @param certificatePath
	 * @return
	 */
	public static boolean verifyCertificate(String certificatePath) {
		return verifyCertificate(new Date(), certificatePath);
	}

	/**
	 * 验证Certificate是否过期或无效
	 * 
	 * @param date
	 * @param certificatePath
	 * @return
	 */
	public static boolean verifyCertificate(Date date, String certificatePath) {
		boolean status = true;
		try {
			// 取得证书
			Certificate certificate = getCertificate(certificatePath);
			// 验证证书是否过期或无效
			status = verifyCertificate(date, certificate);
		} catch (Exception e) {
			status = false;
		}
		return status;
	}

	/**
	 * 验证证书是否过期或无效
	 * 
	 * @param date
	 * @param certificate
	 * @return
	 */
	private static boolean verifyCertificate(Date date, Certificate certificate) {
		boolean status = true;
		try {
			X509Certificate x509Certificate = (X509Certificate) certificate;
			x509Certificate.checkValidity(date);
		} catch (Exception e) {
			status = false;
		}
		return status;
	}

	/**
	 * 签名
	 * 
	 * @param keyStorePath
	 * @param alias
	 * @param password
	 * 
	 * @return
	 * @throws Exception
	 */
	public static String sign(byte[] sign, String keyStorePath, String alias,
			String password) throws Exception {
		// 获得证书
		X509Certificate x509Certificate = (X509Certificate) getCertificate(
				keyStorePath, alias, password);
		// 获取私钥
		KeyStore ks = getKeyStore(keyStorePath, password);
		// 取得私钥
		PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password
				.toCharArray());

		// 构建签名
		Signature signature = Signature.getInstance(x509Certificate
				.getSigAlgName());
		signature.initSign(privateKey);
		signature.update(sign);
		return encryptBASE64(signature.sign());
	}

	/**
	 * 验证签名
	 * 
	 * @param data
	 * @param sign
	 * @param certificatePath
	 * @return
	 * @throws Exception
	 */
	public static boolean verify(byte[] data, String sign,
			String certificatePath) throws Exception {
		// 获得证书
		X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath);
		// 获得公钥
		PublicKey publicKey = x509Certificate.getPublicKey();
		// 构建签名
		Signature signature = Signature.getInstance(x509Certificate
				.getSigAlgName());
		signature.initVerify(publicKey);
		signature.update(data);

		return signature.verify(decryptBASE64(sign));

	}

	/**
	 * 验证Certificate
	 * 
	 * @param keyStorePath
	 * @param alias
	 * @param password
	 * @return
	 */
	public static boolean verifyCertificate(Date date, String keyStorePath,
			String alias, String password) {
		boolean status = true;
		try {
			Certificate certificate = getCertificate(keyStorePath, alias,
					password);
			status = verifyCertificate(date, certificate);
		} catch (Exception e) {
			status = false;
		}
		return status;
	}

	/**
	 * 验证Certificate
	 * 
	 * @param keyStorePath
	 * @param alias
	 * @param password
	 * @return
	 */
	public static boolean verifyCertificate(String keyStorePath, String alias,
			String password) {
		return verifyCertificate(new Date(), keyStorePath, alias, password);
	}

	/**
	 * 获得SSLSocektFactory
	 * 
	 * @param password
	 *            密码
	 * @param keyStorePath
	 *            密钥库路径
	 * 
	 * @param trustKeyStorePath
	 *            信任库路径
	 * @return
	 * @throws Exception
	 */
	private static SSLSocketFactory getSSLSocketFactory(String password,
			String keyStorePath, String trustKeyStorePath) throws Exception {
		// 初始化密钥库
		KeyManagerFactory keyManagerFactory = KeyManagerFactory
				.getInstance(SunX509);
		KeyStore keyStore = getKeyStore(keyStorePath, password);
		keyManagerFactory.init(keyStore, password.toCharArray());

		// 初始化信任库
		TrustManagerFactory trustManagerFactory = TrustManagerFactory
				.getInstance(SunX509);
		KeyStore trustkeyStore = getKeyStore(trustKeyStorePath, password);
		trustManagerFactory.init(trustkeyStore);

		// 初始化SSL上下文
		SSLContext ctx = SSLContext.getInstance(SSL);
		ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory
				.getTrustManagers(), null);
		SSLSocketFactory sf = ctx.getSocketFactory();

		return sf;
	}

	/**
	 * 为HttpsURLConnection配置SSLSocketFactory
	 * 
	 * @param conn
	 *            HttpsURLConnection
	 * @param password
	 *            密码
	 * @param keyStorePath
	 *            密钥库路径
	 * 
	 * @param trustKeyStorePath
	 *            信任库路径
	 * @throws Exception
	 */
	public static void configSSLSocketFactory(HttpsURLConnection conn,
			String password, String keyStorePath, String trustKeyStorePath)
			throws Exception {
		conn.setSSLSocketFactory(getSSLSocketFactory(password, keyStorePath,
				trustKeyStorePath));
	}
}
CertificateCoderTest.java

import static org.junit.Assert.*;

import java.io.DataInputStream;
import java.io.InputStream;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

import org.junit.Test;

/**
 * 
 * @author 梁栋
 * @version 1.0
 * @since 1.0
 */
public class CertificateCoderTest {
	private String password = "123456";
	private String alias = "www.zlex.org";
	private String certificatePath = "d:/zlex.cer";
	private String keyStorePath = "d:/zlex.keystore";
	private String clientKeyStorePath = "d:/zlex-client.keystore";
	private String clientPassword = "654321";

	@Test
	public void test() throws Exception {
		System.err.println("公钥加密——私钥解密");
		String inputStr = "Ceritifcate";
		byte[] data = inputStr.getBytes();

		byte[] encrypt = CertificateCoder.encryptByPublicKey(data,
				certificatePath);

		byte[] decrypt = CertificateCoder.decryptByPrivateKey(encrypt,
				keyStorePath, alias, password);
		String outputStr = new String(decrypt);

		System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr);

		// 验证数据一致
		assertArrayEquals(data, decrypt);

		// 验证证书有效
		assertTrue(CertificateCoder.verifyCertificate(certificatePath));

	}

	@Test
	public void testSign() throws Exception {
		System.err.println("私钥加密——公钥解密");

		String inputStr = "sign";
		byte[] data = inputStr.getBytes();

		byte[] encodedData = CertificateCoder.encryptByPrivateKey(data,
				keyStorePath, alias, password);

		byte[] decodedData = CertificateCoder.decryptByPublicKey(encodedData,
				certificatePath);

		String outputStr = new String(decodedData);
		System.err.println("加密前: " + inputStr + "\n\r" + "解密后: " + outputStr);
		assertEquals(inputStr, outputStr);

		System.err.println("私钥签名——公钥验证签名");
		// 产生签名
		String sign = CertificateCoder.sign(encodedData, keyStorePath, alias,
				password);
		System.err.println("签名:\r" + sign);

		// 验证签名
		boolean status = CertificateCoder.verify(encodedData, sign,
				certificatePath);
		System.err.println("状态:\r" + status);
		assertTrue(status);

	}

	@Test
	public void testHttps() throws Exception {
		URL url = new URL("https://www.zlex.org/examples/");
		HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();

		conn.setDoInput(true);
		conn.setDoOutput(true);

		CertificateCoder.configSSLSocketFactory(conn, clientPassword,
				clientKeyStorePath, clientKeyStorePath);

		InputStream is = conn.getInputStream();

		int length = conn.getContentLength();

		DataInputStream dis = new DataInputStream(is);
		byte[] data = new byte[length];
		dis.readFully(data);

		dis.close();
		System.err.println(new String(data));
		conn.disconnect();
	}
}


2.3Java相关加密解密学习

Java加密技术(一)——BASE64与单向加密算法MD5&SHA&MAC
Java加密技术(二)——对称加密DES&AES
Java加密技术(三)——PBE算法
Java加密技术(四)——非对称加密算法RSA
Java加密技术(五)——非对称加密算法的由来
Java加密技术(六)——数字签名算法DSA
Java加密技术(七)——非对称加密算法最高ECC
Java加密技术(八)——数字证书
Java加密技术(九)——初探SSL
Java加密技术(十)——单向认证
Java加密技术(十一)——双向认证
Java加密技术(十二)——*.PFX(*.p12)&个人信息交换文件




你可能感兴趣的:(PROTOCOL)