生产证书操作说明

  • 商户下载证书生成工具,使用工具生成商户的私钥(xxx.pfx)和公钥(xxx.cer)
  • 商户公钥(xxx.cer)提供给GEP技术支持,技术支持配置后会提供GEP公钥和证书编号

加密过程

  1. 按照接口文档中的加密数据dataContent列表参数组装JSON串明文

  2. 然后对明文进行 BASE64编码

  3. 再使用 商户私钥(xxx.pfx) 进行 RSA加密 得到密文

加密方法可参考 加解密示例 或接口文档 Demo

解密过程

  1. 需对接口返回的结果信息result字段使用GEP公钥 进行 RSA解密

  2. 然后进行BASE64解码后得到明文,

解密方法可参考 加解密示例 或对应接口文档 Demo

注:部分接口返回result不需解密,具体参考对应接口说明

加解密过程图解

加解密示例

若需使用PEM格式证书可使用在线转换工具 RSA证书转PEM

JAVA示例

示例说明:RsaReadUtil.java - 读取证书类,RsaCodingUtil.java - RSA加解密类

  • 私钥加密:RsaCodingUtil.encryptByPriPfxFile
  • 公钥解密:RsaCodingUtil.decryptByPublicKey

RsaReadUtil.java

package com.baofoo.rsa;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.Enumeration;

import sun.misc.BASE64Decoder;

/**
 * <b>公私钥读取工具</b><br>
 *
 */
public final class RsaReadUtil {

