Java,PHP RSA加密解密,分段加解密及RSA签名

本文介绍了在对接第三方支付系统时确保通信安全的RSA加密解密和签名方法。重点讨论了RSA密钥长度对加解密的影响,如1024位密钥的加密长度为117,解密长度为128,以及2048位密钥的相关长度。同时提供了本地生成RSA密钥对的工具地址,以及JAVA和PHP的RSA加解密和签名的工具类源码及调用示例。
摘要由CSDN通过智能技术生成
  1. 对接第三方支付系统接口,为这通信的安全性,通常有MD5签名,RSA签名为主,今天主要讲解RSA加解密及签名。
  2. RSA密钥长度有1024和2048位的,由于RSA加密的特殊性,文本内容过长不进行分段加密的话会出来加密失败
  3. 1024加密长度为:117,解密长度为:128; 2048加密长度为:245,解密长度为:256,这个地方特别需要注意,根据密钥长度修改不同的参数值
  4. 本地生成密钥对工具地址:本地生成RSA密钥对工具包,RSA加密解密-Java文档类资源-CSDN下载

JAVA RSA加解密工具类源码:

package com.pay.utils;

import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
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.Map;

import javax.crypto.Cipher;

public class RSAEncrypt {
    /**
     * 字节数据转字符串专用集合
     */
    private static final char[] HEX_CHAR = { '0', '1', '2', '3', '4', '5', '6',
            '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

    /**
	 * 加密算法RSA
	 */
	public static final String KEY_ALGORITHM = "RSA";
	
	/**
	 * 公钥
	 */
	public static final String PUBLIC_KEY = "publicKey";
	
	/**
	 * 私钥
	 */
	public static final String PRIVATE_KEY = "privateKey";
	
	/**
	 * RSA最大加密明文大小
	 */
	private static final int MAX_ENCRYPT_BLOCK = 245;

	/**
	 * RSA最大解密密文大小
	 */
	private static final int MAX_DECRYPT_BLOCK = 256;
	
    public static Map<String, String> generatorRSAKey(){
        //获得对象 KeyPairGenerator 参数 RSA 2048个字节
        KeyPairGenerator keyPairGen = null;
		try {
			keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
        keyPairGen.initialize(2048);
        //通过对象 KeyPairGenerator 获取对象KeyPair
        KeyPair keyPair = keyPairGen.generateKeyPair();
        byte[] publicBytes = keyPair.getPublic().getEncoded();
        byte[] privateBytes = keyPair.getPrivate().getEncoded();
        //公私钥对象存入map中
        Map<String, String> keyMap = new HashMap<String, String>();
        keyMap.put(PUBLIC_KEY, Base64.encode(publicBytes));
        keyMap.put(PRIVATE_KEY, Base64.encode(privateBytes));
        return keyMap;
    }
    
    /**
     * 从字符串中加载公钥
     *
     * @param publicKeyStr
     *            公钥数据字符串
     * @throws Exception
     *             加载公钥时产生的异常
     */
    public static RSAPublicKey getPublicKey(String publicKeyStr)
            throws Exception {
        try {
            byte[] buffer = Base64.decode(publicKeyStr);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
            return (RSAPublicKey) keyFactory.generatePublic(keySpec);
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此算法");
        } catch (InvalidKeySpecException e) {
            throw new Exception("公钥非法");
        } catch (NullPointerException e) {
            throw new Exception("公钥数据为空");
        }
    }

    public static RSAPrivateKey getPrivateKey(String privateKeyStr)
            throws Exception {
        try {
            byte[] buffer = Base64.decode(privateKeyStr);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此算法");
        } catch (InvalidKeySpecException e) {
            throw new Exception("私钥非法");
        } catch (NullPointerException e) {
            throw new Exception("私钥数据为空");
        }
    }

    /**
	 * <P>
	 * 私钥解密
	 * </p>
	 * 
	 * @param encryptedData
	 *            已加密数据
	 * @param privateKey
	 *            私钥(BASE64编码)
	 * @return
	 * @throws Exception
	 */
	public static String decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception {
		byte[] keyBytes = Base64.decode(privateKey);
		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(Cipher.DECRYPT_MODE, privateK);
		int inputLen = encryptedData.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0;
		byte[] cache;
		int i = 0;
		// 对数据分段解密
		while (inputLen - offSet > 0) {
			if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
				cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
			} else {
				cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
			}
			out.write(cache, 0, cache.length);
			i++;
			offSet = i * MAX_DECRYPT_BLOCK;
		}
		byte[] decryptedData = out.toByteArray();
		out.close();
		return new String(decryptedData, "UTF-8");
	}

	/**
	 * <p>
	 * 公钥解密
	 * </p>
	 * 
	 * @param encryptedData
	 *            已加密数据
	 * @param publicKey
	 *            公钥(BASE64编码)
	 * @return
	 * @throws Exception
	 */
	public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception {
		byte[] keyBytes = Base64.decode(publicKey);
		X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		Key publicK = keyFactory.generatePublic(x509KeySpec);
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(Cipher.DECRYPT_MODE, publicK);
		int inputLen = encryptedData.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0;
		byte[] cache;
		int i = 0;
		// 对数据分段解密
		while (inputLen - offSet > 0) {
			if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
				cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
			} else {
				cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
			}
			out.write(cache, 0, cache.length);
			i++;
			offSet = i * MAX_DECRYPT_BLOCK;
		}
		byte[] decryptedData = out.toByteArray();
		out.close();
		return decryptedData;
	}

