java证书加解密过程

本文介绍了使用Java进行证书加解密的过程,包括生成密钥对、设置参数、模拟服务端与客户端之间的加解密信息交换。通过示例展示了如何进行文件的加密和解密,以及数字签名的验证。
前提铺垫: 本机上构造两个数字证书用作测试,一个 Server 端 与一个Client 端
使用java keytool 生成自签名证书。

过程如下:


参数如下: 
-genkeypair 生成密钥对
-keyalg 指定密钥算法
-keysize 指定密钥长度
-sigalg 指定签名算法
-validity 证书有效期
-alias 别名
-keystore 密钥库存储位置
注:本文目的不在于生成及导出密钥库证书,故不做详细说明
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
生成并导出获得2份证书: JumpFly.cer   JumpFly2.cer   

单程序上模拟服务端与客户端利用证书进行加解密交换信息-------------------------

定义密钥库相关信息:(模拟中两端存于同一密钥库下,实际上应该是双方自己的独立密钥库)

        private static String password = "123456";
private static String alias = "www.JumpFly.org";
private static String Calias = "www.JumpFly2.org";
private static String certificatePath = "D:/FileBox/CerBox/JumpFly.cer";
private static  String CcertificatePath = "D:/FileBox/CerBox/JumpFly2.cer";
private static String keyStorePath = "C:/Windows/System32/JumpFly.keystore";

定义文件路径:

String FilePath="D:\\FileBox\\JAVA3D.zip"; //原始待加密文件路径
String EnFilePath="D:\\FileBox\\EnJAVA3D.zip";//加密后文件路径
String DeFilePath="D:\\FileBox\\DeJAVA3D.zip";//解密后文件路径

文件摘要使用Commons Codec下的DigestUtils类进行摘要处理(可自行查阅Commons Codec相关内容)

由于证书中无秘密密钥(即对称密钥) 所以需要一方生成 然后加密通知另一方获得对称密钥

具体实现如下:

public static void main(String[] args) throws Exception{

	String md5Hex;
	String FilePath="D:\\FileBox\\JAVA3D.zip";
	String EnFilePath="D:\\FileBox\\EnJAVA3D.zip";
	String DeFilePath="D:\\FileBox\\DeJAVA3D.zip";
	//生成摘要
	FileInputStream fileIn=new FileInputStream(FilePath);
	md5Hex = DigestUtils.md5Hex(fileIn);
	System.out.println("文件摘要:"+md5Hex);
	
	//产生签名--JumpFly的私钥
	byte[] sign = CertificateCoder
			.sign(md5Hex.getBytes(), keyStorePath, alias, password);
	System.err.println("数字签名:\n" + Hex.encodeHexString(sign));
	
	//文件加密
	byte[] Key=AESCoder.initKey();//二进制对称密钥key
	AESCoder.encryptFile(FilePath, EnFilePath, Key);
	
	//对称密钥加密--用JumpFly2的公钥
	byte[] EnKey=CertificateCoder.encryptByPublicKey(Key, CcertificatePath);
	System.out.println("以上是JumpFly端加密文件发送.....sign、Key、EnFile、EnKey");
	
	//对称密钥解密--用JumpFly2的私钥
	byte[] DeKey=CertificateCoder.decryptByPrivateKey(EnKey, keyStorePath, Calias, password);
	
	//文件解密
	AESCoder.decryptFile(EnFilePath, DeFilePath, DeKey);
	//验证签名--用JumpFly证书公钥
	FileInputStream fileIn2=new FileInputStream(DeFilePath);
	String md5Hex2 = DigestUtils.md5Hex(fileIn2);
	boolean flag=CertificateCoder.verify(md5Hex2.getBytes(), sign, certificatePath);
	System.out.println("文件摘要:"+md5Hex2+"\t 验证签名:"+flag);
	System.out.println("以上是JumpFly2端接收文件解密.....");
	
	//生成摘要
	String msString="这是JumpFly2端发送的消息";
	String sha1Hex=DigestUtils.sha1Hex(msString.getBytes());
	System.out.println("消息内容:"+msString+"\t 消息摘要:"+sha1Hex);
	//产生签名--JumpFly2的私钥
	byte[] sign2 = CertificateCoder
			.sign(sha1Hex.getBytes(), keyStorePath, Calias, password);
	System.err.println("数字签名:\n" + Hex.encodeHexString(sign2));
	//消息加密
	byte[] EnMsg=AESCoder.encrypt(msString.getBytes(), DeKey);
	//对称密钥加密--用JumpFly的证书公钥
	byte[] EnKey2=CertificateCoder.encryptByPublicKey(DeKey, certificatePath);
	System.out.println("以上是JumpFly2端加密消息发送.....sign2、EnMsg、EnKey2");
	
	
	//对称密钥解密--用JumpFly的私钥
	byte[] DeKey2=CertificateCoder.decryptByPrivateKey(EnKey2, keyStorePath, alias, password);
	//消息解密
	byte[] DeMsg=AESCoder.decrypt(EnMsg, DeKey2);
	String msgString=new String(DeMsg);
	//签名验证--用JumpFly2证书公钥
	String sha1Hex2 = DigestUtils.sha1Hex(DeMsg);
	boolean flag2=CertificateCoder.verify(sha1Hex2.getBytes(), sign2, CcertificatePath);
	System.out.println("消息内容:"+msgString+"\t 消息摘要:"+sha1Hex2+"\t 验证签名:"+flag2);
	System.out.println("以上是JumpFly端接收消息解密.....");

}
相关函数如下:

