Java 證書(keytool實例)代碼實現加解密、加簽、驗簽


一、使用keytool工具制作一個jks證書、並導出公鑰

進入D:\jkstest目錄下,使用命令生成merKey.jks證書文件

keytool -genkey -alias yunbo2 -keypass 123456 -keyalg RSA -keysize 1024 -validity 3650 -keystore merKey.jks -storepass abc@2018 -dname "CN=localhost,OU=localhost, O=localhost, L=深圳, ST=廣東, C=CN"

進入D:\jkstest目錄下,導出公鑰yunbo2.cer文件,輸入以下命令,回車,輸入秘鑰庫密碼 abc@2018

keytool -export -alias yunbo2 -keystore merKey.jks -file yunbo2.cer

生成證書文件如下

二、簡單代碼實現加解密、加簽、驗簽

 

/**
 * desc area
 * Created by yunBo on 2018/9/25 0025.
 */
public class CertificateUtils {
	
	public  static final String KEY_STORE = "JKS";
	public  static final String X509 = "X.509";
	private static final int CACHE_SIZE = 2048;
	private static final int MAX_ENCRYPT_BLOCK = 117;
	private static final int MAX_DECRYPT_BLOCK = 128;
	
	private static final String SHA1WithRSA = "SHA1WithRSA";
	private static final String RSA = "RSA";
	private static final String ECB = "ECB";
	
	public static final Map<String, Object> signData = Maps.newConcurrentMap();
	public static final String CRRECEPAY_SIGN_KEYSTORE="YUNBO_SIGN_KEYSTORE";
	public static final String CRRECEPAY_SIGN_X509CERTIFICATE="YUNBO_SIGN_X509CERTIFICATE";
	
	
	public  static final String keyPass   = "123456";
	public  static final String storePass = "abc@2018";
	public  static final String alias     = "yunbo2";
	public  static final String jksFile   = "D:/jkstest/merKey.jks";
	public  static final String pubFile   = "D:/jkstest/yunbo2.cer";
	
	
	public static void initX509Certificate(String cerFilePath) throws Exception {
		
		InputStream inputStream = null;
		try {
			CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
			inputStream = new FileInputStream(cerFilePath);
			X509Certificate x509Certificate = (X509Certificate) certificateFactory.generateCertificate(inputStream);
			signData.put(CRRECEPAY_SIGN_X509CERTIFICATE, x509Certificate);
		} finally {
			IOUtils.closeQuietly(inputStream);
		}
	}
	
