java中PFX与CER的使用(上)

1 篇文章 0 订阅

开发中交互过程中经常需要对传输数据的保密性和完整性有要求,因此需要对传输的数据加密和签名防止窃取和篡改,首选对加密文件的定义:

通常情况下,作为文件形式存在的证书一般有三种格式:

第一种:带有私钥的证书,由Public Key Cryptography Standards #12,PKCS#12标准定义,包含了公钥和私钥的二进制格式的证书形式,以.pfx作为证书文件后缀名。
第二种:DER Encoded Binary (.cer) 二进制编码的证书,证书中没有私钥,DER 编码二进制格式的证书文件,以.cer作为证书文件后缀名。
第三种:Base64 Encoded(.cer),Base64编码的证书,证书中没有私钥,BASE64 编码格式的证书文件,也是以.cer作为证书文件后缀名。

定义可以看出,只有pfx格式的数字证书是包含有私钥和公钥的,cer格式的数字证书里面只有公钥没有私钥

这里的公钥要私钥只是代表文件内容,并不是对公钥和私钥的定义,可认为能公开让大家都知道的文件为公钥,可以是后缀PFX的这个文件也可以是CER后缀的这个文件,这两个文件的本质是RSA加密的方式一种实现,其实就是两个互质的数,DER加密的文件PFX能解密,PFX加密的文件DER也能解密。

操作java加密和解密需要对KeyStore 和 Cipher 这两个类有大致的了解和使用。