	/**
	 * <p>
	 * 公钥加密
	 * </p>
	 * 
	 * @param data
	 *            源数据
	 * @param publicKey
	 *            公钥(BASE64编码)
	 * @return
	 * @throws Exception
	 */
	public static String encryptByPublicKey(byte[] data, String publicKey) throws Exception {
		byte[] keyBytes = Base64.decode(publicKey);
		X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		Key publicK = keyFactory.generatePublic(x509KeySpec);
		// 对数据加密
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(Cipher.ENCRYPT_MODE, publicK);
		int inputLen = data.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0;
		byte[] cache;
		int i = 0;
		// 对数据分段加密
		while (inputLen - offSet > 0) {
			if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
				cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
			} else {
				cache = cipher.doFinal(data, offSet, inputLen - offSet);
			}
			out.write(cache, 0, cache.length);
			i++;
			offSet = i * MAX_ENCRYPT_BLOCK;
		}
		byte[] encryptedData = out.toByteArray();
		out.close();
		return Base64.encode(encryptedData);
	}

	/**
	 * <p>
	 * 私钥加密
	 * </p>
	 * 
	 * @param data
	 *            源数�?
	 * @param privateKey
	 *            私钥(BASE64编码)
	 * @return
	 * @throws Exception
	 */
	public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception {
		byte[] keyBytes = Base64.decode(privateKey);
		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(Cipher.ENCRYPT_MODE, privateK);
		int inputLen = data.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0;
		byte[] cache;
		int i = 0;
		// 对数据分段加密
		while (inputLen - offSet > 0) {
			if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
				cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
			} else {
				cache = cipher.doFinal(data, offSet, inputLen - offSet);
			}
			out.write(cache, 0, cache.length);
			i++;
			offSet = i * MAX_ENCRYPT_BLOCK;
		}
		byte[] encryptedData = out.toByteArray();
		out.close();
		return encryptedData;
	}

    /**
   	 * 公钥加密 
   	 * @param publicKeyStr
   	 * @param data 加密字符串
   	 * @return String 密文数据
   	 * @throws Exception
   	 */
   	public static String encryptForPublicKey(String data, String publicKeyStr) throws Exception{
   		 return encryptByPublicKey(data.getBytes(), publicKeyStr);
   	}
   	
   	/**
   	 * 私钥加密
   	 * @param privateKeyStr 私钥
   	 * @param data 加密字符串
   	 * @return String 密文数据
   	 * @throws Exception
   	 */
   	public static String encryptForPrivateKey(String data, String privateKeyStr) throws Exception{
   		byte[] decryptedData = encryptByPrivateKey(data.getBytes(), privateKeyStr);
   		return Base64.encode(decryptedData);
   	}
   	
   	/**
   	 * 私钥解密方法
   	 * @param privateKey 私钥
   	 * @param plainTextData 密文
   	 * @return String 明文
   	 * @throws Exception
   	 */
   	public static String decryptForPrivateKey(String plainTextData, String privateKey) throws Exception{
   		return decryptByPrivateKey(plainTextData.getBytes(), privateKey);
   	}
   	
   	/**
   	 * 公钥解密方法
   	 * @param publicKey
   	 * @param plainTextData 密文
   	 * @return 明文
   	 * @throws Exception
   	 */
   	public static String decryptForPublicKey(String plainTextData, String publicKey) throws Exception{
   		byte[] decryptedData = decryptByPublicKey(Base64.decode(plainTextData), publicKey);
   		return new String(decryptedData);
   	}
   	
    /**
     * 字节数据转十六进制字符串
     *
     * @param data
     *            输入数据
     * @return 十六进制内容
     */
    public static String byteArrayToString(byte[] data) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < data.length; i++) {
            // 取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移
            stringBuilder.append(HEX_CHAR[(data[i] & 0xf0) >>> 4]);
            // 取出字节的低四位 作为索引得到相应的十六进制标识符
            stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]);
            if (i < data.length - 1) {
                stringBuilder.append(' ');
            }
        }
        return stringBuilder.toString();
    }
    
    static String bytesToString(byte[] encrytpByte) {
        String result = "";
        for (Byte bytes : encrytpByte) {
            result += bytes.toString() + " ";
        }
        return result;
    }
}