	/**
	 * 獲取私鑰信息
	 * @param jksFilePath
	 * @param keyAlias
	 * @param keyPass
	 * @param storePass
	 * @return
	 * @throws Exception
	 */
	public static PrivateKey getPrivateKey(String jksFilePath, String keyAlias, String keyPass, String storePass) throws Exception {
		
		File jksFile = new File(jksFilePath);
		InputStream in = new FileInputStream(jksFile);
		KeyStore keyStore = KeyStore.getInstance("JKS");
		keyStore.load(in, storePass.toCharArray());
		PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias, keyPass.toCharArray());
		if (in != null) {
			IOUtils.closeQuietly(in);
		}
		return privateKey;
	}
	
	/**
	 * 獲取公鑰信息
	 * @param cerFilePath
	 * @return
	 * @throws KeyStoreException
	 * @throws IOException
	 * @throws CertificateException
	 * @throws NoSuchAlgorithmException
	 */
	public static PublicKey getPublicKey(String cerFilePath) throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException {
		PublicKey publicKey = null;
		try {
			
			X509Certificate x509Certificate = (X509Certificate)signData.get(CRRECEPAY_SIGN_X509CERTIFICATE);
			if (x509Certificate == null) {
				initX509Certificate(cerFilePath);
				x509Certificate = (X509Certificate)signData.get(CRRECEPAY_SIGN_X509CERTIFICATE);
			}
			publicKey = x509Certificate.getPublicKey();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return publicKey;
	}
	
	/**
	 * 加密
	 * @param requestStr
	 * @return
	 * @throws Exception
	 */
	public static byte[] encryptContentBytes(String requestStr) throws Exception {
		
		try {
			PublicKey publicKey = getPublicKey(pubFile);
			String pubKey  = Base64.encodeBase64String(publicKey.getEncoded());
			byte[] content = encryptByPublicKey(requestStr.getBytes(), pubKey);
			return content;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 公鑰加密
	 * @param data
	 * @param publicKey
	 * @return
	 * @throws Exception
	 */
	public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
		
		byte[] keyBytes = org.apache.commons.codec.binary.Base64.decodeBase64(publicKey);
		X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(RSA);
		Key publicK = keyFactory.generatePublic(x509KeySpec);
		// 對數據加密
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(Cipher.ENCRYPT_MODE, publicK);
		int inputLen = data.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0;
		byte[] cache;
		int i = 0;
		// 對數據分段加密
		while (inputLen - offSet > 0) {
			if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
				cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
			} else {
				cache = cipher.doFinal(data, offSet, inputLen - offSet);
			}
			out.write(cache, 0, cache.length);
			i++;
			offSet = i * MAX_ENCRYPT_BLOCK;
		}
		byte[] encryptedData = out.toByteArray();
		out.close();
		return encryptedData;
	}
	
	/**
	 * 私鑰解密
	 *
	 * @param encryptedData
	 * @param privateKey
	 * @return
	 * @throws Exception
	 */
	public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception {
		
		byte[] keyBytes = Base64.decodeBase64(privateKey);
		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(RSA);
		Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(Cipher.DECRYPT_MODE, privateK);
		int inputLen = encryptedData.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0;
		byte[] cache;
		int i = 0;
		// 對數據分段解密
		while (inputLen - offSet > 0) {
			if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
				cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
			} else {
				cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
			}
			out.write(cache, 0, cache.length);
			i++;
			offSet = i * MAX_DECRYPT_BLOCK;
		}
		byte[] decryptedData = out.toByteArray();
		out.close();
		return decryptedData;
	}
	
	/**
	 * 解密
	 * @param responseDataBytes
	 * @return
	 * @throws Exception
	 */
	public static String decryptContentBytes(byte[] responseDataBytes)
			throws Exception {
		
		try {
			PrivateKey privateKey = getPrivateKey(jksFile, alias, keyPass, storePass);
			String priKey = Base64.encodeBase64String(privateKey.getEncoded());
			byte[] decryptContentBytes = decryptByPrivateKey(responseDataBytes, priKey);
			return new String(decryptContentBytes, CharEncoding.UTF_8);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 加簽
	 * @param signData
	 * @return
	 * @throws Exception
	 */
	public static String sign(String signData) throws Exception {
		
		InputStream in = new FileInputStream(new File(jksFile));
		KeyStore keyStore = KeyStore.getInstance("JKS");
		keyStore.load(in, storePass.toCharArray());
		
		// 獲取jks證書別名
		Enumeration en = keyStore.aliases();
		String pName = null;
		while (en.hasMoreElements()) {
			String n = (String) en.nextElement();
			if (keyStore.isKeyEntry(n)) {
				pName = n;
			}
		}
		PrivateKey key = getPrivateKey(jksFile,pName,keyPass,storePass);
		Signature signature = Signature.getInstance(SHA1WithRSA);
		signature.initSign(key);
		signature.update(signData.getBytes("UTF-8"));
		byte[] signedData = signature.sign();
		String signDate = new BASE64Encoder().encode(signedData);
		signDate = signDate.replaceAll("\r\n", "").replaceAll("\n", "");
		return signDate;
	}
	
	/**
	 * 驗簽
	 * @return
	 * @throws Exception
	 */
	public static boolean verifySign2(String originData,String returnSignData) throws Exception {
		
		PublicKey publicKey = getPublicKey(pubFile);
		Signature sign3 = Signature.getInstance(SHA1WithRSA);
		sign3.initVerify(publicKey);
		sign3.update(originData.getBytes("UTF-8"));
		boolean isVerifySign = sign3.verify(new BASE64Decoder().decodeBuffer(returnSignData));
		return isVerifySign;
	}
	
	public static void main(String[] args) throws Exception{
	
		String originData = "hello波波";
		System.out.println("========> 加密開始");
		byte[] enData = encryptContentBytes(originData);
		String signData = sign(originData);
		System.out.println("========> 加簽 signData:"+signData);
		String deData = decryptContentBytes(enData);
		System.out.println("========> 解密 deData:"+deData);
		boolean verifySign = verifySign2(originData,signData);
		System.out.println("========> 解密 verifySign:"+verifySign);
	}
}

  

輸出結果為:

Connected to the target VM, address: '127.0.0.1:13223', transport: 'socket'
========> 加密開始
========> 加簽 signData:kR4GMEQGPsgltoQfK+6IboCHsi+JbsjrrUTA6aW...2J0K2UZwqMJfWCarzxsKvUMFThRhwnuqoZ9u1qWlIko=
========> 解密 deData:hello波波
========> 解密 verifySign:true
Disconnected from the target VM, address: '127.0.0.1:13223', transport: 'socket'

Process finished with exit code 0

  

 

三、總結

1、JKS文件是一個java中的密鑰管理庫,里面可以放各種密鑰文件,倉庫當然會有一把鎖,防范別人隨便亂拿,這個就是JKS文件的密 碼.里面存放的密鑰也各有不同,每個密鑰都有一個名字(在下面叫別名),一類就密鑰對,一類叫公鑰,一類叫私鑰,密鑰對就是包含公鑰和私鑰的。這里的公鑰 只要你能進入倉庫你就可以隨便查看拿走,私鑰則是有密碼的。只允許有權限的人查看拿走.對於讀取公鑰只需要 知道JKS文件(倉庫)的密碼就可以了,但是在讀取私鑰時則必須有私鑰的密碼。

2、在加載證書文件的時候,keyStore.load(in, storePass.toCharArray());storePass為獲取私鑰文件的密碼,即倉庫密碼,我們這里為abc@2018

3、證書加解密、加簽驗簽等功能在項目中非常常見,可以把證書獲取放在靜態對象Maps.newConcurrentMap()中,這樣效率顯著提升。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM