本篇讲解基于 Java 语言,实现 HTTPs 和 RSA 加解密通信的 API 示例。 示例代码已提交到 Github,参考链接 Java 示例代码
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.StringUtils; import org.apache.log4j.Logger; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import java.io.*; import java.nio.charset.Charset; import java.security.*; import java.security.cert.CertificateException; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Enumeration; public class RSAUtil { private static Logger LOGGER = Logger.getLogger(RSAUtil.class); private static String KEY_ALGORITHM = "RSA"; public static final int KEY_SIZE = 2048; // 密钥长度, 一般2048 public static final int RESERVE_BYTES = 11; public final static String KEY_PKCS12 = "PKCS12"; public static final String CIPHER_ALGORITHM = "RSA/ECB/PKCS1Padding"; // 加密block需要预留11字节 public static final String SIGNATURE_ALGORITHM = "MD5withRSA";// sign值生成方式 public static final Charset CHARSET_UTF8 = Charset.forName("UTF-8"); private String algorithm;// 密钥生成模式 private String signature;// 签名sign生成模式 private Charset charset;// 编码格式 private int keySize;// RSA密钥长度必须是64的倍数,在512~65536之间 private int decryptBlock; // 默认keySize=2048的情况下, 256 bytes private int encryptBlock; // 默认keySize=2048的情况下, 245 bytes private static KeyFactory keyFactory; static { try { keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); } catch (NoSuchAlgorithmException e) { LOGGER.info("生成RSA密钥对异常," + e); } } public RSAUtil() { this(CIPHER_ALGORITHM); } public RSAUtil(String algorithm) { this(algorithm, CHARSET_UTF8); } public RSAUtil(int keySize) { this(CIPHER_ALGORITHM, keySize, CHARSET_UTF8, SIGNATURE_ALGORITHM); } public RSAUtil(String algorithm, Charset charset) { this(algorithm, KEY_SIZE, charset, SIGNATURE_ALGORITHM); } public RSAUtil(String algorithm, int keySize, Charset charset, String signature) { this.algorithm = algorithm; this.signature = signature; this.charset = charset; this.keySize = keySize; this.decryptBlock = this.keySize / 8; this.encryptBlock = decryptBlock - RESERVE_BYTES; } /** * 公钥加密 * @param publicKeyStr 公钥字符串 * @param data 需要加密的数据 * @return 加密后字符串 */ public String encrypt(String publicKeyStr, String data) { PublicKey publicKey = restorePublicKey(publicKeyStr); return encrypt(publicKey, data); } /** * 公钥加密 * @param publicKey 公钥 * @param data 需要加密的数据 * @return 加密后字符串 */ public String encrypt(PublicKey publicKey, String data) { byte[] bytes = data.getBytes(charset); return encrypt(publicKey, bytes); } /** * 公钥加密 * @param publicKey 公钥 * @param data 需要加密的数据 * @return 加密后字符串 */ public String encrypt(PublicKey publicKey, byte[] data) { byte[] encrypt = null; int dataLen = data.length; // 计算分段加密的block数 (向上取整) int nBlock = (dataLen / encryptBlock); if ((dataLen % encryptBlock) != 0) { // 余数非0,block数再加1 nBlock += 1; } // 输出buffer, 大小为nBlock个decryptBlock ByteArrayOutputStream outbuf = new ByteArrayOutputStream(nBlock * decryptBlock); try { Cipher cipher = getCipher(); cipher.init(Cipher.ENCRYPT_MODE, publicKey); // 分段加密 for (int offset = 0; offset < dataLen; offset += encryptBlock) { // block大小: encryptBlock 或 剩余字节数 int inputLen = (dataLen - offset); if (inputLen > encryptBlock) { inputLen = encryptBlock; } // 得到分段加密结果 byte[] encryptedBlock = cipher.doFinal(data, offset, inputLen); // 追加结果到输出buffer中 outbuf.write(encryptedBlock); } outbuf.flush(); encrypt = outbuf.toByteArray(); outbuf.close(); } catch (InvalidKeyException | BadPaddingException | IllegalBlockSizeException | IOException e) { LOGGER.info("使用RSA,加密数据异常", e); } byte[] enData = Base64.encodeBase64(encrypt); return StringUtils.newString(enData, charset.name()); } /** * 公钥解密 * @param publicKeyStr 公钥字符串 * @param data 需要解密的数据 * @return 解密后字符串 * @throws Exception 异常 */ public String decryptByPublicKey(String publicKeyStr, String data) throws Exception { PublicKey publicKey = restorePublicKey(publicKeyStr); return decryptByPublicKey(publicKey, data); } /** * 公钥解密 * @param publicKey 公钥 * @param data 需要解密的数据 * @return 解密后字符串 * @throws Exception 异常 */ public String decryptByPublicKey(PublicKey publicKey, String data) throws Exception { byte[] bytes = Base64.decodeBase64(data.getBytes(charset)); return decryptByPublicKey(publicKey, bytes); } /** * 公钥解密 * @param publicKey 公钥 * @param data 需要解密的数据 * @return 解密后字符串 * @throws Exception 异常 */ public String decryptByPublicKey(PublicKey publicKey, byte[] data) throws Exception { byte[] decrypt = null; int dataLen = data.length; // 计算分段解密的block数 (理论上应该能整除) int nBlock = (dataLen / decryptBlock); if ((dataLen % decryptBlock) != 0) { // 余数非0,block数再加1 nBlock += 1; } // 输出buffer, 大小为nBlock个encryptBlock ByteArrayOutputStream outbuf = new ByteArrayOutputStream(nBlock * encryptBlock); Cipher cipher = getCipher(); cipher.init(Cipher.DECRYPT_MODE, publicKey); // 分段解密 for (int offset = 0; offset < data.length; offset += decryptBlock) { // block大小: decryptBlock 或 剩余字节数 int inputLen = (data.length - offset); if (inputLen > decryptBlock) { inputLen = decryptBlock; } // 得到分段解密结果 byte[] decryptedBlock = cipher.doFinal(data, offset, inputLen); // 追加结果到输出buffer中 outbuf.write(decryptedBlock); } outbuf.flush(); decrypt = outbuf.toByteArray(); outbuf.close(); return StringUtils.newString(decrypt, charset.name()); } /** * 私钥加密 * @param privateKeyStr 私钥字符串 * @param data 需要加密的数据 * @return 加密后字符串 */ public String encryptByPrivateKey(String privateKeyStr, String data) { PrivateKey privateKey = restorePrivateKey(privateKeyStr); return encryptByPrivateKey(privateKey, data); } /** * 私钥加密 * @param privateKey 私钥 * @param data 需要加密的数据 * @return 加密后字符串 */ public String encryptByPrivateKey(PrivateKey privateKey, String data) { byte[] bytes = data.getBytes(charset); return encryptByPrivateKey(privateKey, bytes); } /** * 私钥加密 * @param privateKey 私钥 * @param data 需要加密的数据 * @return 加密后字符串 */ public String encryptByPrivateKey(PrivateKey privateKey, byte[] data) { byte[] encrypt = null; int dataLen = data.length; // 计算分段加密的block数 (向上取整) int nBlock = (dataLen / encryptBlock); if ((dataLen % encryptBlock) != 0) { // 余数非0,block数再加1 nBlock += 1; } // 输出buffer, 大小为nBlock个decryptBlock ByteArrayOutputStream outbuf = new ByteArrayOutputStream(nBlock * decryptBlock); try { Cipher cipher = getCipher(); cipher.init(Cipher.ENCRYPT_MODE, privateKey); // 分段加密 for (int offset = 0; offset < dataLen; offset += encryptBlock) { // block大小: encryptBlock 或 剩余字节数 int inputLen = (dataLen - offset); if (inputLen > encryptBlock) { inputLen = encryptBlock; } // 得到分段加密结果 byte[] encryptedBlock = cipher.doFinal(data, offset, inputLen); // 追加结果到输出buffer中 outbuf.write(encryptedBlock); } outbuf.flush(); encrypt = outbuf.toByteArray(); outbuf.close(); } catch (InvalidKeyException | BadPaddingException | IllegalBlockSizeException | IOException e) { LOGGER.info("使用RSA,加密数据异常", e); } byte[] enData = Base64.encodeBase64(encrypt); return StringUtils.newString(enData, charset.name()); } /** * 私钥加密 * @param privateKey 私钥 * @param data 需要加密的数据 * @return 加密后字符串 */ public String encryptByPrivateKeyBase64(PrivateKey privateKey, String data) { byte[] bytes = new String(new Base64().encode(data.getBytes(CHARSET_UTF8))).getBytes(CHARSET_UTF8); return encryptByPrivateKeyBase64(privateKey, bytes); } public String encryptByPrivateKeyBase64(PrivateKey privateKey, byte[] data) { byte[] encrypt = null; int dataLen = data.length; // 计算分段加密的block数 (向上取整) int nBlock = (dataLen / encryptBlock); if ((dataLen % encryptBlock) != 0) { // 余数非0,block数再加1 nBlock += 1; } // 输出buffer, 大小为nBlock个decryptBlock ByteArrayOutputStream outbuf = new ByteArrayOutputStream(nBlock * decryptBlock); try { Cipher cipher = getCipher(); cipher.init(Cipher.ENCRYPT_MODE, privateKey); // 分段加密 for (int offset = 0; offset < dataLen; offset += encryptBlock) { // block大小: encryptBlock 或 剩余字节数 int inputLen = (dataLen - offset); if (inputLen > encryptBlock) { inputLen = encryptBlock; } // 得到分段加密结果 byte[] encryptedBlock = cipher.doFinal(data, offset, inputLen); // 追加结果到输出buffer中 outbuf.write(encryptedBlock); } outbuf.flush(); encrypt = outbuf.toByteArray(); outbuf.close(); } catch (InvalidKeyException | BadPaddingException | IllegalBlockSizeException | IOException e) { LOGGER.info("使用RSA,加密数据异常", e); } StringBuilder hexRetSB = new StringBuilder(); for (byte b : encrypt) { String hexString = Integer.toHexString(0x00ff & b); hexRetSB.append(hexString.length() == 1 ? 0 : "").append(hexString); } return hexRetSB.toString(); } /** * 私钥解密 * @param privateKeyStr 私钥字符串 * @param data 需要解密的数据 * @return 解密后字符串 * @throws Exception 异常 */ public String decrypt(String privateKeyStr, String data) throws Exception { PrivateKey privateKey = restorePrivateKey(privateKeyStr); return decrypt(privateKey, data); } /** * 私钥解密 * @param privateKey 私钥 * @param data 需要解密的数据 * @return 解密后字符串 * @throws Exception 异常 */ public String decrypt(PrivateKey privateKey, String data) throws Exception { byte[] bytes = Base64.decodeBase64(data.getBytes(charset)); return decrypt(privateKey, bytes); } /** * 私钥解密 * @param privateKey 私钥 * @param data 需要解密的数据 * @return 解密后字符串 * @throws Exception 异常 */ public String decrypt(PrivateKey privateKey, byte[] data) throws Exception { byte[] decrypt = null; int dataLen = data.length; // 计算分段解密的block数 (理论上应该能整除) int nBlock = (dataLen / encryptBlock); if ((dataLen % encryptBlock) != 0) { // 余数非0,block数再加1 nBlock += 1; } // 输出buffer, 大小为nBlock个encryptBlock ByteArrayOutputStream outbuf = new ByteArrayOutputStream(nBlock * encryptBlock); Cipher cipher = getCipher(); cipher.init(Cipher.DECRYPT_MODE, privateKey); // 分段解密 for (int offset = 0; offset < data.length; offset += decryptBlock) { // block大小: decryptBlock 或 剩余字节数 int inputLen = (data.length - offset); if (inputLen > decryptBlock) { inputLen = decryptBlock; } // 得到分段解密结果 byte[] decryptedBlock = cipher.doFinal(data, offset, inputLen); // 追加结果到输出buffer中 outbuf.write(decryptedBlock); } outbuf.flush(); decrypt = outbuf.toByteArray(); outbuf.close(); return StringUtils.newString(decrypt, charset.name()); } /** * 根据keyFactory生成Cipher * @return cipher */ private Cipher getCipher() { Cipher cipher = null; try { cipher = Cipher.getInstance(this.algorithm); } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { LOGGER.info("生成RSA Cipher异常", e); } return cipher; } /** * 公钥还原,将公钥转化为PublicKey对象 * @param publicKeyStr 公钥字符串 * @return PublicKey对象 */ public PublicKey restorePublicKey(String publicKeyStr) { PublicKey publicKey = null; byte[] keyBytes = Base64.decodeBase64(publicKeyStr.getBytes(charset)); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); try { publicKey = keyFactory.generatePublic(x509KeySpec); } catch (InvalidKeySpecException e) { LOGGER.info("公钥还原,将公钥转化为PublicKey对象异常", e); } return publicKey; } /** * 私钥还原,将私钥转化为privateKey对象 * @param privateKeyStr 私钥字符串 * @return PrivateKey对象 */ public PrivateKey restorePrivateKey(String privateKeyStr) { PrivateKey privateKey = null; byte[] keyBytes = Base64.decodeBase64(privateKeyStr.getBytes(charset)); PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes); try { privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); } catch (InvalidKeySpecException e) { LOGGER.info("私钥还原,将私钥转化为privateKey对象异常", e); } return privateKey; } /** * 生成密钥对 * @param keySize 密钥长度 * @return 密钥对 */ public static KeyPair generateKeyPair(Integer keySize) { KeyPair keyPair = null; if (null == keySize) { keySize = KEY_SIZE; } try { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM); keyPairGen.initialize(keySize); keyPair = keyPairGen.generateKeyPair(); } catch (NoSuchAlgorithmException e) { LOGGER.info("RSA公私钥对生成异常:", e); } return keyPair; } /** * RSA生成sign值 * @param privateKeyStr 私钥字符串 * @param data 数据 * @return sign值 * @throws Exception 异常 */ public String generateSign(String privateKeyStr, String data) throws Exception { return generateSign(restorePrivateKey(privateKeyStr), data); } /** * RSA生成sign值 * @param privateKey 私钥 * @param data 数据 * @return sign值 * @throws Exception 异常 */ public String generateSign(PrivateKey privateKey, String data) throws Exception { Signature signature = Signature.getInstance(this.signature); signature.initSign(privateKey); signature.update(data.getBytes(charset)); return Base64.encodeBase64String(signature.sign()); } /** * RSA验签 * @param publicKeyStr 公钥字符串 * @param data 数据 * @param sign sign值 * @return 验签是否成功 * @throws Exception 异常 */ public boolean verifyRSA(String publicKeyStr, String data, String sign) throws Exception { return verifyRSA(restorePublicKey(publicKeyStr), data, sign); } /** * RSA验签 * @param publicKey 公钥 * @param data 数据 * @param sign sign值 * @return 验签是否成功 * @throws Exception 异常 */ public boolean verifyRSA(PublicKey publicKey, String data, String sign) throws Exception { Signature signature = Signature.getInstance(this.signature); signature.initVerify(publicKey); signature.update(data.getBytes(charset)); return signature.verify(Base64.decodeBase64(sign)); } /** * 读取密钥对 * * @param file 密钥文件 * @return 密钥对 */ public static KeyPair generateKeyPair(File file, String password) { KeyPair keyPair = null; if (null == file) { return keyPair; } // 文件内容 byte[] reads = null; FileInputStream inputStream = null; try { inputStream = new FileInputStream(file); reads = new byte[inputStream.available()]; inputStream.read(reads); } catch (FileNotFoundException e) { LOGGER.error("公钥文件不存在:", e); } catch (IOException e) { LOGGER.error("公钥文件读取失败:", e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (Exception e) { LOGGER.error("关闭文件流失败:", e); } } } String line = null; // 生成公钥 PublicKey publicKey = null; // 生成私钥 PrivateKey privateKey = null; try { KeyStore ks = KeyStore.getInstance(KEY_PKCS12); char[] charPriKeyPass = password.toCharArray(); ks.load(new ByteArrayInputStream(reads), charPriKeyPass); EnumerationaliasEnum = ks.aliases(); String keyAlias = null; if (aliasEnum.hasMoreElements()) { keyAlias = aliasEnum.nextElement(); } privateKey = (PrivateKey) ks.getKey(keyAlias, charPriKeyPass); } catch (IOException e) { // 加密失败 LOGGER.error("解析文件,读取私钥失败:", e); } catch (KeyStoreException e) { LOGGER.error("私钥存储异常:", e); } catch (NoSuchAlgorithmException e) { LOGGER.error("不存在的解密算法:", e); } catch (CertificateException e) { LOGGER.error("证书异常:", e); } catch (UnrecoverableKeyException e) { LOGGER.error("不可恢复的秘钥异常", e); } // if (null != publicKey && null != privateKey) { if (null != privateKey) { keyPair = new KeyPair(publicKey, privateKey); } else { throw new RuntimeException("加载密钥失败"); } return keyPair; } /** * 生成私钥 base64加密 * @param key 密钥 * @param charset 编码格式 * @return 私钥 */ public static String convertToString(Key key, Charset charset) { byte[] keyBytes = key.getEncoded(); return StringUtils.newString(Base64.encodeBase64(keyBytes), charset.name()); } public int getKeySize() { return keySize; } public Charset getCharset() { return charset; } }
2017-10-22