RSA签名工具类源码:

package com.pay.utils;
import java.lang.reflect.Field;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

public class RSASignature{

    /**
     * 签名算法
     */
    public static final String SIGN_ALGORITHMS = "SHA256WithRSA";

    /**
	 * 加密算法RSA
	 */
	public static final String KEY_ALGORITHM = "RSA";
	
    /**
     * RSA签名
     * @param content 待签名数据
     * @param privateKey 商户私钥
     * @param encode 字符集编码
     * @return 签名值
     */
    public static String sign(String content, String privateKey, String encode)
    {
        try
        {
            PKCS8EncodedKeySpec priPKCS8    = new PKCS8EncodedKeySpec(Base64.decode(privateKey));
            KeyFactory keyf                 = KeyFactory.getInstance(KEY_ALGORITHM);
            PrivateKey priKey               = keyf.generatePrivate(priPKCS8);
            java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
            signature.initSign(priKey);
            signature.update(content.getBytes(encode));
            byte[] signed = signature.sign();
            return Base64.encode(signed);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 根据 content 和 私钥  生成签名
     * @param content  按字典顺序排序的内容
     * @param privateKey  ftp上保存的私钥
     * @return
     */
    public static String sign(String content, String privateKey)
    {
        try
        {
            PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec( Base64.decode(privateKey) );
            KeyFactory keyf = KeyFactory.getInstance(KEY_ALGORITHM);
            PrivateKey priKey = keyf.generatePrivate(priPKCS8);
            java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
            signature.initSign(priKey);
            signature.update(content.getBytes());
            byte[] signed = signature.sign();
            return Base64.encode(signed);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * RSA验签名检查
     * @param content 待签名数据
     * @param sign 签名值
     * @param publicKey 分配给开发商公钥
     * @param encode 字符集编码
     * @return 布尔值
     */
    public static boolean doCheck(String content, String sign, String publicKey,String encode)
    {
        try
        {
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            byte[] encodedKey = Base64.decode(publicKey);
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
            java.security.Signature signature = java.security.Signature
                    .getInstance(SIGN_ALGORITHMS);
            signature.initVerify(pubKey);
            signature.update( content.getBytes(encode) );

            boolean bverify = signature.verify( Base64.decode(sign) );
            return bverify;

        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return false;
    }

    /**
     * RSA验签名检查
     * @param content 待签名数据
     * @param sign 签名值
     * @param publicKey 分配给开发商公钥
     * @return 布尔值
     */
    public static boolean doCheck(String content, String sign, String publicKey)
    {
        try
        {
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            byte[] encodedKey = Base64.decode(publicKey);
            if (encodedKey==null){
                return false;
            }
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));

            // 用私钥对信息生成数字签名
            java.security.Signature signature = java.security.Signature
                    .getInstance(SIGN_ALGORITHMS);

            signature.initVerify(pubKey);
            signature.update( content.getBytes() );
            // 验证方法  返回true则为比对成功
            boolean bverify = signature.verify( Base64.decode(sign) );
            return bverify;

        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return false;
    }


    /**
     * 对象转HashMap
     * @param obj
     * @return
     */
    public static Map<String, Object> objectToMap(Object obj) {
        if (obj == null) {
            return null;
        }

        Map<String, Object> map = new HashMap<String, Object>();
        try {
            Field[] declaredFields = obj.getClass().getDeclaredFields();
            for (Field field : declaredFields) {
                field.setAccessible(true);
                map.put(field.getName(), field.get(obj));
            }
        } catch (Exception e) {

        }

        return map;
    }

    /**
     *  @Description: 将签名的参数内容按参数名的字典顺序进行排序,并拼接为字符串
     */
    public static String getContent(Map<String,Object> map){
        //得到第三方签名 第三方会把sign也放在json里,故转map的时候需要把sign删除
        map.remove("shoppingAddrsInfo");
        map.entrySet().removeIf(entry -> entry.getValue() == null);
        // 将签名的参数内容按参数名的字典顺序进行排序,并拼接为字符串
        StringBuilder sb = new StringBuilder();
        map.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getKey)).forEach(entry ->
                sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&")
        );
        return sb.toString().substring(0, sb.length() - 1);
    }

    /**
     * 签名方法
     * 因为很多处都需要用,特地封装一下,方便调用
     * @param paramStr   按字典顺序拼接过的字符串
     * @param publicKey  从数据库查询出来的第三方公钥
     * @param sign  第三方签名
     * @return
     */
    public static boolean signVerify(String paramStr,String publicKey,String sign){
        try {
            // 使用公钥进行验签
            boolean result = RSASignature.doCheck(paramStr, sign, publicKey);
            if (result){
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }


}

Base64类源码:

package com.pay.utils;

public final class Base64
{

    static private final int     BASELENGTH           = 128;
    static private final int     LOOKUPLENGTH         = 64;
    static private final int     TWENTYFOURBITGROUP   = 24;
    static private final int     EIGHTBIT             = 8;
    static private final int     SIXTEENBIT           = 16;
    static private final int     FOURBYTE             = 4;
    static private final int     SIGN                 = -128;
    static private final char    PAD                  = '=';
    static private final boolean fDebug               = false;
    static final private byte[]  base64Alphabet       = new byte[BASELENGTH];
    static final private char[]  lookUpBase64Alphabet = new char[LOOKUPLENGTH];

    static
    {
        for (int i = 0; i < BASELENGTH; ++i)
        {
            base64Alphabet[i] = -1;
        }
        for (int i = 'Z'; i >= 'A'; i--)
        {
            base64Alphabet[i] = (byte) (i - 'A');
        }
        for (int i = 'z'; i >= 'a'; i--)
        {
            base64Alphabet[i] = (byte) (i - 'a' + 26);
        }

        for (int i = '9'; i >= '0'; i--)
        {
            base64Alphabet[i] = (byte) (i - '0' + 52);
        }

        base64Alphabet['+'] = 62;
        base64Alphabet['/'] = 63;

        for (int i = 0; i <= 25; i++)
        {
            lookUpBase64Alphabet[i] = (char) ('A' + i);
        }

        for (int i = 26, j = 0; i <= 51; i++, j++)
        {
            lookUpBase64Alphabet[i] = (char) ('a' + j);
        }

        for (int i = 52, j = 0; i <= 61; i++, j++)
        {
            lookUpBase64Alphabet[i] = (char) ('0' + j);
        }
        lookUpBase64Alphabet[62] = (char) '+';
        lookUpBase64Alphabet[63] = (char) '/';

    }

    private static boolean isWhiteSpace(char octect)
    {
        return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
    }

    private static boolean isPad(char octect)
    {
        return (octect == PAD);
    }

    private static boolean isData(char octect)
    {
        return (octect < BASELENGTH && base64Alphabet[octect] != -1);
    }

    /**
     * Encodes hex octects into Base64
     * 
     * @param binaryData
     *            Array containing binaryData
     * @return Encoded Base64 array
     */
    public static String encode(byte[] binaryData)
    {

        if (binaryData == null)
        {
            return null;
        }

        int lengthDataBits = binaryData.length * EIGHTBIT;
        if (lengthDataBits == 0)
        {
            return "";
        }

        int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
        int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
        int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1
                : numberTriplets;
        char encodedData[] = null;

        encodedData = new char[numberQuartet * 4];

        byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;

        int encodedIndex = 0;
        int dataIndex = 0;
        if (fDebug)
        {
            System.out.println("number of triplets = " + numberTriplets);
        }

        for (int i = 0; i < numberTriplets; i++)
        {
            b1 = binaryData[dataIndex++];
            b2 = binaryData[dataIndex++];
            b3 = binaryData[dataIndex++];

            if (fDebug)
            {
                System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3);
            }

            l = (byte) (b2 & 0x0f);
            k = (byte) (b1 & 0x03);

            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
                    : (byte) ((b1) >> 2 ^ 0xc0);
            byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
                    : (byte) ((b2) >> 4 ^ 0xf0);
            byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6)
                    : (byte) ((b3) >> 6 ^ 0xfc);

            if (fDebug)
            {
                System.out.println("val2 = " + val2);
                System.out.println("k4   = " + (k << 4));
                System.out.println("vak  = " + (val2 | (k << 4)));
            }

            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
        }

        // form integral number of 6-bit groups
        if (fewerThan24bits == EIGHTBIT)
        {
            b1 = binaryData[dataIndex];
            k = (byte) (b1 & 0x03);
            if (fDebug)
            {
                System.out.println("b1=" + b1);
                System.out.println("b1<<2 = " + (b1 >> 2));
            }
            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
                    : (byte) ((b1) >> 2 ^ 0xc0);
            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
            encodedData[encodedIndex++] = PAD;
            encodedData[encodedIndex++] = PAD;
        }
        else if (fewerThan24bits == SIXTEENBIT)
        {
            b1 = binaryData[dataIndex];
            b2 = binaryData[dataIndex + 1];
            l = (byte) (b2 & 0x0f);
            k = (byte) (b1 & 0x03);

            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
                    : (byte) ((b1) >> 2 ^ 0xc0);
            byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
                    : (byte) ((b2) >> 4 ^ 0xf0);

            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
            encodedData[encodedIndex++] = PAD;
        }

        return new String(encodedData);
    }

    /**
     * Decodes Base64 data into octects
     * 
     * @param encoded
     *            string containing Base64 data
     * @return Array containind decoded data.
     */
    public static byte[] decode(String encoded)
    {

        if (encoded == null)
        {
            return null;
        }

        char[] base64Data = encoded.toCharArray();
        // remove white spaces
        int len = removeWhiteSpace(base64Data);

        if (len % FOURBYTE != 0)
        {
            return null;// should be divisible by four
        }

        int numberQuadruple = (len / FOURBYTE);

        if (numberQuadruple == 0)
        {
            return new byte[0];
        }

        byte decodedData[] = null;
        byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
        char d1 = 0, d2 = 0, d3 = 0, d4 = 0;

        int i = 0;
        int encodedIndex = 0;
        int dataIndex = 0;
        decodedData = new byte[(numberQuadruple) * 3];

        for (; i < numberQuadruple - 1; i++)
        {

            if (!isData((d1 = base64Data[dataIndex++]))
                    || !isData((d2 = base64Data[dataIndex++]))
                    || !isData((d3 = base64Data[dataIndex++]))
                    || !isData((d4 = base64Data[dataIndex++])))
            {
                return null;
            }// if found "no data" just return null

            b1 = base64Alphabet[d1];
            b2 = base64Alphabet[d2];
            b3 = base64Alphabet[d3];
            b4 = base64Alphabet[d4];

            decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
            decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
            decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
        }

        if (!isData((d1 = base64Data[dataIndex++]))
                || !isData((d2 = base64Data[dataIndex++])))
        {
            return null;// if found "no data" just return null
        }

        b1 = base64Alphabet[d1];
        b2 = base64Alphabet[d2];

        d3 = base64Data[dataIndex++];
        d4 = base64Data[dataIndex++];
        if (!isData((d3)) || !isData((d4)))
        {// Check if they are PAD characters
            if (isPad(d3) && isPad(d4))
            {
                if ((b2 & 0xf) != 0)// last 4 bits should be zero
                {
                    return null;
                }
                byte[] tmp = new byte[i * 3 + 1];
                System.arraycopy(decodedData, 0, tmp, 0, i * 3);
                tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
                return tmp;
            }
            else if (!isPad(d3) && isPad(d4))
            {
                b3 = base64Alphabet[d3];
                if ((b3 & 0x3) != 0)// last 2 bits should be zero
                {
                    return null;
                }
                byte[] tmp = new byte[i * 3 + 2];
                System.arraycopy(decodedData, 0, tmp, 0, i * 3);
                tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
                tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
                return tmp;
            }
            else
            {
                return null;
            }
        }
        else
        { // No PAD e.g 3cQl
            b3 = base64Alphabet[d3];
            b4 = base64Alphabet[d4];
            decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
            decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
            decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);

        }

        return decodedData;
    }

    /**
     * remove WhiteSpace from MIME containing encoded Base64 data.
     * 
     * @param data
     *            the byte array of base64 data (with WS)
     * @return the new length
     */
    private static int removeWhiteSpace(char[] data)
    {
        if (data == null)
        {
            return 0;
        }

        // count characters that's not whitespace
        int newSize = 0;
        int len = data.length;
        for (int i = 0; i < len; i++)
        {
            if (!isWhiteSpace(data[i]))
            {
                data[newSize++] = data[i];
            }
        }
        return newSize;
    }
}

JAVA调用示例:

public class Test {
static String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnPo+UWWzx0Ny83acrRJCZy8sE5sYkuwvNYMTMd9ZHZQb8QRdZq6Ib+04+FocSHPt6OoMD+QB6ekbPyKY9NUGdtDVJ6AySGYlYnMT963lthsJrcJIL+QFyAlN2+BSh40ReTPISc2RpC7ahScsRmoj+wQE+HUSXvt7rqAdQM/ijthudPOI+DfGCtZjX7oS5pN3U2Ih7Qsx/51NpGbYKxA7ve+KCYDfmGbWDtwAChAFQnVZDyNOuusjyXbmHu2q+ey5y7Ztn2MyIQ2d/Ki3wDqLvZORgPpm6xm73+qh1A/9sjbsSc0cxPju21wP2tSKzNdegj6soXYUsWkrUM7Bcoi91wIDAQAB";
    static String privateKey = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCQuWPZmqnRPKbxtLkowlF+foMHM0NPr5D2dqWLAwmarUgdUd1L10WLIaJOjL36S1VOF4woDc8sd26ntO2LfP+TpAAIXpmsWRq9C4fY7Z24mR2EAu6FlDlHXvteYKh6XUYw36xn9fg9yh7yKjC0M8F/LTsmY1fKc4k0w0ARrWdY3IqpbFv8E/7WkUp6oBaza5+GiQ614fvmxzIAJaXg6D6USvmbPLMgxYFePOXyxDnA3YmC4SC4Zru3V0QVHewmy+VOHc+L3MJcMPPzMifZ5R2tXUM0mQPb3k9GuDY2etCI00jwhaw1IGIdgGsv8yJcwX9IBZYTsPIX5FUh9eVWKE/LAgMBAAECggEAdwfjtf/dF/i4niez+nAIMu++uNdSz2Fo6y0ebr0q0wseOu8wAcamrg4VvmFHh2saWEZJwk/JS5tXaZwHnChM1JOYa0nTPstykHXBX4vfowpcGk2G/Fqy2Z6nRDJfn3TD3EK7PC4z5C4vUaGduTiwNvdupN4kQKDSApFsSp3CWHSY0rE+kgNXfBrY6u16xc0QNRzoj+8/R1mno8OZCUEnFocRV4975mtAVrt3xsA+ejQqjhJnxUAKXVDMmOaVTyHwQyRrRDk7UzCpYax5YgVUbquRweOJl/HK9+zZzNcAy1cQUMjrAr9gUwCXZaKkdL0fujXXxPmfDLZF+QzoZrKVQQKBgQDqbps2vX/EGii8HjOFf4uvhMbSct37kWOiJMGqLIinxvrlxeWWShXhNp5eUPHg9i0bEZYSTLxRd2qM3xFsE6Wy/Zt/1x+9M7EDYafvJsSVsvmcJFBlfG2/VBT56iT4xDgHJOoDa8OeYQMbkJIEE+Xl+dXmfcfnijZkL66/JSebewKBgQCeCfb5D1ehRvvRw9gh0vXI18J0lc6wUEFS6A5UV7P27jmh80HgRnYlLzWryIAXcqvGACir9V6ZHCWfdzuhxxFqjSBqZPTMfKFHCxOk2YvHcGRQwsSZMGBfRKjyETFGRkPBphnq0sE3zKIKafB7Z0swBlcKB0yneIAilwUAsT2D8QKBgBPJ2lg4jrxi6OVYN0khhwz9zDqfb5V4pExfhelzcOWYqj0TA1o4Trh//8Y+VuyCWzRZu603xP2rctcJTVMuJWKCfcnAwvEZl+uNJrvNLfLk9KT1e8PVSP5JfqvJ0+0bww73UrmPMyf/UF/XSDwH4fQTrraSD3m/9O9oBvwjisBZAoGAQ5GXGl1I5hdnSwQkwDFmDHzTEu2J9TAa/cthdQYaV5T65xcOL0lw8e0BUXTj7yKD9p/Sw9Kgo225WDiuMjjeZWP5XAPV9ifC/JDr0SuB679N5ImhbK2WRqUgZn6bRqR8C6tsoU2Cdszy6ujofJppNxs+03bTeza18hQHe4hL+MECgYB9fEHhluk+fuKDfxVNTd98PBjatv4ZhMD3j1d+u0PWGZ2ajOBZ7m0ewso2n5otaTP2pxclmOq1/NX2KXUS2XVgX/bVZy1iUOmT8lUX3CHLUugQqdcv2oBL9n8n3rFhebps98MmUtVhx7qORrNU0aG6RlvFn3QBmF6mHXOuZ1nq6w==";
    public static void main(String[] args) throws Exception {
        Map<String,Object> params = new HashMap<>();
        params.put("merchantNo", merchantNo); // 商户号
		params.put("merchantOrderNo", merchantOrderNo); // 商户订单号
		params.put("currency", "CNY"); // 币种
		params.put("amount", "0.15");// 交易金额(单位:元)
        //签名数据按ASCII字码从小到大排序,所有键值对以“&”字符连接起来
		String data = 
        RSASignature.getContent(JSON.parseObject(JSON.toJSONString(params)));
		System.out.println(data);
        // RSA签名
		String sign = RSASignature.sign(data, privateKey, "UTF-8");
        System.out.println(sign);
        String encryptData = RSAEncrypt.encryptForPrivateKey(str, privateKey);
        System.out.println("加密后内容:" + encryptData);
        //公钥解密
        //RSA解密
		String decryptData = RSAEncrypt.decryptForPublicKey(encryptData, publicKey);
		System.out.println("解密后内容:" + decryptData);
    }
}

PHP加解密工具类源码:

class RSA
{
    public $privateKey = './rsa_private_key.pem';           //私钥地址
    public $publicKey = './rsa_public_key.pem';             //公钥地址

