加密过程

  1. 按照加密数据dataContent列表参数组装JSON串明文

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

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

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

解密过程

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

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

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

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

加解密过程图解

生产证书操作说明

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

加解密示例

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示例

更新说明:

  • 2024-07-25 修复加密后密文前缀为00时会丢失的问题

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证书的读取

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"
    "io/ioutil"
    "math/big"

    "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
    }
    if len(blocks) != 2 {
        return nil, errors.New("failed to decode PEM block containing private key")
    }
    privateKey, err := x509.ParsePKCS1PrivateKey(blocks[0].Bytes)
    if err != nil {
        return nil, err
    }

    return privateKey, nil
}

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 := ioutil.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 := ioutil.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 ioutil.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 := "Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!"
    encryptstr, err := EncryptWithPrivateKey(plaintext, "D:\\GEP\\key_5181200731000138828@@2103031802000005106.pfx", "5181200731000138828_190684")
    if err != nil {
        fmt.Printf("私钥加密失败: %v\n", err)
        return
    }
    fmt.Printf("私钥加密encryptstr: %v\n", encryptstr)

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

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

    decryptstr1, err := DecryptWithPrivateKey(encryptstr1, "D:\\GEP\\key_5181200731000138828@@2103031802000005106.pfx", "5181200731000138828_190684")
    if err != nil {
        fmt.Printf("私钥解密失败: %v\n", err)
        return
    }
    fmt.Printf("私钥decryptstr: %v\n", decryptstr1)
}
作者:陈花枪  创建时间:2024-08-15 10:18
最后编辑:陈花枪  更新时间:2025-04-07 14:39