首先是对 数据的加密PFX的使用示例,PFX文件的密码默认123456:


	/**
	 * 根据私钥文件加密
	 * 
	 * @param src
	 * @param pfxPath
	 * @param priKeyPass
	 * @return
	 */
	public static String encryptByPriPfxFile(String src, String pfxPath, String priKeyPass) {

		PrivateKey privateKey = getPrivateKeyFromFile(pfxPath, priKeyPass);
		if (privateKey == null) {
			return null;
		}
		return encryptByPrivateKey(src, privateKey);

	/**
	 * 根据私钥加密
	 * 
	 * @param src
	 * @param privateKey
	 */
	public static String encryptByPrivateKey(String src, PrivateKey privateKey) {

		byte[] destBytes = rsaByPrivateKey(src.getBytes(), privateKey, Cipher.ENCRYPT_MODE);

		if (destBytes == null) {
			return null;
		}
		return FormatUtil.byte2Hex(destBytes);

	}

/**
	 * 根据私钥路径读取私钥
	 * 
	 * @param pfxPath
	 * @param priKeyPass
	 * @return
	 */
	public static PrivateKey getPrivateKeyFromFile(String pfxPath, String priKeyPass) {
		InputStream priKeyStream = null;
		try {
			priKeyStream = new FileInputStream(pfxPath);
			byte[] reads = new byte[priKeyStream.available()];
			priKeyStream.read(reads);
			return getPrivateKeyByStream(reads, priKeyPass);
		} catch (Exception e) {
			// log.error("解析文件,读取私钥失败:", e);
		} finally {
			if (priKeyStream != null) {
				try {
					priKeyStream.close();
				} catch (Exception e) {
					//
				}
			}
		}
		return null;
	}

	/**
	 * 根据PFX私钥字节流读取私钥
	 * 
	 * @param pfxBytes
	 * @param priKeyPass
	 * @return
	 */
	public static PrivateKey getPrivateKeyByStream(byte[] pfxBytes, String priKeyPass) {
		try {
			String KEY_PKCS12 = "PKCS12";
			KeyStore ks = KeyStore.getInstance(RsaConst.KEY_PKCS12);
			char[] charPriKeyPass = priKeyPass.toCharArray();
			ks.load(new ByteArrayInputStream(pfxBytes), charPriKeyPass);
			Enumeration<String> aliasEnum = ks.aliases();
			String keyAlias = null;
			if (aliasEnum.hasMoreElements()) {
				keyAlias = (String) aliasEnum.nextElement();
			}
			return (PrivateKey) ks.getKey(keyAlias, charPriKeyPass);
		} catch (IOException e) {
			// 加密失败
			// log.error("解析文件,读取私钥失败:", e);
		} catch (KeyStoreException e) {
			// log.error("私钥存储异常:", e);
		} catch (NoSuchAlgorithmException e) {
			// log.error("不存在的解密算法:", e);
		} catch (CertificateException e) {
			// log.error("证书异常:", e);
		} catch (UnrecoverableKeyException e) {
			// log.error("不可恢复的秘钥异常", e);
		}
		return null;
	}

	/**
	 * 私钥算法
	 * 
	 * @param srcData
	 *            源字节
	 * @param privateKey
	 *            私钥
	 * @param mode
	 *            加密 OR 解密
	 * @return
	 */
	public static byte[] rsaByPrivateKey(byte[] srcData, PrivateKey privateKey, int mode) {
		try {
			String RSA_CHIPER = "RSA/ECB/PKCS1Padding";
			Cipher cipher = Cipher.getInstance(RsaConst.RSA_CHIPER);
			cipher.init(mode, privateKey);
			// 分段加密			
			int blockSize = (mode == Cipher.ENCRYPT_MODE) ? cipher.getOutputSize(srcData.length)-11 : cipher.getOutputSize(srcData.length);
			byte[] decryptData = null;
			
			for (int i = 0; i < srcData.length; i += blockSize) {
				byte[] doFinal = cipher.doFinal(subarray(srcData, i, i + blockSize));
				
				decryptData = addAll(decryptData, doFinal);
			}
			return decryptData;
		} catch (NoSuchAlgorithmException e) {
//			//log.error("私钥算法-不存在的解密算法:", e);
		} catch (NoSuchPaddingException e) {
			//log.error("私钥算法-无效的补位算法:", e);
		} catch (IllegalBlockSizeException e) {
			//log.error("私钥算法-无效的块大小:", e);
		} catch (BadPaddingException e) {
			//log.error("私钥算法-补位算法异常:", e);
		} catch (InvalidKeyException e) {
			//log.error("私钥算法-无效的私钥:", e);
		}
		return null;
	}

	public static byte[] subarray(byte[] array, int startIndexInclusive, int endIndexExclusive) {
		if (array == null) {
			return null;
		}
		if (startIndexInclusive < 0) {
			startIndexInclusive = 0;
		}
		if (endIndexExclusive > array.length) {
			endIndexExclusive = array.length;
		}
		int newSize = endIndexExclusive - startIndexInclusive;
				
		if (newSize <= 0) {
			return new byte[0];
		}

		byte[] subarray = new byte[newSize];

		System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);

		return subarray;
	}

	public static byte[] addAll(byte[] array1, byte[] array2) {
		if (array1 == null) {
			return clone(array2);
		} else if (array2 == null) {
			return clone(array1);
		}
		byte[] joinedArray = new byte[array1.length + array2.length];
		System.arraycopy(array1, 0, joinedArray, 0, array1.length);
		System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
		return joinedArray;
	}

	/**
	 * 将byte[] 转换成字符串
	 */
	public static String byte2Hex(byte[] srcBytes) {
		StringBuilder hexRetSB = new StringBuilder();
		for (byte b : srcBytes) {
			String hexString = Integer.toHexString(0x00ff & b);
			hexRetSB.append(hexString.length() == 1 ? 0 : "").append(hexString);
		}
		return hexRetSB.toString();
	}

大致流程为先用文件流InputStream 读取到PFX文件到byte[]数组中,在通过KeyStore类加载出来PrivateKey,拿到私钥之后就可以使用Cipher对需要加密的数据进行操作了,操作完成之后就是byte数据在转成16进制的字符串就是加密完成的数据了。
CER的待更新。。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值