    public $pri_key = '';
    public $pub_key = '';

    /**
     * RSA constructor.
     * @param null $publicKeyPath
     * @param null $privateKeyPath
     * @param null $publicKey
     * @param null $privateKey
     * @throws FileNotFoundException
     */
    public function __construct($publicKeyPath=null, $privateKeyPath=null, $publicKey=null, $privateKey=null) {

        if ($this->checkKeyFile($publicKeyPath)) {
            $this->pub_key = openssl_pkey_get_public(file_get_contents($publicKeyPath));
        }

        if ($this->checkKeyFile($privateKeyPath)) {
            $this->pri_key = openssl_pkey_get_private(file_get_contents($privateKeyPath));
        }

        if (!is_null($publicKey)) {
            $this->pub_key = openssl_pkey_get_public($this->formatterPublicKey($publicKey));
        }

        if (!is_null($privateKey)) {
            $this->pri_key = openssl_pkey_get_private($this->formatterPrivateKey($privateKey));
        }

    }

    /**
     * 校验文件是否存在
     * @param $keyPath string 文件路径
     * @return bool
     * @throws FileNotFoundException
     */
    public function checkKeyFile($keyPath)
    {
        if (!is_null($keyPath)) {
            if(!file_exists($keyPath)) {
                throw new FileNotFoundException($keyPath);
            }

            return true;
        }

        return false;
    }