AESCoder :(在java加密与解密的艺术2相关代码中加以修改)

	private static final String KEY_ALGORITHM="AES";
	private static final String CIPHER_ALGORITHM="AES/ECB/PKCS5Padding";
	private static byte[] getKey(String key)throws Exception{
		return Base64.decodeBase64(key);
	}
	private static Key toKey(byte[] key)throws Exception{
		//实例化密钥材料
		SecretKey secretKey=new SecretKeySpec(key, KEY_ALGORITHM);
		return secretKey;
	}
	public static byte[] decrypt(byte[] data,byte[] key)throws Exception{
		//还原密钥
		Key K=toKey(key);
		Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM);
		cipher.init(Cipher.DECRYPT_MODE, K);
		return cipher.doFinal(data);
	}
	public static byte[] decrypt(byte[] data,String key)throws Exception{
		
		return decrypt(data, getKey(key));
	}
	public static byte[] encrypt(byte[] data,byte[] key)throws Exception{
		//还原密钥
		Key K=toKey(key);
		Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM);
		cipher.init(Cipher.ENCRYPT_MODE, K);
		return cipher.doFinal(data);
	}
	public static byte[] encrypt(byte[] data,String key)throws Exception{
		return encrypt(data, getKey(key));
	}
	
	public static void encryptFile(String FilePath,String EnFilePath,byte[] key)throws Exception{
		FileInputStream fileIn= new FileInputStream(FilePath);
		FileOutputStream fileOut=new FileOutputStream(EnFilePath);
		Key K=toKey(key);
		Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM);
		cipher.init(Cipher.ENCRYPT_MODE, K);
		crypt(fileIn, fileOut, cipher);
		
	}
	public static void encryptFile(String FilePath,String EnFilePath,String key)throws Exception{
		encryptFile(FilePath, EnFilePath, getKey(key));
	}
	public static void decryptFile(String EnFilePath,String DeFilePath,byte[] key)throws Exception{
		FileInputStream fileIn= new FileInputStream(EnFilePath);
		FileOutputStream fileOut=new FileOutputStream(DeFilePath);
		Key K=toKey(key);
		Cipher cipher=Cipher.getInstance(CIPHER_ALGORITHM);
		cipher.init(Cipher.DECRYPT_MODE, K);
		crypt(fileIn, fileOut, cipher);
		
	}
	public static void decryptFile(String EnFilePath,String DeFilePath,String key)throws Exception{
		decryptFile(EnFilePath, DeFilePath, getKey(key));
	}
	public static byte[] initKey()throws Exception{
		KeyGenerator kg=KeyGenerator.getInstance(KEY_ALGORITHM);
		kg.init(256);
		//生成秘密密钥
		SecretKey secretKey=kg.generateKey();
		return secretKey.getEncoded();
	}
	public static String initKeyString()throws Exception{
		return Base64.encodeBase64String(initKey());
	}
	public static void crypt(FileInputStream in,FileOutputStream out,Cipher cipher)throws IOException,GeneralSecurityException{
		FileChannel fcIn=null;
		MappedByteBuffer mbbfIn=null;
		int blockSize=cipher.getBlockSize();
		int outputSize=cipher.getOutputSize(blockSize);
		byte[] inBytes=new byte[blockSize];
		byte[] outBytes=new byte[outputSize];
		int len=0,outLenth;
		fcIn=in.getChannel();
		mbbfIn=fcIn.map(FileChannel.MapMode.READ_ONLY, 0, fcIn.size());
		boolean more=true;
			while(more){
				len=mbbfIn.limit()-mbbfIn.position();
				if(len>blockSize)
				{	mbbfIn.get(inBytes, 0, blockSize);
					outLenth=cipher.update(inBytes, 0, blockSize, outBytes);
				  out.write(outBytes,0,outLenth);
				}else{
					more=false;
				}
			} 
			if(len>0){mbbfIn.get(inBytes, 0, len);
					  outBytes=cipher.doFinal(inBytes,0,len);
			     }else outBytes=cipher.doFinal();
			out.write(outBytes);
		if(fcIn!=null)
			fcIn.close();
	}

