Rsa加密解密,支持分段加密解密,支持java,php

java版

package com.zmt.payment.common.encrypt.utils;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * @author : scott
 * @version : v1.0
 * @calssname : Rsa
 * @date : 2022/3/28 18:22
 * @status : create
 * @description :RSA 非对称加密 标准版-官方发布参考Oracle整合
 * 缺点:加密长度受密钥长度限制,导致加密数据长度不能超过总数据长度的   定值比例
 *  

* 需要依赖 Apache Commons Codec *

* Apache Commons Codec 软件包包含各种格式的简单编码器和解码器,如Base64和Hexadecimal。 * 除了这些广泛使用的编码器和解码器之外,编解码器包还维护一组语音编码实用程序。 */ public class RsaOfficial { /** * 加密算法类型 *

* 只能是:DiffieHellman、DSA、RSA、EC * * @see KeyPairGenerator Algorithms */ static final String ALGORITHM_KEY = "RSA"; /** * 算法长度 * DiffieHellman(1024)、DSA(1024)、RSA(1024,2048) * * @see Class KeyPairGenerator */ // private static final int KEY_SIZE = 1024; private static final int KEY_SIZE = 2048; /** * 初始化秘钥对 * * @return 标准密钥对 * @see KeyPairGenerator Algorithms */ public static KeyPair initKeyPair() { try { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM_KEY); keyPairGenerator.initialize(KEY_SIZE); return keyPairGenerator.generateKeyPair(); } catch (NoSuchAlgorithmException e) { throw new IllegalStateException(e); } } /** * 初始化密钥对 * * @return 字节数组数据类型的密钥对 * @see #initKeyPair() */ public static ByteKey getByteKey() { KeyPair keyPair = initKeyPair(); return new ByteKey( keyPair.getPublic() , keyPair.getPrivate()); } /** * 初始化密钥对 * * @return String 类型的密钥对 * @see #initKeyPair() */ public static StringKey getStringKey() { KeyPair keyPair = initKeyPair(); return new StringKey( keyPair.getPublic() , keyPair.getPrivate()); } /** * 通过公钥加密数据 * * @param publicKeyByte 公钥,字节数组类型 * @param dataByte 需要加密的数据,字节数组类型 * @return 返回公钥加密数据 * @throws InvalidKeySpecException 使用字节数据类型的公钥根据指定算法生成公钥时异常 * 可能出现的原因: * 1、公钥错误 * 2、公钥与算法不匹配 * @throws NoSuchPaddingException 本例中不出现 * 使用 {@link KeyPairGenerator#getInstance(String, String)}、 * {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常 * @throws InvalidKeyException 秘钥无效、秘钥与秘钥类型不匹配 * @throws BadPaddingException 秘钥错误 * @throws IllegalBlockSizeException 加密模块长度不合法 * 长度限制:需要加密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11) * @see #publicKey(byte[], byte[], int) * @see #privateKeyDecryptByte(byte[], byte[]) 对应解密时使用 */ public static byte[] publicKeyEncryptByte(byte[] publicKeyByte, byte[] dataByte) throws InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { return publicKey( publicKeyByte , dataByte , Cipher.ENCRYPT_MODE); } /** * 通过私钥解密数据 * * @param privateKeyByte 私钥,字节数组类型 * @param dataByte 需要解密的数据,字节数组类型 * @return 返回通过私钥解密的数据,字节数组类型 * @throws InvalidKeySpecException 使用字节数据类型的公钥根据指定算法生成公钥时异常 * 可能出现的原因: * 1、公钥错误 * 2、公钥与算法不匹配 * @throws NoSuchPaddingException 本例中不出现 * 使用 {@link KeyPairGenerator#getInstance(String, String)}、 * {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常 * @throws InvalidKeyException 秘钥无效、秘钥与秘钥类型不匹配 * @throws BadPaddingException 秘钥错误 * @throws IllegalBlockSizeException 加密模块长度不合法 * 长度限制:需要加密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11) * @see #privateKey(byte[], byte[], int) * @see #publicKeyEncryptByte(byte[], byte[]) 对应加密时使用 */ public static byte[] privateKeyDecryptByte(byte[] privateKeyByte, byte[] dataByte) throws InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { return privateKey( privateKeyByte , dataByte , Cipher.DECRYPT_MODE); } /** * 通过公钥加密数据 * * @param publicKey 公钥 * @param data 需要加密的数据 * @return 返回公钥加密数据 * @throws InvalidKeySpecException 使用字节数据类型的公钥根据指定算法生成公钥时异常 * 可能出现的原因: * 1、公钥错误 * 2、公钥与算法不匹配 * @throws NoSuchPaddingException 本例中不出现 * 使用 {@link KeyPairGenerator#getInstance(String, String)}、 * {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常 * @throws InvalidKeyException 秘钥无效、秘钥与秘钥类型不匹配 * @throws BadPaddingException 秘钥错误 * @throws IllegalBlockSizeException 加密模块长度不合法 * 长度限制:需要加密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11) * @see #privateKey(byte[], byte[], int) * @see #privateKeyDecrypt(String, String) 对应解密时使用 */ public static String publicKeyEncrypt(String publicKey, String data) throws InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { return Base64.encodeBase64String( publicKeyEncryptByte( Base64.decodeBase64(publicKey) , data.getBytes()) ); } /** * 通过私钥解密数据 * * @param privateKey 私钥 * @param data 需要解密的数据 * @return 返回私钥解密数据 * @throws InvalidKeySpecException 使用字节数据类型的公钥根据指定算法生成公钥时异常 * 可能出现的原因: * 1、公钥错误 * 2、公钥与算法不匹配 * @throws NoSuchPaddingException 本例中不出现 * 使用 {@link KeyPairGenerator#getInstance(String, String)}、 * {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常 * @throws InvalidKeyException 秘钥无效、秘钥与秘钥类型不匹配 * @throws BadPaddingException 秘钥错误 * @throws IllegalBlockSizeException 加密模块长度不合法 * 长度限制:需要加密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11) * @see #publicKey(byte[], byte[], int) * @see #publicKeyEncrypt(String, String) 对应加密时使用 */ public static String privateKeyDecrypt(String privateKey, String data) throws InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { return new String( privateKeyDecryptByte( Base64.decodeBase64(privateKey) , Base64.decodeBase64(data)) ); } /** * 通过私钥加密数据 * * @param privateKeyByte 私钥,字节数组类型 * @param dataByte 需要解密的数据,字节数组类型 * @return 返回私钥加密数据,字节数组类型 * @throws NoSuchPaddingException 本例中不出现 * 使用 {@link KeyPairGenerator#getInstance(String, String)}、 * {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常 * @throws IllegalBlockSizeException 加密模块长度不合法 * 长度限制:需要加密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11) * @throws BadPaddingException 秘钥错误 * @throws InvalidKeyException 秘钥无效、秘钥与秘钥类型不匹配 * @throws InvalidKeySpecException 使用字节数据类型的公钥根据指定算法生成公钥时异常 * 可能出现的原因: * 1、公钥错误 * 2、公钥与算法不匹配 * @see #privateKey(byte[], byte[], int) * @see #publicKeyDecryptByte(byte[], byte[]) 对应解密时使用 */ public static byte[] privateKeyEncryptByte(byte[] privateKeyByte, byte[] dataByte) throws NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException { return privateKey( privateKeyByte , dataByte , Cipher.ENCRYPT_MODE); } /** * 通过公钥解密数据 * * @param publicKeyByte 公钥,字节数组类型 * @param dataByte 需要加密的数据,字节数组类型 * @return 返回公钥解密数据,字节数组类型 * @throws NoSuchPaddingException 本例中不出现 * 使用 {@link KeyPairGenerator#getInstance(String, String)}、 * {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常 * @throws IllegalBlockSizeException 加密模块长度不合法 * 长度限制:需要加密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11) * @throws BadPaddingException 秘钥错误 * @throws InvalidKeyException 秘钥无效、秘钥与秘钥类型不匹配 * @throws InvalidKeySpecException 使用字节数据类型的公钥根据指定算法生成公钥时异常 * 可能出现的原因: * 1、公钥错误 * 2、公钥与算法不匹配 * @see #publicKey(byte[], byte[], int) * @see #privateKeyEncryptByte(byte[], byte[]) 对应加密时使用 */ public static byte[] publicKeyDecryptByte(byte[] publicKeyByte, byte[] dataByte) throws NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException { return publicKey( publicKeyByte , dataByte , Cipher.DECRYPT_MODE); } /** * 通过私钥加密数据 * * @param privateKey 私钥 * @param data 需要解密的数据 * @return 私密加密的数据 * @throws NoSuchPaddingException 本例中不出现 * 使用 {@link KeyPairGenerator#getInstance(String, String)}、 * {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常 * @throws IllegalBlockSizeException 加密模块长度不合法 * 长度限制:需要加密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11) * @throws BadPaddingException 秘钥错误 * @throws InvalidKeyException 秘钥无效、秘钥与秘钥类型不匹配 * @throws InvalidKeySpecException 使用字节数据类型的公钥根据指定算法生成公钥时异常 * 可能出现的原因: * 1、公钥错误 * 2、公钥与算法不匹配 * @see #privateKey(byte[], byte[], int) * @see #publicKeyDecrypt(String, String) 对应解密时使用 */ public static String privateKeyEncrypt(String privateKey, String data) throws NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException { return Base64.encodeBase64String( privateKey( Base64.decodeBase64(privateKey) , data.getBytes() , Cipher.ENCRYPT_MODE) ); } /** * 通过公钥解密数据 * * @param publicKey 公钥,字节数组类型 * @param data 需要加密的数据,字节数组类型 * @return 返回公钥解密数据,字节数组类型 * @throws NoSuchPaddingException 本例中不出现 * 使用 {@link KeyPairGenerator#getInstance(String, String)}、 * {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常 * @throws IllegalBlockSizeException 加密模块长度不合法 * 长度限制:需要加密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11) * @throws BadPaddingException 秘钥错误 * @throws InvalidKeyException 秘钥无效、秘钥与秘钥类型不匹配 * @throws InvalidKeySpecException 使用字节数据类型的公钥根据指定算法生成公钥时异常 * 可能出现的原因: * 1、公钥错误 * 2、公钥与算法不匹配 * @see #publicKey(byte[], byte[], int) * @see #privateKeyEncrypt(String, String) 对应加密时使用 */ public static String publicKeyDecrypt(String publicKey, String data) throws NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidKeySpecException { return new String( publicKey( Base64.decodeBase64(publicKey) , Base64.decodeBase64(data) , Cipher.DECRYPT_MODE) ); } /** * 通过公钥加密、解密数据 * * @param publicKeyByte 公钥,字节数组类型 * @param dataByte 需要加密的数据,字节数组类型 * @param encryptOrDecrypt 加密还是解密 * 加密:{@link Cipher#ENCRYPT_MODE} * 解密:{@link Cipher#DECRYPT_MODE} * @return 返回通过公钥加密的数据 * @throws InvalidKeySpecException 使用字节数据类型的公钥根据指定算法生成公钥时异常 * 可能出现的原因: * 1、公钥错误 * 2、公钥与算法不匹配 * @throws NoSuchPaddingException 本例中不出现 * 使用 {@link KeyPairGenerator#getInstance(String, String)}、 * {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常 * @throws InvalidKeyException 秘钥无效、秘钥与秘钥类型不匹配 * @throws BadPaddingException 秘钥错误 * 可能出现的错误:秘钥与秘钥类型不匹配 * @throws IllegalBlockSizeException 加密模块长度不合法 * 长度限制:需要加密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11) * @see KeyFactory Algorithms */ private static byte[] publicKey(byte[] publicKeyByte, byte[] dataByte, int encryptOrDecrypt) throws InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyByte); KeyFactory keyFactory; try { keyFactory = KeyFactory.getInstance(ALGORITHM_KEY); } catch (NoSuchAlgorithmException e) { throw new IllegalStateException(e); } Key publicKey = keyFactory.generatePublic(x509KeySpec); String algorithmPublicKey = keyFactory.getAlgorithm(); Cipher cipherPublicKey; try { cipherPublicKey = Cipher.getInstance(algorithmPublicKey); } catch (NoSuchAlgorithmException e) { throw new IllegalStateException(e); } cipherPublicKey.init(encryptOrDecrypt, publicKey); return cipherPublicKey.doFinal(dataByte); } /** * 通过私钥加密、解密数据 * * @param privateKeyByte 私钥,字节数组类型 * @param dataByte 需要解密的数据,字节数组类型 * @param encryptOrDecrypt 加密还是解密 * 加密:{@link Cipher#ENCRYPT_MODE} * 解密:{@link Cipher#DECRYPT_MODE} * @return 返回通过私钥解密的数据,字节数组类型 * @throws InvalidKeySpecException 使用字节数据类型的私钥根据指定算法生成私钥时异常 * 可能出现的原因: * 1、私钥错误 * 2、私钥与算法不匹配 * @throws NoSuchPaddingException 本例中不出现 * 使用 {@link KeyPairGenerator#getInstance(String, String)}、 * {@link KeyPairGenerator#getInstance(String, Provider)} 时可能会出现此异常 * @throws InvalidKeyException 秘钥无效、秘钥与秘钥类型不匹配 * @throws BadPaddingException 秘钥错误 * 可能出现的错误:秘钥与秘钥类型不匹配 * @throws IllegalBlockSizeException 解密模块长度不合法 * 长度限制:需要解密的数组字节数据长度 小于 (数据加密算法模块长度 / 8 - 11) * @see KeyFactory Algorithms */ private static byte[] privateKey(byte[] privateKeyByte, byte[] dataByte, int encryptOrDecrypt) throws InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { KeyFactory keyFactory; try { keyFactory = KeyFactory.getInstance(ALGORITHM_KEY); } catch (NoSuchAlgorithmException e) { throw new IllegalStateException(e); } PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyByte); String algorithmPrivateKey = keyFactory.getAlgorithm(); Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipherPrivateKey; try { cipherPrivateKey = Cipher.getInstance(algorithmPrivateKey); } catch (NoSuchAlgorithmException e) { throw new IllegalStateException(e); } cipherPrivateKey.init(encryptOrDecrypt, privateKey); return cipherPrivateKey.doFinal(dataByte); } /** * 字节数据类型的密钥对 */ public static class ByteKey { /** * 公钥 */ private final byte[] publicKey; /** * 私钥 */ private final byte[] privateKey; /** * 构造器 * * @param publicKey 公钥 * @param privateKey 私钥 */ private ByteKey(PublicKey publicKey, PrivateKey privateKey) { this.publicKey = publicKey.getEncoded(); this.privateKey = privateKey.getEncoded(); } /** * 获取公钥 * * @return 返回公钥 */ public byte[] getPublicKey() { return publicKey; } /** * 获取私钥,byte[] * * @return 返回私钥,byte[] */ public byte[] getPrivateKey() { return privateKey; } } /** * String数据类型的密钥对 */ public static class StringKey { /** * 公钥 */ private final String publicKey; /** * 私钥 */ private final String privateKey; /** * 构造器 * * @param publicKey 公钥 * @param privateKey 私钥 */ private StringKey(PublicKey publicKey, PrivateKey privateKey) { this.publicKey = Base64.encodeBase64String(publicKey.getEncoded()); this.privateKey = Base64.encodeBase64String(privateKey.getEncoded()); } /** * 获取公钥 * * @return 返回公钥,String */ public String getPublicKey() { return publicKey; } /** * 获取私钥 * * @return 返回私钥,String */ public String getPrivateKey() { return privateKey; } } } package com.zmt.payment.common.encrypt.utils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang3.ArrayUtils; import javax.crypto.Cipher; import java.security.*; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; /** * @author : scott * @version : v1.0 * @calssname : RsaCustomize * @date : 2022/3/28 22:36 * @status : create * @description : RSA 非对称加密 自定义版 */ @Slf4j public class Rsa { /** * 加密算法类型 */ static final String ALGORITHM_KEY = "RSA"; /** * 算法长度 1024 or 2048 */ private static final int KEY_SIZE = 2048; /** * 加密数据拆分节点 */ private static final int MAX_ENCRYPT_BLOCK = (KEY_SIZE / 8) -11; /** * 解密数据拆分节点 */ private static final int MAX_DECRYPT_BLOCK = KEY_SIZE / 8; public static final String SIGN_ALGORITHMS = "SHA256withRSA"; /** * 算法实例 */ private static String ALGORITHM_RSA = "RSA"; /** 密钥流程:初始化密钥 -> (公钥 + 私钥)对 **/ /** 加密流程:客户端 -> 公钥+待解密数据 -> 加密数据 **/ /** 解密流程:服务端 -> 私钥钥+加密密数据 -> 解密数据 **/ /** 签名流程:商户端 -> 公钥 * 公钥加密数据 + 私钥 = 签名数据 * * 平台端: -> 私钥 * 私钥加密数据 + 私钥 = 签名 * * 验签流程:商户端 -> 校验平台签名 * 私钥加密数据 + 私钥签名 + 公钥 * * 平台端 -> 校验商户签名 * 公钥加密数据 + 公钥签名 + 公钥 * **/ /** 验签流程:服务端 -> 私钥钥+加密密数据 -> 解密数据 **/ /** * 使用公钥将数据加密 * @param sourceData:原始字符串 * @param publicKey:公钥 * @return */ public static String publicEncrypt(String sourceData , String publicKey){ return rsaEncrypt( sourceData , publicKey , Boolean.FALSE); } /** * 使用私钥将数据加密 * @param sourceData:原始字符串 * @param privateKey:私钥 * @return */ public static String privateEncrypt(String sourceData , String privateKey){ return rsaEncrypt( sourceData , privateKey , Boolean.TRUE); } /** * 使用公钥解密 * @param encryptedData:私钥加密数据 * @param privateKey:(公钥)私钥 * @return */ public static String publicDecrypt(String encryptedData , String privateKey) { return rsaDecrypt( encryptedData , privateKey , Boolean.FALSE); } /** * 使用私钥解密 * @param encryptedData:公钥加密数据 * @param privateKey:私钥 * @return */ public static String privateDecrypt(String encryptedData , String privateKey) { return rsaDecrypt( encryptedData , privateKey , Boolean.TRUE); } /** * RSA加密算法 - 分段 * @param sourceData:待加密数据/原始数据 * @param key :公钥/私钥 * @param isPrivate TRUE = 私钥 | FALSE = 公钥 * @return */ protected static String rsaEncrypt(String sourceData , String key , Boolean isPrivate){ try { Key key1 = isPrivate ? loadPrivateKey(key) : loadPublicKey(key); byte[] data = sourceData.getBytes(); byte[] dataReturn = new byte[0]; Cipher cipher = Cipher.getInstance(ALGORITHM_RSA); cipher.init(Cipher.ENCRYPT_MODE, key1); // 加密时超过117/245字节就报错。为此采用分段加密的办法来加密 StringBuilder sb = new StringBuilder(); for (int i = 0; i < data.length; i += MAX_ENCRYPT_BLOCK) { byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i,i + MAX_ENCRYPT_BLOCK)); sb.append(new String(doFinal)); dataReturn = ArrayUtils.addAll(dataReturn, doFinal); } return Base64.encodeBase64URLSafeString(dataReturn); } catch (Exception e) { e.printStackTrace(); return null; } } /** * RSA解密算法 - 分段 * @param encryptedData:加密数据/待解密数据 * @param key:公钥/私钥 * @param isPrivate TRUE = 私钥 | FALSE = 公钥 * @return */ protected static String rsaDecrypt(String encryptedData, String key , Boolean isPrivate){ try { Key key1 = isPrivate ? loadPrivateKey(key) : loadPublicKey(key); byte[] data = Base64.decodeBase64(encryptedData); Cipher cipher = Cipher.getInstance(ALGORITHM_RSA); cipher.init(Cipher.DECRYPT_MODE, key1); // 解密时超过128字节就报错。为此采用分段解密的办法来解密 byte[] dataReturn = new byte[0]; for (int i = 0; i < data.length; i += MAX_DECRYPT_BLOCK) { byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + MAX_DECRYPT_BLOCK)); dataReturn = ArrayUtils.addAll(dataReturn, doFinal); } return new String(dataReturn); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 私钥签名 * @param encryptData:加密数据 * @param privateKey:私钥 * @return */ public static String rsaSign(String encryptData , String privateKey) { try { Signature signature = Signature.getInstance(SIGN_ALGORITHMS); signature.initSign(loadPrivateKey(privateKey)); signature.update(encryptData.getBytes()); byte[] signed = signature.sign(); return Base64.encodeBase64URLSafeString(signed); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 公钥验签 * @param encryptStr:加密数据 * @param sign:签名数据 * @param publicKey:公钥 * @return * @throws Exception */ public static boolean verifySign(String encryptStr , String sign , String publicKey)throws Exception { try { Signature signature = Signature.getInstance(SIGN_ALGORITHMS); signature.initVerify(loadPublicKey(publicKey)); signature.update(encryptStr.getBytes()); return signature.verify(Base64.decodeBase64(sign)); } catch (NoSuchAlgorithmException e) { throw new Exception(String.format("验证数字签名时没有[%s]此类算法", SIGN_ALGORITHMS)); } catch (InvalidKeyException e) { throw new Exception("验证数字签名时公钥无效"); } catch (SignatureException e) { throw new Exception("验证数字签名时出现异常"); } } /** * 字符串转加载公钥 * @param publicKeyStr * @return * @throws Exception */ public static PublicKey loadPublicKey(String publicKeyStr) throws Exception { byte[] buffer = Base64.decodeBase64(publicKeyStr); KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer); return keyFactory.generatePublic(keySpec); } /** * 字符串转加载私钥 * @param privateKeyStr * @return * @throws Exception */ public static PrivateKey loadPrivateKey(String privateKeyStr) throws Exception { byte[] buffer = Base64.decodeBase64(privateKeyStr); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer); KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA); return keyFactory.generatePrivate(keySpec); } /** * URL安全编码器 * @param encryptStr * @return */ public static String urlsafe_encode (String encryptStr){ return encryptStr .replaceAll("\\+","-") .replaceAll("/","_") .replaceAll("=","") .replaceAll("(\r\n|\r|\n|\n\r)",""); } /** * URL安全解码器 * @param encryptStr * @return */ public static String urlsafe_decode(String encryptStr){ encryptStr= encryptStr .replaceAll("-","+") .replaceAll("_","/"); int mob = encryptStr.length() % 4; if(mob > 0){ encryptStr += "====".substring(mob); } return encryptStr; } /** * 加解密测试 * @param args * @throws Exception */ public static void main(String[ ] args) throws Exception { // 密钥生成 2048 Long startTime = System.currentTimeMillis(); RsaOfficial.StringKey key = RsaOfficial.getStringKey(); String publicKeyStr = key.getPublicKey(); String privateKeyStr = key.getPrivateKey(); Long keyTime = System.currentTimeMillis(); log.warn("密钥生成耗时:{} ms" , (keyTime - startTime)); //加密 String data = "i like java"; data = "{\"emptyBillingInfo\":true,\"inWebsiteType\":\"default\",\"merOrderNo\":\"13396670-20220327005549\",\"merchantNo\":\"1009\",\"notifyUrl\":\"https://pay.wechatka.com/apg/wechatka/notify/13396670\",\"payAmount\":\"5.48\",\"payCurrency\":\"USD\",\"returnUrl\":\"https://pay.wechatka.com/apg/wechatka/return/13396670\",\"sign\":\"fadb2b66f9275e3ee56a80761967ce25d9ca0cceb16e29f7eb9569004899386c60518a19a7d0c91d24aa44547eef0657f63bedd549f7c32183f9c2eb1567efc4\",\"tranCode\":\"TA002\",\"goods\":\"[{price:5.48,num:1,name:抖币}]\"}"; String privateEncryptStr = privateEncrypt(data , privateKeyStr); String publicEncryptStr = publicEncrypt(data , publicKeyStr); String privateEncryptSign = rsaSign(privateEncryptStr , privateKeyStr); String publicEncryptSign = rsaSign(publicEncryptStr , privateKeyStr); log.info("公钥:{}" , publicKeyStr); log.info("私钥:{}" , privateKeyStr); log.info("原始数据:{}" , data); log.info("私钥加密数据: " + privateEncryptStr); log.info("公钥加密数据: " + publicEncryptStr); log.info("私钥签名: " + privateEncryptSign); log.info("公钥签名: " + publicEncryptSign); log.info("公钥解密:" + publicDecrypt(privateEncryptStr , publicKeyStr)); log.info("私钥解密:" + privateDecrypt(publicEncryptStr , privateKeyStr)); log.info("verifySign1: " + verifySign(privateEncryptStr , privateEncryptSign , publicKeyStr)); log.info("verifySign2: " + verifySign(publicEncryptStr , publicEncryptSign , publicKeyStr)); } }

php版

private_key =str_replace(array("\r\n", "\r", "\n"), "", $this->private_key);
            $this->private_key =  "-----BEGIN PRIVATE KEY-----\n" . wordwrap($this->private_key, 64, "\n",true) . "\n-----END PRIVATE KEY-----";
            //这个函数可用来判断私钥是否是可用的,可用返回资源id Resource id
            $this->pi_key =  openssl_pkey_get_private($this->private_key);
            
            //公钥太长,格式不对。使用此方法格式化公钥
            $this->public_key =str_replace(array("\r\n", "\r", "\n"), "", $this->public_key);
            $this->public_key =  "-----BEGIN PUBLIC KEY-----\n" . wordwrap($this->public_key, 64, "\n",true) . "\n-----END PUBLIC KEY-----";
            //这个函数可用来判断公钥是否是可用的
            $this->pu_key = openssl_pkey_get_public($this->public_key);
        }
  
 
        //加密码时把特殊符号替换成URL可以带的内容
        function urlsafe_b64encode($string) {
            $data = base64_encode($string);
            $data = str_replace(array('+','/','='),array('-','_',''),$data);
            return $data;
        }
 
        //解密码时把转换后的符号替换特殊符号
        function urlsafe_b64decode($string) {
            $data = str_replace(array('-','_'),array('+','/'),$string);
            $mod4 = strlen($data) % 4;
            if ($mod4) {
                $data .= substr('====', $mod4);
            }
            return base64_decode($data);
        }
 
         //私钥加密
        public function PrivateEncrypt($data){
           // openssl_private_encrypt($data,$encrypted,$this->pi_key);
            $crypto = '';
            foreach (str_split($data, 117) as $chunk) {
                openssl_private_encrypt($chunk, $encryptData, $this->pi_key);
                $crypto .= $encryptData;
            }
            $encrypted = $this->urlsafe_b64encode($crypto);//加密后的内容通常含有特殊字符,需要编码转换下,在网络间通过url传输时要注意base64编码是否是url安全的
            return $encrypted;
        }
 
        //私钥加密的内容通过公钥解密出来
        public function PublicDecrypt($encrypted){
            $crypto = '';
            foreach (str_split($this->urlsafe_b64decode($encrypted), 128) as $chunk) {
                openssl_public_decrypt($chunk, $decryptData, $this->pu_key);
                $crypto .= $decryptData;
            }
            return $crypto;
        }
 
        //公钥加密
        public function PublicEncrypt($data){
            //openssl_public_encrypt($data,$encrypted,$this->pu_key);//公钥加密
            $crypto = '';
            foreach (str_split($data, 117) as $chunk) {
                openssl_public_encrypt($chunk, $encryptData, $this->pu_key);
                $crypto .= $encryptData;
            }
            $encrypted = $this->urlsafe_b64encode($crypto);
            return $encrypted;
        }
 
        //公钥加密的内容通过私钥解密出来。密文过长,使用此方法进行解密。
        public function PrivateDecrypt($encrypted)
        {
            $pub_id = openssl_get_publickey($this->pu_key);
            $key_len = openssl_pkey_get_details($pub_id)['bits'];
            $part_len = $key_len/8;
            $crypto = '';
            foreach (str_split($this->urlsafe_b64decode($encrypted), $part_len) as $chunk) {
                openssl_private_decrypt($chunk, $decryptData, $this->pi_key);
                $crypto .= $decryptData;
            }
            return $crypto;
        }

}


//使用方法
$rsa = new OpensslRSA();
//待加密的明文
$data = '0123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255';
//明文公钥加密
$encrypt_data = $rsa -> PublicEncrypt($data);
//密文私钥解密
$decrypt_data = $rsa -> PrivateDecrypt($encrypt_data);

// echo $encrypt_data;
echo $decrypt_data;


你可能感兴趣的:(RSA,java)