    /**
     * 格式化公钥
     * @param $publicKey string 公钥
     * @return string
     */
    public function formatterPublicKey($publicKey)
    {
        if (str_contains('-----BEGIN PUBLIC KEY-----', $publicKey)) return $publicKey;

        $str = chunk_split($publicKey, 64, PHP_EOL);//在每一个64字符后加一个\n
        $publicKey = "-----BEGIN PUBLIC KEY-----".PHP_EOL.$str."-----END PUBLIC KEY-----";

        return $publicKey;
    }

    /**
     * 格式化私钥
     * @param $privateKey string 公钥
     * @return string
     */
    public function formatterPrivateKey($privateKey)
    {
        if (str_contains('-----BEGIN RSA PRIVATE KEY-----', $privateKey)) return $privateKey;

        $str = chunk_split($privateKey, 64, PHP_EOL);//在每一个64字符后加一个\n
        $privateKey = "-----BEGIN RSA PRIVATE KEY-----".PHP_EOL.$str."-----END RSA PRIVATE KEY-----";

        return $privateKey;
    }

    /**
     *  私钥加密(分段加密)
     *  emptyStr    需要加密字符串
     */
    public function encrypt($str) {
        $crypted = array();
//        $data = json_encode($str);
        $data = $str;
        $dataArray = str_split($data, 117);
        foreach($dataArray as $subData){
            $subCrypted = null;
            openssl_private_encrypt($subData, $subCrypted, $this->pri_key);
            $crypted[] = $subCrypted;
        }
        $crypted = implode('',$crypted);
        return base64_encode($crypted);
    }