    /**
     * 根据Cer文件读取公钥
     *
     * @param pubCerPath
     * @return
     */
    public static PublicKey getPublicKeyFromFile(String pubCerPath) {
        FileInputStream pubKeyStream = null;
        try {
            pubKeyStream = new FileInputStream(pubCerPath);
            byte[] reads = new byte[pubKeyStream.available()];
            pubKeyStream.read(reads);
            return getPublicKeyByText(new String(reads));
        } catch (FileNotFoundException e) {
            // //log.error("公钥文件不存在:", e);
        } catch (IOException e) {
            // log.error("公钥文件读取失败:", e);
        } finally {
            if (pubKeyStream != null) {
                try {
                    pubKeyStream.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * 根据公钥Cer文本串读取公钥
     *
     * @param pubKeyText
     * @return
     */
    public static PublicKey getPublicKeyByText(String pubKeyText) {
        try {
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
            BufferedReader br = new BufferedReader(new StringReader(pubKeyText));
            String line = null;
            StringBuilder keyBuffer = new StringBuilder();
            while ((line = br.readLine()) != null) {
                if (!line.startsWith("-")) {
                    keyBuffer.append(line);
                }
            }
            Certificate certificate = certificateFactory.generateCertificate(new ByteArrayInputStream(new BASE64Decoder().decodeBuffer(keyBuffer.toString())));
            return certificate.getPublicKey();
        } catch (Exception e) {
            // log.error("解析公钥内容失败:", e);
        }
        return null;
    }

    /**
     * 根据私钥路径读取私钥
     *
     * @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) {
            e.printStackTrace();
        } finally {
            if (priKeyStream != null) {
                try {
                    priKeyStream.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * 根据PFX私钥字节流读取私钥
     *
     * @param pfxBytes
     * @param priKeyPass
     * @return
     */
    public static PrivateKey getPrivateKeyByStream(byte[] pfxBytes, String priKeyPass) {
        try {
            KeyStore ks = KeyStore.getInstance("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;
    }
}

RsaCodingUtil.java

package com.baofoo.rsa;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import com.baofoo.util.FormatUtil;

/**
 * <b>Rsa加解密工具</b><br>
 * <br>
 * 公钥采用X509,Cer格式的<br>
 * 私钥采用PKCS12加密方式的PFX私钥文件<br>
 */
public final class RsaCodingUtil {

    // ======================================================================================
    // 公钥加密私钥解密段
    // ======================================================================================

    /**
     * 指定Cer公钥路径加密
     * 
     * @param src
     * @param pubCerPath
     * @return hex串
     */
    public static String encryptByPubCerFile(String src, String pubCerPath) {

        PublicKey publicKey = RsaReadUtil.getPublicKeyFromFile(pubCerPath);
        if (publicKey == null) {
            return null;
        }
        return encryptByPublicKey(src, publicKey);
    }

    /**
     * 用公钥内容加密
     * 
     * @param src
     * @param pubKeyText
     * @return hex串
     */
    public static String encryptByPubCerText(String src, String pubKeyText) {
        PublicKey publicKey = RsaReadUtil.getPublicKeyByText(pubKeyText);
        if (publicKey == null) {
            return null;
        }
        return encryptByPublicKey(src, publicKey);
    }

    /**
     * 公钥加密返回
     * 
     * @param src
     * @param publicKey
     * @param encryptMode
     * @return hex串
     */
    public static String encryptByPublicKey(String src, PublicKey publicKey) {
        byte[] destBytes = rsaByPublicKey(src.getBytes(), publicKey, Cipher.ENCRYPT_MODE);

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

        return FormatUtil.byte2Hex(destBytes);

    }

    /**
     * 根据私钥文件解密
     * 
     * @param src
     * @param pfxPath
     * @param priKeyPass
     * @return
     */
    public static String decryptByPriPfxFile(String src, String pfxPath, String priKeyPass) {
        if (FormatUtil.isEmpty(src) || FormatUtil.isEmpty(pfxPath)) {
            return null;
        }
        PrivateKey privateKey = RsaReadUtil.getPrivateKeyFromFile(pfxPath, priKeyPass);
        if (privateKey == null) {
            return null;
        }
        return decryptByPrivateKey(src, privateKey);
    }

    /**
     * 根据私钥文件流解密
     * 
     * @param src
     * @param pfxPath
     * @param priKeyPass
     * @return
     */
    public static String decryptByPriPfxStream(String src, byte[] pfxBytes, String priKeyPass) {
        if (FormatUtil.isEmpty(src)) {
            return null;
        }
        PrivateKey privateKey = RsaReadUtil.getPrivateKeyByStream(pfxBytes, priKeyPass);
        if (privateKey == null) {
            return null;
        }
        return decryptByPrivateKey(src, privateKey);
    }

    /**
     * 私钥解密
     * 
     * @param src
     * @param privateKey
     * @return
     */
    public static String decryptByPrivateKey(String src, PrivateKey privateKey) {
        if (FormatUtil.isEmpty(src)) {
            return null;
        }
        try {
            byte[] destBytes = rsaByPrivateKey(FormatUtil.hex2Bytes(src), privateKey, Cipher.DECRYPT_MODE);
            if (destBytes == null) {
                return null;
            }
            return new String(destBytes, "UTF-8");
        } catch (UnsupportedEncodingException e) {
//            //log.error("解密内容不是正确的UTF8格式:", e);
        } catch (Exception e) {
//            //log.error("解密内容异常", e);
        }

        return null;
    }

    // ======================================================================================
    // 私钥加密公钥解密
    // ======================================================================================

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

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

    /**
     * 根据私钥文件流加密
     * 
     * @param src
     * @param pfxPath
     * @param priKeyPass
     * @return
     */
    public static String encryptByPriPfxStream(String src, byte[] pfxBytes, String priKeyPass) {
        PrivateKey privateKey = RsaReadUtil.getPrivateKeyByStream(pfxBytes, 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);

    }

    /**
     * 指定Cer公钥路径解密
     * 
     * @param src
     * @param pubCerPath
     * @return
     */
    public static String decryptByPubCerFile(String src, String pubCerPath) {
        PublicKey publicKey = RsaReadUtil.getPublicKeyFromFile(pubCerPath);
        if (publicKey == null) {
            System.out.println("证书读取失败");
            return null;
        }
        return decryptByPublicKey(src, publicKey);
    }

    /**
     * 根据公钥文本解密
     * 
     * @param src
     * @param pubKeyText
     * @return
     */
    public static String decryptByPubCerText(String src, String pubKeyText) {
        PublicKey publicKey = RsaReadUtil.getPublicKeyByText(pubKeyText);
        if (publicKey == null) {
            return null;
        }
        return decryptByPublicKey(src, publicKey);
    }

    /**
     * 根据公钥解密
     * 
     * @param src
     * @param publicKey
     * @return
     */
    public static String decryptByPublicKey(String src, PublicKey publicKey) {

        try {
            byte[] destBytes = rsaByPublicKey(FormatUtil.hex2Bytes(src), publicKey, Cipher.DECRYPT_MODE);
            if (destBytes == null) {
                return null;
            }
            return new String(destBytes, "UTF-8");
        } catch (UnsupportedEncodingException e) {
//            //log.error("解密内容不是正确的UTF8格式:", e);
            e.printStackTrace();
        }
        return null;
    }

    // ======================================================================================
    // 公私钥算法
    // ======================================================================================
    /**
     * 公钥算法
     * 
     * @param srcData   源字节
     * @param publicKey 公钥
     * @param mode      加密 OR 解密
     * @return
     */
    public static byte[] rsaByPublicKey(byte[] srcData, PublicKey publicKey, int mode) {
        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(mode, publicKey);
            // 分段加密
            int blockSize = (mode == Cipher.ENCRYPT_MODE) ? cipher.getOutputSize(srcData.length) - 11
                    : cipher.getOutputSize(srcData.length);
            byte[] encryptedData = null;
            for (int i = 0; i < srcData.length; i += blockSize) {
                // 注意要使用2的倍数,否则会出现加密后的内容再解密时为乱码
                byte[] doFinal = cipher.doFinal(subarray(srcData, i, i + blockSize));
                encryptedData = addAll(encryptedData, doFinal);
            }
            System.out.println("-------解密成功--------");
            return encryptedData;

        } catch (NoSuchAlgorithmException e) {
            System.out.println("公钥算法-不存在的解密算法:" + e);
//            //log.error("公钥算法-不存在的解密算法:", e);
        } catch (NoSuchPaddingException e) {
            System.out.println("公钥算法-无效的补位算法:" + e);
//            //log.error("公钥算法-无效的补位算法:", e);
        } catch (IllegalBlockSizeException e) {
            System.out.println("公钥算法-无效的块大小:" + e);
//            //log.error("公钥算法-无效的块大小:", e);
        } catch (BadPaddingException e) {
            System.out.println("公钥算法-补位算法异常:" + e);
//            //log.error("公钥算法-补位算法异常:", e);
        } catch (InvalidKeyException e) {
            System.out.println("公钥算法-无效的私钥:" + 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 {
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            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;
    }

    public static byte[] clone(byte[] array) {
        if (array == null) {
            return null;
        }
        return (byte[]) array.clone();
    }
}

PHP示例

  • 私钥加密:encryptByPFXFile
  • 公钥解密:decryptByCERFile

RSAUtil.php

<?php
/**
 * Company: www.baofu.com
 * @date 2023年2月20日
 * 新增1024与2048兼容加解密
 */
 class RSAUtil{    
    /**
     * 读取私钥
     * @param type $PfxPath
     * @param type $PrivateKPASS
     * @return array
     * @throws Exception
     */
    private static function  getPriveKey($PfxPath,$PrivateKPASS){
        try { 
            if(!file_exists($PfxPath)) {
                throw new Exception("私钥文件不存在!路径:".$PfxPath);
            }
            $PKCS12 = file_get_contents($PfxPath);
            $PrivateKey = array();
            if(openssl_pkcs12_read($PKCS12, $PrivateKey, $PrivateKPASS)){
                return $PrivateKey["pkey"];
             }else{
                throw new Exception("私钥证书读取出错!原因[证书或密码不匹配],请检查本地证书相关信息。");
             }
         } catch (Exception $ex) {
            $ex->getTrace();
        }
    }

    /**
     * 读取公钥
     * @param type $PublicPath
     * @return type
     * @throws Exception
     */
    private static function  getPublicKey($PublicPath){
        try { 
            if(!file_exists($PublicPath)) {
                throw new Exception("公钥文件不存在!路径:".$PublicPath);
            }      
            $KeyFile = file_get_contents($PublicPath);
            $PublicKey = openssl_get_publickey($KeyFile);             
            if(empty($PublicKey)){
                throw new Exception("公钥不可用!路径:".$PublicPath);
            }            
            return $PublicKey;
         } catch (Exception $ex) {
            $ex->getTraceAsString();
        }
    }

    /**
     * 公钥加密
     * @param type $Data    加密数据
     * @param type $PfxPath     私钥路径
     * @param type $PrivateKPASS  私钥密码
     * @return type
     * @throws Exception
     */
    public static function encryptByCERFile($Data,$PublicPath){
        try {
            if (!function_exists( 'bin2hex')) {
                throw new Exception("bin2hex PHP5.4及以上版本支持此函数,也可自行实现!");
            }
            $KeyObj = self::getPublicKey($PublicPath);
            $BASE64EN_DATA = base64_encode($Data);
            $EncryptStr = "";
            $blockSize = self::get_Key_Size($KeyObj,false);
            if($blockSize<=0){
                throw new Exception("BlockSize is 0");
            }else{
                $blockSize = $blockSize/8-11;
            }
            $totalLen = strlen($BASE64EN_DATA);
            $EncryptSubStarLen = 0;
            $EncryptTempData="";
            while ($EncryptSubStarLen < $totalLen){
                openssl_public_encrypt(substr($BASE64EN_DATA, $EncryptSubStarLen, $blockSize), $EncryptTempData, $KeyObj);
                $EncryptStr .= bin2hex($EncryptTempData);
                $EncryptSubStarLen += $blockSize;
            }
            return $EncryptStr;
        } catch (Exception $exc) {
            echo $exc->getTraceAsString();
        }
    }

    /**
     * 私钥加密
     * @param type $Data
     * @param type $PfxPath
     * @param type $PrivateKPASS
     * @return type
     * @throws Exception
     */
    public static function encryptByPFXFile($Data,$PfxPath,$PrivateKPASS){
        try {
            if (!function_exists( 'bin2hex')) {
                throw new Exception("bin2hex PHP5.4及以上版本支持此函数,也可自行实现!");
            }
            $KeyObj = self::getPriveKey($PfxPath,$PrivateKPASS);
            $BASE64EN_DATA = base64_encode($Data);
            $EncryptStr = "";
            $blockSize = self::get_Key_Size($KeyObj);
            if($blockSize<=0){
                throw new Exception("BlockSize is 0");
            }else{
                $blockSize = $blockSize/8-11;//分段
            }
            $totalLen = strlen($BASE64EN_DATA);
            $EncryptSubStarLen = 0;
            $EncryptTempData="";
            while ($EncryptSubStarLen < $totalLen){
                openssl_private_encrypt(substr($BASE64EN_DATA, $EncryptSubStarLen, $blockSize), $EncryptTempData, $KeyObj);
                $EncryptStr .= bin2hex($EncryptTempData);
                $EncryptSubStarLen += $blockSize;
            }
            return $EncryptStr;
        } catch (Exception $exc) {
            echo $exc->getTraceAsString();
        }
    }

    /**
     * 私钥解密
     * @param type $Data    解密数据
     * @param type $PublicPath  解密公钥路径    
     * @return type
     * @throws Exception
     */
    public static function decryptByPFXFile($Data,$PfxPath,$PrivateKPASS){
        try {            
            if (!function_exists( 'hex2bin')) {
                throw new Exception("hex2bin PHP5.4及以上版本支持此函数,也可自行实现!");
            }
            $KeyObj = self::getPriveKey($PfxPath,$PrivateKPASS);            
            $blockSize = self::get_Key_Size($KeyObj);            
            if($blockSize<=0){
                throw new Exception("BlockSize is 0");
            }else{
                $blockSize = $blockSize/4;
            }
            $DecryptRsult="";
            $totalLen = strlen($Data);
            $EncryptSubStarLen = 0;
            $DecryptTempData="";
            while ($EncryptSubStarLen < $totalLen) {
                openssl_private_decrypt(hex2bin(substr($Data, $EncryptSubStarLen, $blockSize)), $DecryptTempData, $KeyObj);
                $DecryptRsult .= $DecryptTempData;
                $EncryptSubStarLen += $blockSize;
            }
            return base64_decode($DecryptRsult);
        } catch (Exception $exc) {
            echo $exc->getTraceAsString();
        }
    }

    /**
     * 公钥解密
     * @param type $Data
     * @param type $PublicPath
     * @return type
     * @throws Exception
     */
    public static function decryptByCERFile($Data,$PublicPath) {
        try {            
            if (!function_exists( 'hex2bin')) {
                throw new Exception("hex2bin PHP5.4及以上版本支持此函数,也可自行实现!");
            }
            $KeyObj = self::getPublicKey($PublicPath);
            $DecryptRsult="";
            $blockSize = self::get_Key_Size($KeyObj,false);
            if($blockSize<=0){
                throw new Exception("BlockSize is 0");
            }else{
                $blockSize = $blockSize/4;
            }
            $totalLen = strlen($Data);
            $EncryptSubStarLen = 0;
            $DecryptTempData="";
            while ($EncryptSubStarLen < $totalLen) {
                openssl_public_decrypt(hex2bin(substr($Data, $EncryptSubStarLen, $blockSize)), $DecryptTempData, $KeyObj);
                $DecryptRsult .= $DecryptTempData;
                $EncryptSubStarLen += $blockSize;
            }
            return base64_decode($DecryptRsult);
        } catch (Exception $exc) {
            echo $exc->getTraceAsString();
        }        
    }

    /**
     * 获取证书长度
     * @param type $Key_String
     * @param type $Key_Type
     * @return int
     * @throws Exception
     */
    private static function get_Key_Size($Key_String,$Key_Type=true){
        $Key_Temp=array();
        try{
            if($Key_Type){//私钥
                $Key_Temp = openssl_pkey_get_details(openssl_pkey_get_private($Key_String));
            }else if(openssl_pkey_get_public($Key_String)){//公钥
                $Key_Temp = openssl_pkey_get_details(openssl_pkey_get_public($Key_String));
            }else{
                throw new Exception("Is not a key");
            }
            IF(array_key_exists("bits",$Key_Temp)){
                return $Key_Temp["bits"];
            }else{
                return 0;
            }
        } catch (Exception $ex){
            $ex->getTrace();
            return 0;
        }
    }
}

.NET示例

示例需用到BouncyCastle包,可以使用NuGet引用;RsaReadUtil.cs-证书读取类,RSAUtil.cs-RSA加解密类

  • 私钥加密:EncryptRSAByPfx
  • 公钥解密:DecryptRSAByCer

RsaReadUtil.cs

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Pkix;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.Utilities.Encoders;

namespace SecurityUtil
{
    /**
     * <b>Rsa加解密工具</b><br>
     * <br>
     * 公钥采用X509,Cer格式<br>
     * 私钥采用PKCS12加密方式的PFX私钥文件<br>
     * 加密算法为1024位的RSA\工作模式ECB\填充算法为PKCS1Padding<br>
     * 
     * @author 宝付_大圣
     * @version 1.0
     * 宝付网络科技(上海)有限公司
     * 引用加密动态库 BouncyCastle.Crypto.dll(必要)
     */
    class RsaReadUtil
    {
        /*
         * 
        ==================读取私钥==========================
         * path   证书路径
         * 
         * pwd  证书密码
         * 
         */
         public static AsymmetricKeyParameter getPrivateKeyFromFile( string path,string pwd)
        {
            FileStream fs = File.OpenRead(path);      //path路径下证书
            char[] passwd = pwd.ToCharArray();

            Pkcs12Store store = new Pkcs12StoreBuilder().Build();  
            store.Load(fs, passwd); //加载证书  
            string alias = null;  
            foreach (string str in store.Aliases)  
            {  
                if (store.IsKeyEntry(str))  
                    alias = str;  
            }
            AsymmetricKeyEntry keyEntry = store.GetKey(alias);
            return keyEntry.Key;

        }

         /*
          ==================读取公钥==========================
          * 
          * path   证书路径
          * 
          */

         public static AsymmetricKeyParameter getPublicKeyFromFile(string path) 
         {
             StreamReader sr = new StreamReader(path);
             String line = null;
             StringBuilder keyBuffer = new StringBuilder();
             while ((line = sr.ReadLine()) != null)
             {
                 if (!line.StartsWith("-"))
                 {
                     keyBuffer.Append(line);
                 }
             }
             if (String.IsNullOrEmpty(keyBuffer.ToString().Trim()))
             {
                 throw new Exception("公钥读取异常[keyBuffer=null or Empty]");
             }
             X509Certificate CerObj = new X509CertificateParser().ReadCertificate(Base64.Decode(keyBuffer.ToString()));
             return CerObj.GetPublicKey();
         }

    }
}

RSAUtil.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Org.BouncyCastle.Utilities.Encoders;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto;
using SecurityUtil;

namespace SecurityUtil
{
    /**
     * <b>Rsa加解密工具</b><br>
     * <br>
     * 公钥采用X509,Cer格式<br>
     * 私钥采用PKCS12加密方式的PFX私钥文件<br>
     * 加密算法为1024位的RSA\工作模式ECB\填充算法为PKCS1Padding<br>
     * 
     * @author 宝付_大圣
     * @version 1.0
     * 宝付网络科技(上海)有限公司
     * 开源加密方法BouncYCastle
     */
    public class RSAUtil
    {
        public static String EncryptRSAByCer(string src, string path)
        {
            try
            {
                AsymmetricKeyParameter PrivteKey = RsaReadUtil.getPublicKeyFromFile(path);//读取公钥
                byte[] string64 = Base64.Encode(System.Text.Encoding.UTF8.GetBytes(src));//Base64编码  字符编码UF8
                String HEX = Hex.ToHexString(RSAEDCore(string64, PrivteKey, true));//加密并转成十六进制
                return HEX;
            }
            catch (Exception ex) 
            {
                return "{[本地加密异常][EncryptRSAByPfx][" + ex.Message + "]}";
            }
        }

        public static string EncryptRSAByPfx(string src, string path, string passwd)
        {

            try
            {
                AsymmetricKeyParameter PrivteKey = RsaReadUtil.getPrivateKeyFromFile(path, passwd);//读取私钥
                byte[] string64 = Base64.Encode(System.Text.Encoding.UTF8.GetBytes(src));//Base64编码  字符编码UF8
                // Log.LogWrite("【Base64编码】" + System.Text.Encoding.UTF8.GetString(string64));
                string HEX = Hex.ToHexString(RSAEDCore(string64, PrivteKey, true));//加密并转成十六进制
                return HEX;
            }
            catch (Exception ex)
            {
                return "{[本地加密异常][EncryptRSAByPfx][" + ex.Message + "]}";
            }
        }


        public static String DecryptRSAByPfx(string src, string path, string passwd) 
        {
            try
            {
                AsymmetricKeyParameter PublicKey = RsaReadUtil.getPrivateKeyFromFile(path, passwd);//读取私钥
                byte[] HEXbyte = Hex.Decode(src);
                byte[] DecryString = RSAEDCore(HEXbyte, PublicKey, false);
                return System.Text.Encoding.UTF8.GetString(Base64.Decode(DecryString));
            }catch(Exception ex)
            {
                return "{[本地解密异常][DecryptRSAByCer][" + ex.Message + "]}";
            }
        }

        public static string DecryptRSAByCer(string src, string path)
        {
            try
            {
                AsymmetricKeyParameter PublicKey = RsaReadUtil.getPublicKeyFromFile(path);//读取公钥
                byte[] HEXbyte = Hex.Decode(src);
                byte[] DecryString = RSAEDCore(HEXbyte, PublicKey, false);
                return System.Text.Encoding.UTF8.GetString(Base64.Decode(DecryString));
            }
            catch (Exception ex)
            {
                return "{[本地解密异常][DecryptRSAByCer][" + ex.Message + "]}";
            }
        }

        /*加密核心
         * Src加密内容
         * 
         * PFXorCER  证书
         * 
         * Mode  加密或解密  true  OR  false
         */
        private static byte[] RSAEDCore(byte[] Src,AsymmetricKeyParameter PFXorCER,bool Mode) 
        {
            IAsymmetricBlockCipher engine = new RsaEngine();
            IBufferedCipher Cipher = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");//加密标准

            Cipher.Init(Mode, PFXorCER);//初始加密程序

            byte[] EDString = null;

            int blockSize = Cipher.GetBlockSize();//获取分段长度  

            for (int i = 0; i < Src.Length; i += blockSize)
            {
                byte[] outBytes = Cipher.DoFinal(Subarray(Src, i, i + blockSize));//数据加密
                EDString = AddAll(EDString, outBytes);
            }

            return EDString;
        }

        /*
         * 数据分块算法
         * 
         * array:源长度
         * 
         * startIndexInclusive:开始长度
         * 
         * endIndexExclusive:结束长度
         * 
         */
        private static byte[] Subarray(byte[] array, int startIndexInclusive, int endIndexExclusive)
        {
            if (array == null)
            {
                throw new IOException("byte[] array内容为空!异常:subarray(byte[],int,int)");
            }
            if (endIndexExclusive > array.Length)
            {
                endIndexExclusive = array.Length;
            }
            int newSize = endIndexExclusive - startIndexInclusive;
            if (newSize <= 0)
            {
                return new byte[0];
            }
            byte[] subarray = new byte[newSize];
            Array.Copy(array, startIndexInclusive, subarray, 0, newSize);
            return subarray;
        }

        /*
         * 数据拼接
         * 
         * array1   
         * 
         * array2
         * 
         * AddAll=array1+array2
         */
        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];
            Array.Copy(array1, 0, joinedArray, 0, array1.Length);
            Array.Copy(array2, 0, joinedArray, array1.Length, array2.Length);
            return joinedArray;
        }

        /*
         *=======================================
         */

        public static byte[] Clone(byte[] array)
        {
            if (array == null)
            {
                return null;
            }
            return (byte[])array.Clone() ;
        }

    }
}

PYTHON示例

RSAUtil.py

"""
-------------------------------------------------
   File Name:   RSAUtil
   Description:  PYTHON-RSA 加密/解密、加签/验签
   Author:       CANGMU
   date:        2024/5/27
-------------------------------------------------
"""
import base64
import binascii
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.serialization import pkcs12
from rsa import pkcs1, core, transform, PrivateKey, PublicKey, sign, verify, VerificationError


class RSAUtil:
    @staticmethod
    def load_key(cert_file_path, password=None):
        """Load a private or public key from a certificate file."""
        try:
            with open(cert_file_path, 'rb') as f:
                cert_data = f.read()

            if cert_file_path.endswith(('.pfx', '.p12')):
                private_key, _, _ = pkcs12.load_key_and_certificates(
                    cert_data,
                    password.encode() if password else None,
                    backend=default_backend()
                )
                return PrivateKey.load_pkcs1(private_key.private_bytes(
                    encoding=serialization.Encoding.PEM,
                    format=serialization.PrivateFormat.TraditionalOpenSSL,
                    encryption_algorithm=serialization.NoEncryption()
                ))
            else:
                certificate = x509.load_pem_x509_certificate(cert_data, backend=default_backend())
                return PublicKey.load_pkcs1_openssl_pem(certificate.public_key().public_bytes(
                    encoding=serialization.Encoding.PEM,
                    format=serialization.PublicFormat.SubjectPublicKeyInfo
                ))
        except Exception as e:
            print(f"Error loading key: {e}")
            return None

    @staticmethod
    def _chunk_data(data, chunk_size):
        """Yield successive chunks from the input data."""
        for i in range(0, len(data), chunk_size):
            yield data[i:i + chunk_size]

    @staticmethod
    def pri_encrypt(encrypt_text, pfx_path, pfxpass):
        """Encrypt data using a private key."""
        key = RSAUtil.load_key(pfx_path, pfxpass)
        key_length = key.n.bit_length() // 8
        block_size = key_length - 11
        encrypt_text_base64 = base64.b64encode(encrypt_text.encode('utf-8'))
        encrypted_data = b''

        for chunk in RSAUtil._chunk_data(encrypt_text_base64, block_size):
            chunk = pkcs1._pad_for_signing(chunk, key_length)
            num = transform.bytes2int(chunk)
            encrypted = core.encrypt_int(num, key.d, key.n)
            encrypted_bytes = transform.int2bytes(encrypted)

            # 确保加密数据填充前导零以匹配密钥长度
            pad_length = key_length - len(encrypted_bytes)
            padded_data = b'\x00' * pad_length + encrypted_bytes
            encrypted_data += padded_data

        return encrypted_data.hex()

    @staticmethod
    def pub_decrypt(decrypt_text, cer_path):
        """Decrypt data using a public key."""
        key = RSAUtil.load_key(cer_path)
        block_size = key.n.bit_length() // 8
        decrypt_text_unhex = binascii.unhexlify(decrypt_text)
        decrypted_data = b''

        for chunk in RSAUtil._chunk_data(decrypt_text_unhex, block_size):
            num = transform.bytes2int(chunk)
            decrypted_int = core.decrypt_int(num, key.e, key.n)
            decrypted_data += transform.int2bytes(decrypted_int)

        return base64.b64decode(decrypted_data).decode('utf-8')

    @staticmethod
    def pub_encrypt(encrypt_text, cer_path):
        """Encrypt data using a public key."""
        key = RSAUtil.load_key(cer_path)
        block_size = key.n.bit_length() // 8 - 11
        encrypted_data = b''

        for chunk in RSAUtil._chunk_data(base64.b64encode(encrypt_text.encode('utf-8')), block_size):
            encrypted_data += pkcs1.encrypt(chunk, key)

        return encrypted_data.hex()

    @staticmethod
    def pri_decrypt(decrypt_text, pfx_path, pfxpass):
        """Decrypt data using a private key."""
        key = RSAUtil.load_key(pfx_path, pfxpass)
        block_size = key.n.bit_length() // 8
        decrypted_data = b''

        for chunk in RSAUtil._chunk_data(binascii.unhexlify(decrypt_text), block_size):
            decrypted_data += pkcs1.decrypt(chunk, key)

        return base64.b64decode(decrypted_data).decode('utf-8')

    @staticmethod
    def pri_sign(sign_text, algorithm_name, pfx_path, pfxpass):
        """Sign data using a private key and the specified hash algorithm."""
        key = RSAUtil.load_key(pfx_path, pfxpass)
        return sign(sign_text.encode('utf-8'), key, algorithm_name).hex()

    @staticmethod
    def pub_verify(data, sign_text, cer_path):
        """Verify a signature using a public key and the specified hash algorithm."""
        key = RSAUtil.load_key(cer_path)
        try:
            verify(data.encode('utf-8'), binascii.unhexlify(sign_text), key)
            return True
        except VerificationError:
            return False

    @staticmethod
    def pri_sha1_sign(sign_text, pfx_path, pfxpass):
        return RSAUtil.pri_sign(sign_text, 'SHA-1', pfx_path, pfxpass)

    @staticmethod
    def pub_sha1_verify(data, sign_text, cer_path):
        return RSAUtil.pub_verify(data, sign_text, cer_path)

    @staticmethod
    def pri_sha256_sign(sign_text, pfx_path, pfxpass):
        return RSAUtil.pri_sign(sign_text, 'SHA-256', pfx_path, pfxpass)

    @staticmethod
    def pub_sha256_verify(data, sign_text, cer_path):
        return RSAUtil.pub_verify(data, sign_text, cer_path)

# Example usage
if __name__ == '__main__':

    test_data = 'send_time=2018-01-24 13:25:33&msg_id=456795112&version=4.0.0.0&123=100000949&txn_type=03&member_id=100000749&dgtl_envlp=5a9c3ac419735d249e319727c89cfc0ce4a80d6a954980eaf3ea934316a56a121c758b0d13bf3302b877a8dd68619db&user_id=123'
    pfx_path1 = 'D:\\cert\\BAOFU20240612_pri.pfx'
    pfx_psw1 = '123456'
    cer_path1 = 'D:\\cert\\BAOFU20240612_pub1.cer'

    pfx_path = 'D:\\cert\\key_5181200731000138828@@2103031802000005106.pfx'
    pfx_psw = '5181200731000138828_190684'
    cer_path = 'D:\\cert\\key_5181200731000138828@@2103031802000005106.cer'

    pri_encrypted = RSAUtil.pri_encrypt(test_data, pfx_path, pfx_psw)
    print("Private key encryption:", pri_encrypted)

    decrypted = RSAUtil.pub_decrypt(pri_encrypted, cer_path)
    print("Public key decryption:", decrypted)

    pub_encrypted = RSAUtil.pub_encrypt(test_data, cer_path)
    print("Public key encryption:", pub_encrypted)

    decrypted_pri = RSAUtil.pri_decrypt(pub_encrypted, pfx_path, pfx_psw)
    print("Private key decryption:", decrypted_pri)

    sha256_sign_str = RSAUtil.pri_sha256_sign(test_data, pfx_path, pfx_psw)
    print("Private key sign-sha256:", sha256_sign_str)
    sha256_verify = RSAUtil.pub_sha256_verify(test_data, sha256_sign_str, cer_path)
    print("Public key verify-sha256:", sha256_verify)

    sha1_sign_str = RSAUtil.pri_sha1_sign(test_data, pfx_path, pfx_psw)
    print("Private key sign-sha1:", sha1_sign_str)
    sha1_verify = RSAUtil.pub_sha1_verify(test_data, sha1_sign_str, cer_path)
    print("Public key verify-sha1:", sha1_verify)

NODEJS示例

更新说明:

  • 2024-5-27 创建nodejs 加解密示例
  • 2024-12-23 优化读取证书方法loadCert,兼容1024和2048证书的读取
  • 私钥加密:privateEncrypt
  • 公钥解密:publicDecrypt

RSAUtil.js

const fs = require('fs');
const forge = require('node-forge');
const crypto = require('crypto');

// 读取和解析证书(PFX 和 CER)
function loadCert(filePath, password = null, isPfx = false) {
    const certBuffer = fs.readFileSync(filePath, 'binary');
    let cert, key, blocks;
    try{
        if (isPfx) {
            // 解析 PFX 文件
            const pfxAsn1 = forge.asn1.fromDer(certBuffer);
            const pfx = forge.pkcs12.pkcs12FromAsn1(pfxAsn1, password);
            pfx.safeContents.forEach((safeContent) => {
                safeContent.safeBags.forEach((safeBag) => {
                    if (safeBag.type === forge.pki.oids.pkcs8ShroudedKeyBag) {
                        key = safeBag.key;
                    } else if (safeBag.type === forge.pki.oids.certBag) {
                        cert = safeBag.cert;
                    }
                });
            });
            if (!key) {
                throw new Error('Private key not found in PFX file.');
            }
            blocks = key.n.toString(16).length / 2;
            return { pem: forge.pki.privateKeyToPem(key), blocks };
        } else {
            // 解析 CER 文件
            cert = forge.pki.certificateFromPem(certBuffer);
            const publicKey = cert.publicKey;
            blocks = publicKey.n.toString(16).length / 2;
            return { pem: forge.pki.publicKeyToPem(publicKey), blocks };
        }
    } catch (error) {
        throw new Error(`Failed to parse file ${filePath}: ${error.message}`);
    }

}

// 使用 RSA 公钥加密
function publicEncrypt(data, cerPath) {
    const { pem, blocks } = loadCert(cerPath, null, false);
    const input = Buffer.from(data, 'utf8');
    return encrypt(input, pem, blocks, crypto.publicEncrypt);
}

// 使用 RSA 私钥解密
function privateDecrypt(data, pfxPath, pfxPass) {
    const { pem, blocks } = loadCert(pfxPath, pfxPass, true);
    const input = Buffer.from(data, 'hex');
    return decrypt(input, pem, blocks, crypto.privateDecrypt);
}

// 使用 RSA 私钥加密
function privateEncrypt(data, pfxPath, pfxPass) {
    const { pem, blocks } = loadCert(pfxPath, pfxPass, true);
    const input = Buffer.from(data, 'utf8');
    return encrypt(input, pem, blocks, crypto.privateEncrypt);
}

// 使用 RSA 公钥解密
function publicDecrypt(data, cerPath) {
    const { pem, blocks } = loadCert(cerPath, null, false);
    const input = Buffer.from(data, 'hex');
    return decrypt(input, pem, blocks, crypto.publicDecrypt);
}

// 通用加密函数
function encrypt(input, pem, blocks, encryptFunc) {
    const encrypted = [];
    for (let i = 0; i < input.length; i += (blocks - 11)) {
        encrypted.push(encryptFunc(
            { key: pem, padding: crypto.constants.RSA_PKCS1_PADDING },
            input.subarray(i, i + (blocks - 11))
        ));
    }
    return Buffer.concat(encrypted).toString('hex');
}

// 通用解密函数
function decrypt(input, pem, blocks, decryptFunc) {
    const decrypted = [];
    for (let i = 0; i < input.length; i += blocks) {
        decrypted.push(decryptFunc(
            { key: pem, padding: crypto.constants.RSA_PKCS1_PADDING },
            input.subarray(i, i + blocks)
        ));
    }
    return Buffer.concat(decrypted).toString('utf8');
}

// 创建签名
function createSign(data, pfxPath, pfxPass, algorithm) {
    const sign = crypto.createSign(algorithm);
    sign.update(data);
    sign.end();
    const { pem } = loadCert(pfxPath, pfxPass, true);
    return sign.sign(pem).toString('hex');
}

// 验证签名
function verifySign(data, sign, cerPath, algorithm) {
    const { pem } = loadCert(cerPath, null, false);
    const verify = crypto.createVerify(algorithm);
    verify.update(data);
    verify.end();
    return verify.verify(pem, Buffer.from(sign, 'hex'));
}

// 使用 RSA-SHA1 创建签名
function createSignSHA1(data, pfxPath, pfxPass) {
    return createSign(data, pfxPath, pfxPass, 'RSA-SHA1');
}

// 使用 RSA-SHA1 验证签名
function verifySignSHA1(data, sign, cerPath) {
    return verifySign(data, sign, cerPath, 'RSA-SHA1');
}

// 使用 RSA-SHA256 创建签名
function createSignSHA256(data, pfxPath, pfxPass) {
    return createSign(data, pfxPath, pfxPass, 'RSA-SHA256');
}

// 使用 RSA-SHA256 验证签名
function verifySignSHA256(data, sign, cerPath) {
    return verifySign(data, sign, cerPath, 'RSA-SHA256');
}

module.exports = {
    publicEncrypt,
    privateDecrypt,
    privateEncrypt,
    publicDecrypt,
    createSignSHA1,
    verifySignSHA1,
    createSignSHA256,
    verifySignSHA256
};


//----------------------------------------------------------------------------------------------------
const pfxpath = "D:\\cert\\BAOFU20240612_pri.pfx";
const cerpath = "D:\\cert\\BAOFU20240612_pub1.cer";
const pfxPass = "123456";

const pfxpath1 = "D:\\cert\\key_5181200731000138828@@2103031802000005106.pfx";
const cerpath1 = "D:\\cert\\key_5181200731000138828@@2103031802000005106.cer";
const pfxPass1 = "5181200731000138828_190684";

// 测试数据
const testData = 'send_time=2018-01-24 13:25:33&msg_id=456795112&version=4.0.0.0&123=100000949&txn_type=03&member_id=100000749&dgtl_envlp=5a9c3ac419735d249e319727c89cfc0ce4a80d6a954980eaf3ea934316a56a121c758b0d13bf3302b877a8dd68619db&user_id=123';
console.log("-------------String-------------:", testData);
// 测试加密和解密
const encryptedStr = publicEncrypt(testData, cerpath);
console.log("-------------Encrypted String-------------:", encryptedStr);

const decryptedStr = privateDecrypt(encryptedStr, pfxpath, pfxPass);
console.log("-------------Decrypted String-------------:", decryptedStr);

// 测试私钥加密和公钥解密
const priEncryptedStr = privateEncrypt(testData, pfxpath, pfxPass);
console.log("-------------Private Encrypted String-------------:", priEncryptedStr);

const pubDecryptedStr = publicDecrypt(priEncryptedStr, cerpath);
console.log("-------------Public Decrypted String-------------:", pubDecryptedStr);

// 测试签名和验签
const signatureStr = createSignSHA1(testData, pfxpath, pfxPass);
console.log("-------------Signature SHA1-------------:", signatureStr);

const isVerified = verifySignSHA1(testData, signatureStr, cerpath);
console.log("-------------Verification SHA1 Result-------------:", isVerified);

const signatureStr1 = createSignSHA256(testData, pfxpath, pfxPass);
console.log("-------------Signature SHA256-------------:", signatureStr1);

const isVerified1 = verifySignSHA256(testData, signatureStr1, cerpath);
console.log("-------------Verification SHA256 Result-------------:", isVerified1);

GOLANG示例

  • 私钥加密
  • 公钥解密

RSAUtil.go

package main

import (
    "bytes"
    "crypto"
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha1"
    "crypto/x509"
    "encoding/base64"
    "encoding/hex"
    "encoding/pem"
    "errors"
    "fmt"
    "io"
    "math/big"
    "os"

    "golang.org/x/crypto/pkcs12"
)

var (
    ErrDataToLarge     = errors.New("message too long for RSA public key size")
    ErrDataLen         = errors.New("data length error")
    ErrDataBroken      = errors.New("data broken, first byte is not zero")
    ErrKeyPairDismatch = errors.New("data is not encrypted by the private key")
    ErrDecryption      = errors.New("decryption error")
    ErrPublicKey       = errors.New("get public key error")
    ErrPrivateKey      = errors.New("get private key error")
)

func LoadPrivateKey(privateKeyName, privatePassword string) (*rsa.PrivateKey, error) {
    bytes, err := readFile(privateKeyName)
    if err != nil {
        return nil, err
    }

    blocks, err := pkcs12.ToPEM(bytes, privatePassword)
    if err != nil {
        return nil, err
    }
    // 寻找私钥块
    var privBlock *pem.Block
    for _, block := range blocks {
        if block.Type == "PRIVATE KEY" {
            privBlock = block
            break
        }
    }
    if privBlock == nil {
        return nil, errors.New("failed to find PRIVATE KEY block")
    }

    // 尝试解析私钥
    privInterface, err := parsePrivateKey(privBlock.Bytes)
    if err != nil {
        return nil, err
    }

    // 转换为 RSA 私钥
    priv, ok := privInterface.(*rsa.PrivateKey)
    if !ok {
        return nil, errors.New("failed to convert private key to RSA format")
    }

    return priv, nil
}

// parsePrivateKey 解析私钥
func parsePrivateKey(data []byte) (interface{}, error) {
    // 尝试解析为 PKCS#8 私钥
    priv, err := x509.ParsePKCS8PrivateKey(data)
    if err == nil {
        return priv, nil
    }

    // 尝试解析为 EC 私钥
    privEC, err := x509.ParseECPrivateKey(data)
    if err == nil {
        return privEC, nil
    }

    // 尝试解析为 PKCS#1 私钥
    privRSA, err := x509.ParsePKCS1PrivateKey(data)
    if err == nil {
        return privRSA, nil
    }

    return nil, errors.New("failed to parse private key")
}

func LoadPublicKey(publicName string) (*rsa.PublicKey, error) {
    bytes, err := readFile(publicName)
    if err != nil {
        return nil, err
    }

    block, _ := pem.Decode(bytes)
    if block == nil {
        return nil, errors.New("failed to decode PEM block containing public key")
    }
    x509Cer, err := x509.ParseCertificate(block.Bytes)
    if err != nil {
        return nil, err
    }

    publicKey, ok := x509Cer.PublicKey.(*rsa.PublicKey)
    if !ok {
        return nil, errors.New("failed to assert type *rsa.PublicKey")
    }

    return publicKey, nil
}

func EncryptWithPrivateKey(data, pfxpath, pfxpass string) (string, error) {
    privateKey, err := LoadPrivateKey(pfxpath, pfxpass)
    if err != nil {
        return "", err
    }
    baseData := base64.StdEncoding.EncodeToString([]byte(data))
    return encryptDecryptWithPrivateKey(privateKey, baseData, true)
}

func DecryptWithPublicKey(data, pubpath string) (string, error) {
    dataByte, err := hex.DecodeString(data)
    if err != nil {
        return "", err
    }
    publicKey, err := LoadPublicKey(pubpath)
    if err != nil {
        return "", err
    }
    return encryptDecryptWithPublicKey(publicKey, dataByte, false)
}

func EncryptWithPublicKey(data, cerpath string) (string, error) {
    publicKey, err := LoadPublicKey(cerpath)
    if err != nil {
        return "", err
    }
    baseData := base64.StdEncoding.EncodeToString([]byte(data))
    return encryptDecryptWithPublicKey(publicKey, []byte(baseData), true)
}

func DecryptWithPrivateKey(data, pripath, pfxpass string) (string, error) {
    dataByte, err := hex.DecodeString(data)
    if err != nil {
        return "", err
    }
    privateKey, err := LoadPrivateKey(pripath, pfxpass)
    if err != nil {
        return "", err
    }
    return encryptDecryptWithPrivateKey(privateKey, string(dataByte), false)
}

func SignSha1WithRsa(data, pripath, pfxpass string) (string, error) {
    privateKey, err := LoadPrivateKey(pripath, pfxpass)
    if err != nil {
        return "", err
    }

    sha1Hash := sha1.New()
    sha1Hash.Write([]byte(data))
    hashed := sha1Hash.Sum(nil)
    signByte, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA1, hashed)

    return hex.EncodeToString(signByte), err
}

func VerifySignSha1WithRsa(data, signData, cerpath string) error {
    publicKey, err := LoadPublicKey(cerpath)
    if err != nil {
        return err
    }

    sign, err := hex.DecodeString(signData)
    if err != nil {
        return err
    }
    hash := sha1.New()
    hash.Write([]byte(data))
    return rsa.VerifyPKCS1v15(publicKey, crypto.SHA1, hash.Sum(nil), sign)
}

func pubKeyIO(pub *rsa.PublicKey, in io.Reader, out io.Writer, isEncrypt bool) error {
    k := (pub.N.BitLen() + 7) / 8
    if isEncrypt {
        k -= 11
    }
    buf := make([]byte, k)
    var b []byte
    for {
        size, err := in.Read(buf)
        if err != nil {
            if err == io.EOF {
                return nil
            }
            return err
        }
        if size < k {
            b = buf[:size]
        } else {
            b = buf
        }
        if isEncrypt {
            b, err = rsa.EncryptPKCS1v15(rand.Reader, pub, b)
        } else {
            b, err = pubKeyDecrypt(pub, b)
        }
        if err != nil {
            return err
        }
        if _, err = out.Write(b); err != nil {
            return err
        }
    }
}

func priKeyIO(pri *rsa.PrivateKey, in io.Reader, out io.Writer, isEncrypt bool) error {
    k := (pri.N.BitLen() + 7) / 8
    if isEncrypt {
        k -= 11
    }
    buf := make([]byte, k)
    var b []byte
    for {
        size, err := in.Read(buf)
        if err != nil {
            if err == io.EOF {
                return nil
            }
            return err
        }
        if size < k {
            b = buf[:size]
        } else {
            b = buf
        }
        if isEncrypt {
            b, err = priKeyEncrypt(rand.Reader, pri, b)
        } else {
            b, err = rsa.DecryptPKCS1v15(rand.Reader, pri, b)
        }
        if err != nil {
            return err
        }
        if _, err = out.Write(b); err != nil {
            return err
        }
    }
}

func pubKeyDecrypt(pub *rsa.PublicKey, data []byte) ([]byte, error) {
    k := (pub.N.BitLen() + 7) / 8
    if k != len(data) {
        return nil, ErrDataLen
    }
    m := new(big.Int).SetBytes(data)
    if m.Cmp(pub.N) > 0 {
        return nil, ErrDataToLarge
    }
    m.Exp(m, big.NewInt(int64(pub.E)), pub.N)
    d := leftPad(m.Bytes(), k)
    if d[0] != 0 {
        return nil, ErrDataBroken
    }
    if d[1] != 0 && d[1] != 1 {
        return nil, ErrKeyPairDismatch
    }
    var i = 2
    for ; i < len(d); i++ {
        if d[i] == 0 {
            break
        }
    }
    i++
    if i == len(d) {
        return nil, nil
    }
    return d[i:], nil
}

func priKeyEncrypt(rand io.Reader, priv *rsa.PrivateKey, hashed []byte) ([]byte, error) {
    tLen := len(hashed)
    k := (priv.N.BitLen() + 7) / 8
    if k < tLen+11 {
        return nil, ErrDataLen
    }
    em := make([]byte, k)
    em[1] = 1
    for i := 2; i < k-tLen-1; i++ {
        em[i] = 0xff
    }
    copy(em[k-tLen:k], hashed)
    m := new(big.Int).SetBytes(em)
    c, err := decrypt(rand, priv, m)
    if err != nil {
        return nil, err
    }
    copyWithLeftPad(em, c.Bytes())
    return em, nil
}

func encryptDecryptWithPrivateKey(privateKey *rsa.PrivateKey, data string, isEncrypt bool) (string, error) {
    out := bytes.NewBuffer(nil)
    in := bytes.NewReader([]byte(data))
    if err := priKeyIO(privateKey, in, out, isEncrypt); err != nil {
        return "", err
    }

    result, err := io.ReadAll(out)
    if err != nil {
        return "", err
    }

    if isEncrypt {
        return hex.EncodeToString(result), nil
    }
    dataBs, err := base64.StdEncoding.DecodeString(string(result))
    if err != nil {
        return "", err
    }
    return string(dataBs), nil
}

func encryptDecryptWithPublicKey(publicKey *rsa.PublicKey, data []byte, isEncrypt bool) (string, error) {
    out := bytes.NewBuffer(nil)
    in := bytes.NewReader(data)
    if err := pubKeyIO(publicKey, in, out, isEncrypt); err != nil {
        return "", err
    }

    result, err := io.ReadAll(out)
    if err != nil {
        return "", err
    }

    if isEncrypt {
        return hex.EncodeToString(result), nil
    }
    dataBs, err := base64.StdEncoding.DecodeString(string(result))
    if err != nil {
        return "", err
    }
    return string(dataBs), nil
}

func readFile(fileName string) ([]byte, error) {
    return os.ReadFile(fileName)
}

func leftPad(input []byte, length int) []byte {
    if len(input) >= length {
        return input
    }
    padding := make([]byte, length-len(input))
    return append(padding, input...)
}

func copyWithLeftPad(dst, src []byte) {
    copy(dst[len(dst)-len(src):], src)
}

func decrypt(random io.Reader, priv *rsa.PrivateKey, c *big.Int) (*big.Int, error) {
    if c.Cmp(priv.N) > 0 {
        return nil, ErrDecryption
    }
    var ir *big.Int
    if priv.Precomputed.Dp == nil {
        ir = new(big.Int).Exp(c, priv.D, priv.N)
    } else {
        m := new(big.Int).Exp(c, priv.Precomputed.Dp, priv.Primes[0])
        m2 := new(big.Int).Exp(c, priv.Precomputed.Dq, priv.Primes[1])
        m.Sub(m, m2)
        if m.Sign() < 0 {
            m.Add(m, priv.Primes[0])
        }
        m.Mul(m, priv.Precomputed.Qinv)
        m.Mod(m, priv.Primes[0])
        m.Mul(m, priv.Primes[1])
        m.Add(m, m2)
        ir = m
    }
    return ir, nil
}

func main() {
    fmt.Println("RSA Encryption Decryption Example")
    plaintext := `{
        "header": {
            "memberId": "102004465",
            "serviceTp": "T-1001-013-01",
            "verifyType": "1",
            "terminalId": "102004465"
        },
        "body": {
            "version": "4.1.0",
            "accType": 2,
            "accInfo": {
                "transSerialNo": "seq081600001",
                "loginNo": "cnk033447rgc73f2u980",
        },"noticeUrl":"","businessType":"BCT2.0"
    }`
    pfxpath := "D:\\GEP\\正式环境证书生成工具\\certool\\keyfile_pri.pfx"
    pfxpsw := "123456"
    cerpath := "D:\\GEP\\正式环境证书生成工具\\certool\\keyfile_pub.cer"

    encryptstr, err := EncryptWithPrivateKey(plaintext, pfxpath, pfxpsw)
    if err != nil {
        fmt.Printf("私钥加密失败: %v\n", err)
        return
    }
    fmt.Printf("私钥加密encryptstr: %v\n", encryptstr)

    decryptstr, err := DecryptWithPublicKey(encryptstr, cerpath)
    if err != nil {
        fmt.Printf("公钥解密失败: %v\n", err)
        return
    }
    fmt.Printf("公钥decryptstr: %v\n", decryptstr)

    encryptstr1, err := EncryptWithPublicKey(plaintext, cerpath)
    if err != nil {
        fmt.Printf("公钥加密失败: %v\n", err)
        return
    }
    fmt.Printf("公钥encryptstr: %v\n", encryptstr1)

    decryptstr1, err := DecryptWithPrivateKey(encryptstr1, pfxpath, pfxpsw)
    if err != nil {
        fmt.Printf("私钥解密失败: %v\n", err)
        return
    }
    fmt.Printf("私钥decryptstr: %v\n", decryptstr1)
}
作者:陈花枪  创建时间:2024-08-15 10:18
最后编辑:陈花枪  更新时间:2025-05-26 15:03