CertificateCoder:

public static byte[] sign(byte[] sign, String keyStorePath, String alias,
			String password) throws Exception {
		// 获得证书
		X509Certificate x509Certificate = (X509Certificate) getCertificate(
				keyStorePath, alias, password);
		// 构建签名,由证书指定签名算法
		Signature signature = Signature.getInstance(x509Certificate
				.getSigAlgName());
		// 获取私钥
		PrivateKey privateKey = getPrivateKeyByKeyStore(keyStorePath, alias,
				password);
		// 初始化签名,由私钥构建
		signature.initSign(privateKey);
		signature.update(sign);
		return signature.sign();
	}

public static byte[] encryptByPublicKey(byte[] data, String certificatePath)
			throws Exception {
		// 取得公钥
		PublicKey publicKey = getPublicKeyByCertificate(certificatePath);
		// 对数据加密
		Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		return cipher.doFinal(data);

	}

public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath,
			String alias, String password) throws Exception {
		// 取得私钥
		PrivateKey privateKey = getPrivateKeyByKeyStore(keyStorePath, alias,
				password);
		// 对数据加密
		Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		return cipher.doFinal(data);

	}

输出结果:

文件摘要:5417f2fe5eafc7b531a91ed391dbec89
数字签名:
c9a7884f64848c2e04c31a501c7f3301b504c8f7f5066f20800295808e28d3e20373b74466406590665107095fcb1afa413ca2d32cdf1c37ce23d61f6ca12e4aa7c6640aec07e92e837d43f9b65db0ce5e7d14dc893ce4271aa21027bdb660db2884e64e64ced5c208b0e7a8625e669cc23e247d02160e48dc7de6d164f591f2c99abb132a1afeb652af59d313e3b377eda46f4b74057d0e6cf59815461e6b99e37b3adac6e2295f499e4942db0eb5d81bee49304a4541c895b3647dd998690b249361e4b6bf34ceff01b172157057e4f224e5f6065a2bc748cfcb0c7fbf37066402164907a64ee7ad6d404ce3e3bd1f42939fa209f1a9c931f4a4c2d3567685
文件加密耗时: 12153 ms
以上是JumpFly端加密文件发送.....sign、Key、EnFile、EnKey
文件解密耗时: 12075 ms
文件摘要:5417f2fe5eafc7b531a91ed391dbec89 验证签名:true
以上是JumpFly2端接收文件解密.....
消息内容:这是JumpFly2端发送的消息 消息摘要:d5193b828c60194ef91c8af5617df68f6aa0cde4
数字签名:
6a43c3851407777c8b09f7c62899afecc1cc3c85a3f4037e1ef071dcd26c3380cb8db4b7d989756cc3247e9c44cbc4f9b68f77fa5379293a2b24ff4a2f8bbe2812b84a6a6861e9aad19ad3b0ed9e553f5cd1654aa146387d7b4354bebe126de00bff6990e7acb89f9b15f189c8b345498e7b0f7964c96d0156e88f473c9f23d97905d848a812ed7c1f1099f6f86d75aee67566b6f3aa8c60d52cf6127f43bd211f063503436e0535c9d6315e313feadac15eec604502645448e1e582079fb9e97d0059fa382db141c01e3183e6a7f45cd2f025846c0a01e0c10202f1e13397b605783df3b69a4f440c1ad9513c75dfcf72bc3543a76b8779edbb0394cab06ee1
以上是JumpFly2端加密消息发送.....sign2、EnMsg、EnKey2
消息内容:这是JumpFly2端发送的消息       消息摘要:d5193b828c60194ef91c8af5617df68f6aa0cde4  

验证签名:true
以上是JumpFly端接收消息解密.....






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值