JAVA实现RSA生成公私钥/加解密/签名验签
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang3.StringUtils; import javax.crypto.Cipher; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class Sha1WithRsaUtil { static String reqParam = "{'aa':11,'cc':33,'ee':'','bb':22,'signType':'SHA1WithRSA','signData':'aa'}"; static String reqParam2 = "{\"aa\":11,\"cc\":33,\"ee\":\"\",\"bb\":22,\"signType\":\"SHA1WithRSA\",\"signData\":\"aa\"}"; /** * 加密算法RSA */ public static final String RSA_ALGORITHM = "RSA"; /** * 签名算法 * SHA1WithRSA MD5withRSA */ public static final String SIGNATURE_ALGORITHM = "SHA1WithRSA"; /** * 据说1024 加密不安全,默认 走2048加密 */ public static final int keySize = 2048; /** * 字符串编码 */ public static final String CHARSET = "UTF-8"; /** * 忽略不参与签名的参数 */ private static String signTypeKey = "signType"; private static String signDataKey = "signData"; /** * 请求参数按照ASCII 码升序排序,并用&连接字符串 * * @Param reqJson: 请求的json 串 * {'aa':11,'cc':33,'ee':'','bb':22,'signType':'SHA1WithRSA','signData':'aa'} * @Return: aa=11&bb=22&cc=3 */ public static String preSignDataProcess(String reqJson) { if (StringUtils.isEmpty(reqJson)) { return null; } HashMap<String, Object> map = JSON.parseObject(reqJson, new TypeReference<HashMap<String, Object>>() { }); List<String> keyList = map.keySet().stream().sorted().collect(Collectors.toList()); StringBuffer sb = new StringBuffer(); keyList.stream().forEach(k -> { Object v = map.get(k); if (v != null && !"".equals(v) && !signTypeKey.equals(k) && !signDataKey.equals(k)) { sb.append(k.trim()).append("=").append(v).append("&"); } }); if (sb.toString().endsWith("&")) { sb.deleteCharAt(sb.length() - 1); } return sb.toString(); } /** * 创建RSA 原始的公钥私钥 * * @return */ public static Map<String, String> createKeys() { return createKeys(keySize); } /** * 获取初始的公钥和私钥 * 1024 2048 */ private static Map<String, String> createKeys(int keySize) { // 为RSA算法创建一个KeyPairGenerator对象 KeyPairGenerator kpg; try { kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM); } catch (NoSuchAlgorithmException e) { throw new IllegalArgumentException("No such algorithm-->[" + RSA_ALGORITHM + "]"); } // 初始化KeyPairGenerator对象,密钥长度 kpg.initialize(keySize); // 生成密匙对 KeyPair keyPair = kpg.generateKeyPair(); // 得到公钥 Key publicKey = keyPair.getPublic(); String publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded()); // 得到私钥 Key privateKey = keyPair.getPrivate(); String privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded()); Map<String, String> keyPairMap = new HashMap<>(); keyPairMap.put("publicKey", publicKeyStr); keyPairMap.put("privateKey", privateKeyStr); return keyPairMap; } /** * 根据RSA初始公钥 转化为 X509公钥 * * @param publicKey 密钥字符串(经过base64编码) * @throws Exception */ public static RSAPublicKey getPublicKeyX509(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException { // 通过X509编码的Key指令获得公钥对象 KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey)); RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec); return key; } /** * 根据RSA初始私钥 转化为 PKCS8私钥 * * @param privateKey 密钥字符串(经过base64编码) * @throws Exception */ public static RSAPrivateKey getPrivateKeyPkcs8(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException { // 通过PKCS#8编码的Key指令获得私钥对象 KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey)); RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec); return key; } /** * 加密操作 * X509 公钥加密(对应 PKCS8 私钥进行解密) 或者 PKCS8 私钥加密(对应X509公钥解密) */ private static String encrypt(String data, Key key) { BigInteger modulus = keyModulus(key); try { Cipher cipher = cipherInstance(Cipher.ENCRYPT_MODE, key); byte[] bytes = rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), modulus.bitLength()); return Base64.encodeBase64URLSafeString(bytes); } catch (Exception e) { throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e); } } /** * 解密操作 * PKCS8 私钥解密(对应 X509 公钥加密)或者 X509 公钥解密(对应 PKCS8 私钥进行加密) */ private static String decrypt(String data, Key key) { BigInteger modulus = keyModulus(key); Cipher cipher = cipherInstance(Cipher.DECRYPT_MODE, key); byte[] bytes = rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), modulus.bitLength()); try { return new String(bytes, CHARSET); } catch (UnsupportedEncodingException e) { throw new RuntimeException("RSA解密失败:", e); } } /** * RSA签名 * * @param content 待签名数据 * @param privateKey 商户私钥 * @return 签名值 */ public static String sign(String content, String privateKey) { try { PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey)); KeyFactory keyf = KeyFactory.getInstance(RSA_ALGORITHM); PrivateKey priKey = keyf.generatePrivate(priPKCS8); java.security.Signature signature = java.security.Signature.getInstance(SIGNATURE_ALGORITHM); signature.initSign(priKey); signature.update(content.getBytes(CHARSET)); byte[] signed = signature.sign(); return Base64.encodeBase64URLSafeString(signed); } catch (Exception e) { throw new RuntimeException("签名发生异常", e); } } /** * RSA 验签 * * @param content 待签名数据 * @param sign 签名值 * @param publicKey 分配给开发商公钥 * @return 布尔值 */ public static boolean verify(String content, String sign, String publicKey) { try { KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM); byte[] encodedKey = Base64.decodeBase64(publicKey); PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey)); java.security.Signature signature = java.security.Signature.getInstance(SIGNATURE_ALGORITHM); signature.initVerify(pubKey); signature.update(content.getBytes(CHARSET)); boolean bverify = signature.verify(Base64.decodeBase64(sign)); return bverify; } catch (Exception e) { throw new RuntimeException("RSA 验签失败", e); } } /** * 分段处理 * * @param cipher * @param opmode * @param datas * @param keySize * @return */ private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize) { int maxBlock = 0; if (opmode == Cipher.DECRYPT_MODE) { maxBlock = keySize / 8; } else { maxBlock = keySize / 8 - 11; } ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; byte[] buff; byte[] resultDatas; Exception e1; int i = 0; try { while (datas.length > offSet) { if (datas.length - offSet > maxBlock) { buff = cipher.doFinal(datas, offSet, maxBlock); } else { buff = cipher.doFinal(datas, offSet, datas.length - offSet); } out.write(buff, 0, buff.length); i++; offSet = i * maxBlock; } resultDatas = out.toByteArray(); } catch (Exception e) { throw new RuntimeException("加解密阀值为[" + maxBlock + "]的数据时发生异常", e); } finally { try { out.close(); } catch (IOException e) { throw new RuntimeException("加解密阀值为[" + maxBlock + "]的数据时,关闭流发生异常", e); } } return resultDatas; } /** * 获取加密key的 实例 */ private static Cipher cipherInstance(int mode, java.security.Key key) { Cipher cipher = null; try { cipher = Cipher.getInstance(RSA_ALGORITHM); cipher.init(mode, key); } catch (Exception e) { throw new RuntimeException("获取Cipher 实例异常:", e); } return cipher; } private static BigInteger keyModulus(Key key) { BigInteger modulus = null; if (key instanceof RSAPublicKey) { modulus = ((RSAPublicKey) key).getModulus(); } else if (key instanceof RSAPrivateKey) { modulus = ((RSAPrivateKey) key).getModulus(); } return modulus; } public static void main(String[] args) throws Exception { Map<String, String> keyMap = createKeys(); String publicKey = keyMap.get("publicKey"); String privateKey = keyMap.get("privateKey"); System.out.println("原始公钥:\n" + publicKey); System.out.println("原始私钥:\n" + privateKey); String content = preSignDataProcess(reqParam); String sign = sign(content, privateKey); System.out.println("签名:\n" + sign); boolean verify = verify(content, sign, publicKey); System.out.println("验签:" + verify); String privateEncrypt = encrypt(content, getPrivateKeyPkcs8(privateKey)); System.out.println("PKCS8 私钥加密:\n" + privateEncrypt); String publicDecrypt = decrypt(privateEncrypt, getPublicKeyX509(publicKey)); System.out.println("X509 公钥解密:\n" + publicDecrypt); String publicEncrypt = encrypt(content, getPublicKeyX509(publicKey)); System.out.println("X509 公钥加密:\n" + publicEncrypt); String privateDecrypt = decrypt(publicEncrypt, getPrivateKeyPkcs8(privateKey)); System.out.println("PKCS8 私钥解密:\n" + privateDecrypt); } }