    /**
     *  公钥解密(分段解密)
     *  @encrypstr  加密字符串
     */
    public function decrypt($encryptstr) {
        // echo $encryptstr;exit;
        $encryptstr = base64_decode($encryptstr);
        $decrypted = array();
        $dataArray = str_split($encryptstr, 128);

        foreach($dataArray as $subData){
            $subDecrypted = null;
            openssl_public_decrypt($subData, $subDecrypted, $this->pub_key);
            $decrypted[] = $subDecrypted;
        }
        $decrypted = implode('',$decrypted);
        // openssl_public_decrypt(base64_decode($encryptstr),$decryptstr,$this->pub_key);
        return $decrypted;
    }

}

PHP RSA签名验签:

/**
 * 生成签名
 * @param    string     $signString 待签名字符串
 * @param    [type]     $priKey     私钥
 * @return   string     base64结果值
 */
function getSign($signString,$priKey){
    $privKeyId = openssl_pkey_get_private($priKey);
    $signature = '';
    openssl_sign($signString, $signature, $privKeyId);
    openssl_free_key($privKeyId);
    return base64_encode($signature);
}

/**
 * 校验签名
 * @param    string     $pubKey 公钥
 * @param    string     $sign   签名
 * @param    string     $toSign 待签名字符串
 * @param    string     $signature_alg 签名方式 比如 sha1WithRSAEncryption 或者sha512
 * @return   bool
 */
function checkSign($pubKey,$sign,$toSign,$signature_alg=OPENSSL_ALGO_SHA1){
    $publicKeyId = openssl_pkey_get_public($pubKey);
    $result = openssl_verify($toSign, base64_decode($sign), $publicKeyId,$signature_alg);
    openssl_free_key($publicKeyId);
    return $result === 1 ? true : false;
}

 PHP调用示例:

$privateKey = 'MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANSwa2pVnn4QbVxaNJg/1sudmGZL3eFOEOMk/ILagTnXNNtdV6pOslBOp5RBd93TdMZg/4KaAiluyOfg+WbExS7hg/cPXEiVfhF+4O+39uGmoYjlxAAs0dr+ZMAYjiZ+XKh8fuctD7mRYEkr7pBvqQbcRIDyJZpKIbyotcFudXVfAgMBAAECgYAJwJEcThK3Ww94pZY1yO+TZIWBY0coNoklsSN26If2W/zLdis33uXkMscSUDIr1K9NDVOJ7H/e4HqLz1AAO1ODLmFxflnyeEIKan6M/4NA8/7IF+Wu0FDQjNm2iKW68axKiW01j6yqq2JagG9kff5xbkzxriuWpmiDF0TWxzm6aQJBAPB2asI5dVr7bBC+sK7FjPQGNIu6X2NHeacHzUswSo7b4NgTucAkubjLTgpd3s8/FQoVBm4Ay7Juzc0DBjVUv2UCQQDibpd6lzY0E9cNGol83HDKJGUTmnpduE9PKYua019vx/tgoMOK4squqnV74IY7NkhP5V0djO0XYxD0EaFnmV9zAkAkp4hijuuqsMSqUMcR/R8dW4zK99/ufEi5A2Fx4qya1j2R8n/QIEkHOEZvIhwCr3T/knDmd8yVKHrKk3lwy7hZAkEAlB7SGpCGFaUQ3XKJk9NEOQd700oPV/V0dA1yVHKHEMFaMIiZweW/vmild8aVKHDG9vTMZ8NDaTQV6AMMeY+7/wJBANeLmqSHflwpMA9BdyTxmuRv8W2lLKsjGDBDnVaKf4hBltMll/e3/OPkg/BPew3lxrHkp3E1I6RyMTzmQxwXd78=';

$rsa = new RSA(null, null, null, $privateKey);

// 读取pem文件
// $rsa = new RSA(null, public_path('rsa_private_key.pem'));

$string = '{"phone":"15256232333","name":"张三","inAcctNo":"8239472342342342","idNo":"342422165897654326","inAcctBankName":"平安银行"}';

$encryptstr = $rsa->encrypt($string);

echo $encryptstr;


//获取签名
$sign = getSign($signString,$priKey);

//验证签名
$res = checkSign($pubKey,$sign,$signString);
var_dump($res);//结果为 true

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xx3020

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值