Bootstrap

rsa加签验签C#和js、java、微信小程序互通

js实现rsa加签验签

https://github.com/kjur/jsrsasign
11.1.0版本
解压选择需要的版本,这里选择all版本了
在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JS RSA加签验签</title>
</head>
<body>

</body>
<script src="jsrsasign-all-min.js"></script>
<script type="text/javascript">
    // 公钥
    let pk = "-----BEGIN PUBLIC KEY-----\n" +
        "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD3XSdz1MnzazBEN5KOfTx0IyVJ\n" +
        "Z5wb57isrCuHDhnYXwtmdhQalgII0fozeeFpMpAvlnmHC1kpW7XVGvZnLx3bWbCE\n" +
        "bf+pMSW4kmQuI+5cxRUJbCl7sdaODBrINgERHPICVC18AJLThEVMHyjuR6Jn4zQm\n" +
        "yYNbReSktY/BrFTvMQIDAQAB\n" +
        "-----END PUBLIC KEY-----";
    // 私钥
    let priK = "-----BEGIN PRIVATE KEY-----\n" +
        "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAPddJ3PUyfNrMEQ3\n" +
        "ko59PHQjJUlnnBvnuKysK4cOGdhfC2Z2FBqWAgjR+jN54WkykC+WeYcLWSlbtdUa\n" +
        "9mcvHdtZsIRt/6kxJbiSZC4j7lzFFQlsKXux1o4MGsg2AREc8gJULXwAktOERUwf\n" +
        "KO5HomfjNCbJg1tF5KS1j8GsVO8xAgMBAAECgYEA6eG1JMrj63jEmStmMb1txG1a\n" +
        "mu4Q5z2QGgtr2HVXsIIlGEq6tWxyHf7TL4qkuz9onuYKn8n2Eqm44fZtVaBx+5ES\n" +
        "zRpIvlTvaxmVu0HZ1hYAzUw1XyRnXNMKpL5tT4GCjm8+QGPzlGxgXI1sNg8r9Jaw\n" +
        "9zRUYeA6LQR9RIMkHWUCQQD8QojjVoGjtiunoh/N8iplhUszZIavAEvmDIE+kVy+\n" +
        "pA7hvlukLw6JMc7cfTcnHyxDo9iHVIzrWlTuKRq9KWVLAkEA+wgJS2sgtldnCVn6\n" +
        "tJKFVwsHrWhMIU29msPPbNuWUD23BcKE/vehIyFu1ahNA/TiM40PEnzprQ5JfPxU\n" +
        "16S78wJANTfMLTnYy7Lo7sqTLx2BuD0wqjzw9QZ4/KVytsJv8IAn65P/PVn4FRV+\n" +
        "8KEx+3zmF7b/PT2nJRe/hycAzxtmlQJBAMrFwQxEqpXfoAEzx4lY2ZBn/nmaR/SW\n" +
        "4VNEXCbocVC7qT1j1R5HVMgV13uKiTtq8dUGWmhqsi7x3XayNK5ECPUCQQDZaAN6\n" +
        "tvIHApz9OLsXSw0jZirQ6KEYdharXbIVDy1W1sVE3lzLbqLdFp1bxAHQIvsYS5PM\n" +
        "A9veSJh372RLJKkj\n" +
        "-----END PRIVATE KEY-----";

    // 原文
    var src = "好厉害";
    src="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiMTU2MjEzNTc1MDEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ4MDY5NjUyNDQ4NDY3NyIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0";
    // 创建 Signature 对象
    let signature = new KJUR.crypto.Signature({alg: "SHA1withRSA", prvkeypem: priK});    //!这里指定 私钥 pem!
    signature.updateString(src);
    let a = signature.sign();
    let sign = hextob64(a);

    console.log("jsrsasign: \n"+sign);

    // 验签
    // !要重新new 一个Signature, 否则, 取摘要和签名时取得摘要不一样, 导致验签误报失败(原因不明)!
    let signatureVf = new KJUR.crypto.Signature({alg: "SHA1withRSA", prvkeypem: pk});
    signatureVf.updateString(src);
    // !接受的参数是16进制字符串!
    let b = signatureVf.verify(b64tohex(sign));
    console.log("jsrsasign verify: " + b);
</script>
</html>

在这里插入图片描述
也可以换成SHA256withRSA

vue中使用

npm i jsrsasign

使用

import jsrsasign from 'jsrsasign';
let signData="";//原始数据
let sign="";//base64格式签名
let publicKey="";//公钥
let signatureVf = new jsrsasign.Signature({alg: "SHA256withRSA", prvkeypem: publicKey});
signatureVf.updateString(signData);
// !接受的参数是16进制字符串!
let b = signatureVf.verify(jsrsasign.b64tohex(sign));

微信小程序使用

找到npm/lib下jsrsasign.js,底部有export的js就是
在这里插入图片描述

import jsrsasign from './jsrsasign'
/**
 * 验签
 */
function veritify(data,sign,publickKey){
  let signatureVf = new jsrsasign.Signature({alg: "SHA256withRSA", prvkeypem: publickKey});
  signatureVf.updateString(data);
  let b = signatureVf.verify(jsrsasign.b64tohex(sign));
  return b;
}

C# 实现rsa加签验签

新建.net core3.1项目
安装BouncyCastle.Cryptography 2.4.0

RSAHelper

using System;
using System.Security.Cryptography;
using System.Text;
using System.Xml;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;

namespace RSACSharpJsStu01
{
    public class RSAHelper
    {
        /// <summary>
        /// 重写FromXmlString方法
        /// </summary>
        /// <param name="xmlString"></param>
        /// <returns></returns>
        public static RSACryptoServiceProvider FromXmlString(string xmlString)
        {
            var rsa = new RSACryptoServiceProvider();
            RSAParameters parameters = new RSAParameters();
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xmlString);
            if (xmlDoc.DocumentElement.Name.Equals("RSAKeyValue"))
            {
                foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes)
                {
                    switch (node.Name)
                    {
                        case "Modulus":
                            parameters.Modulus = Convert.FromBase64String(node.InnerText);
                            break;
                        case "Exponent":
                            parameters.Exponent = Convert.FromBase64String(node.InnerText);
                            break;
                        case "P":
                            parameters.P = Convert.FromBase64String(node.InnerText);
                            break;
                        case "Q":
                            parameters.Q = Convert.FromBase64String(node.InnerText);
                            break;
                        case "DP":
                            parameters.DP = Convert.FromBase64String(node.InnerText);
                            break;
                        case "DQ":
                            parameters.DQ = Convert.FromBase64String(node.InnerText);
                            break;
                        case "InverseQ":
                            parameters.InverseQ = Convert.FromBase64String(node.InnerText);
                            break;
                        case "D":
                            parameters.D = Convert.FromBase64String(node.InnerText);
                            break;
                    }
                }
            }
            else
            {
                throw new Exception("Invalid XML RSA key.");
            }

            rsa.ImportParameters(parameters);
            return rsa;
        }

        /// <summary>
        /// RSA公钥,从Java格式转.net格式(不依赖第三方包)
        /// </summary>
        /// <param name="publikKey"></param>
        /// <returns></returns>
        public static string RSAPublicKeyJava2DotNet(string publicKey)
        {
            RsaKeyParameters publicKeyParam =
                (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
            return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",
                Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
                Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
        }

        /// <summary>        
        /// RSA签名验证
        /// </summary> 
        /// <param name="encryptSource">签名</param>
        /// <param name="c">验证的字符串</param>
        /// <param name="publicKey">公钥</param>
        /// <returns>是否相同,true验证成功,false验证失败。</returns>
        public static bool VerifySignature(string encryptSource, string compareString, string publicKey)
        {
            try
            {
                //.net core2.2及其以下版本使用,重写FromXmlString(string)方法
                //using RSACryptoServiceProvider rsa = FromXmlString(RSAPublicKeyJava2DotNet(publicKey));
                var rsa = new RSACryptoServiceProvider();
                rsa.FromXmlString(RSAPublicKeyJava2DotNet(publicKey)); //.net core3.0直接使用,不需要重写
                byte[] signature = Convert.FromBase64String(encryptSource);
                //SHA1Managed sha1 = new SHA1Managed();
                SHA256Managed sha256 = new SHA256Managed();
               
                RSAPKCS1SignatureDeformatter df = new RSAPKCS1SignatureDeformatter(rsa);
                df.SetHashAlgorithm("SHA256");
                byte[] compareByte = sha256.ComputeHash(Encoding.UTF8.GetBytes(compareString));

                return df.VerifySignature(compareByte, signature);
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// RSA私钥,从Java格式转.net格式(不依赖第三方包)
        /// </summary>
        /// <param name="privateKey">私钥</param>
        /// <returns></returns>
        public static string RSAPrivateKeyJava2DotNet(string privateKey)
        {
            RsaPrivateCrtKeyParameters privateKeyParam =
                (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey));
            return string.Format(
                "<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",
                Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()),
                Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned()));
        }

        /// <summary>
        /// 私钥签名
        /// </summary>
        /// <param name="contentForSign"></param>
        /// <param name="privateKey"></param>
        /// <returns></returns>
        public static string Sign(string contentForSign, string privateKey)
        {
            var netKey = RSAPrivateKeyJava2DotNet(privateKey); //转换成适用于.net的私钥

            //var rsa = FromXmlString(netKey); //.net core2.2及其以下版本使用,重写FromXmlString(string)方法

            var rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(netKey); //.net core3.0直接使用,不需要重写

            var rsaClear = new RSACryptoServiceProvider();
            var paras = rsa.ExportParameters(true);
            rsaClear.ImportParameters(paras); //签名返回
            //var sha1 = new SHA1CryptoServiceProvider();
            using (var sha256 = new SHA256CryptoServiceProvider())
            {
                var signData = rsa.SignData(Encoding.UTF8.GetBytes(contentForSign), sha256);
                return Convert.ToBase64String(signData);
            }
        }
    }
}

接口如下

using System.Text;
using Microsoft.AspNetCore.Mvc;

namespace RSACSharpJsStu01.Controllers
{
    [ApiController]
    public class IndexController : ControllerBase
    {
        // 公钥
        private string pk = //"-----BEGIN PUBLIC KEY-----\n" +
                "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD3XSdz1MnzazBEN5KOfTx0IyVJ\n" +
                "Z5wb57isrCuHDhnYXwtmdhQalgII0fozeeFpMpAvlnmHC1kpW7XVGvZnLx3bWbCE\n" +
                "bf+pMSW4kmQuI+5cxRUJbCl7sdaODBrINgERHPICVC18AJLThEVMHyjuR6Jn4zQm\n" +
                "yYNbReSktY/BrFTvMQIDAQAB\n"
            //+"-----END PUBLIC KEY-----"
            ;

        // 私钥
        private string priK = //"-----BEGIN PRIVATE KEY-----\n" +
                "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAPddJ3PUyfNrMEQ3\n" +
                "ko59PHQjJUlnnBvnuKysK4cOGdhfC2Z2FBqWAgjR+jN54WkykC+WeYcLWSlbtdUa\n" +
                "9mcvHdtZsIRt/6kxJbiSZC4j7lzFFQlsKXux1o4MGsg2AREc8gJULXwAktOERUwf\n" +
                "KO5HomfjNCbJg1tF5KS1j8GsVO8xAgMBAAECgYEA6eG1JMrj63jEmStmMb1txG1a\n" +
                "mu4Q5z2QGgtr2HVXsIIlGEq6tWxyHf7TL4qkuz9onuYKn8n2Eqm44fZtVaBx+5ES\n" +
                "zRpIvlTvaxmVu0HZ1hYAzUw1XyRnXNMKpL5tT4GCjm8+QGPzlGxgXI1sNg8r9Jaw\n" +
                "9zRUYeA6LQR9RIMkHWUCQQD8QojjVoGjtiunoh/N8iplhUszZIavAEvmDIE+kVy+\n" +
                "pA7hvlukLw6JMc7cfTcnHyxDo9iHVIzrWlTuKRq9KWVLAkEA+wgJS2sgtldnCVn6\n" +
                "tJKFVwsHrWhMIU29msPPbNuWUD23BcKE/vehIyFu1ahNA/TiM40PEnzprQ5JfPxU\n" +
                "16S78wJANTfMLTnYy7Lo7sqTLx2BuD0wqjzw9QZ4/KVytsJv8IAn65P/PVn4FRV+\n" +
                "8KEx+3zmF7b/PT2nJRe/hycAzxtmlQJBAMrFwQxEqpXfoAEzx4lY2ZBn/nmaR/SW\n" +
                "4VNEXCbocVC7qT1j1R5HVMgV13uKiTtq8dUGWmhqsi7x3XayNK5ECPUCQQDZaAN6\n" +
                "tvIHApz9OLsXSw0jZirQ6KEYdharXbIVDy1W1sVE3lzLbqLdFp1bxAHQIvsYS5PM\n" +
                "A9veSJh372RLJKkj\n"
            //+"-----END PRIVATE KEY-----"
            ;

        [HttpGet("/rsa")]
        public string Get()
        {
            var src = "好厉害";
            src =
                "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiMTU2MjEzNTc1MDEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ4MDY5NjUyNDQ4NDY3NyIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0";
            var sign = RSAHelper.Sign(src, priK);
            StringBuilder result = new StringBuilder();
            result.Append("加签结果:");
            result.Append(sign);
            var isSuccess = RSAHelper.VerifySignature(sign,src, pk);
            result.Append("验签结果:");
            result.Append(isSuccess + "");
            return result.ToString();
        }
    }
}

在这里插入图片描述
转化为RsaPemHelper

 public class PemHelper
    {
        static private Regex _PEMCode = new Regex(@"--+.+?--+|\s+");
        static private byte[] _SeqOID = new byte[] { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
        static private byte[] _Ver = new byte[] { 0x02, 0x01, 0x00 };

        /// <summary>
        /// 用PEM格式密钥对创建RSA,支持PKCS#1、PKCS#8格式的PEM
        /// </summary>
        public static RSACryptoServiceProvider FromPEM(string pem)
        {
            var rsaParams = new CspParameters();
            rsaParams.Flags = CspProviderFlags.UseMachineKeyStore;
            var rsa = new RSACryptoServiceProvider(rsaParams);

            var param = new RSAParameters();

            var base64 = _PEMCode.Replace(pem, "");
            var data = RSAUnitHelper.Base64DecodeBytes(base64);
            if (data == null)
            {
                throw new Exception("PEM内容无效");
            }
            var idx = 0;

            //读取长度
            Func<byte, int> readLen = (first) => {
                if (data[idx] == first)
                {
                    idx++;
                    if (data[idx] == 0x81)
                    {
                        idx++;
                        return data[idx++];
                    }
                    else if (data[idx] == 0x82)
                    {
                        idx++;
                        return (((int)data[idx++]) << 8) + data[idx++];
                    }
                    else if (data[idx] < 0x80)
                    {
                        return data[idx++];
                    }
                }
                throw new Exception("PEM未能提取到数据");
            };
            //读取块数据
            Func<byte[]> readBlock = () => {
                var len = readLen(0x02);
                if (data[idx] == 0x00)
                {
                    idx++;
                    len--;
                }
                var val = data.sub(idx, len);
                idx += len;
                return val;
            };
            //比较data从idx位置开始是否是byts内容
            Func<byte[], bool> eq = (byts) => {
                for (var i = 0; i < byts.Length; i++, idx++)
                {
                    if (idx >= data.Length)
                    {
                        return false;
                    }
                    if (byts[i] != data[idx])
                    {
                        return false;
                    }
                }
                return true;
            };




            if (pem.Contains("PUBLIC KEY"))
            {
                /****使用公钥****/
                //读取数据总长度
                readLen(0x30);
                if (!eq(_SeqOID))
                {
                    throw new Exception("PEM未知格式");
                }
                //读取1长度
                readLen(0x03);
                idx++;//跳过0x00
                      //读取2长度
                readLen(0x30);

                //Modulus
                param.Modulus = readBlock();

                //Exponent
                param.Exponent = readBlock();
            }
            else if (pem.Contains("PRIVATE KEY"))
            {
                /****使用私钥****/
                //读取数据总长度
                readLen(0x30);

                //读取版本号
                if (!eq(_Ver))
                {
                    throw new Exception("PEM未知版本");
                }

                //检测PKCS8
                var idx2 = idx;
                if (eq(_SeqOID))
                {
                    //读取1长度
                    readLen(0x04);
                    //读取2长度
                    readLen(0x30);

                    //读取版本号
                    if (!eq(_Ver))
                    {
                        throw new Exception("PEM版本无效");
                    }
                }
                else
                {
                    idx = idx2;
                }

                //读取数据
                param.Modulus = readBlock();
                param.Exponent = readBlock();
                param.D = readBlock();
                param.P = readBlock();
                param.Q = readBlock();
                param.DP = readBlock();
                param.DQ = readBlock();
                param.InverseQ = readBlock();
            }
            else
            {
                throw new Exception("pem需要BEGIN END标头");
            }

            rsa.ImportParameters(param);
            return rsa;
        }

        /// <summary>
        /// 将RSA中的密钥对转换成PEM格式,usePKCS8=false时返回PKCS#1格式,否则返回PKCS#8格式,如果convertToPublic含私钥的RSA将只返回公钥,仅含公钥的RSA不受影响
        /// </summary>
        public static string ToPEM(RSACryptoServiceProvider rsa, bool convertToPublic, bool usePKCS8)
        {
            var ms = new MemoryStream();
            //写入一个长度字节码
            Action<int> writeLenByte = (len) => {
                if (len < 0x80)
                {
                    ms.WriteByte((byte)len);
                }
                else if (len <= 0xff)
                {
                    ms.WriteByte(0x81);
                    ms.WriteByte((byte)len);
                }
                else
                {
                    ms.WriteByte(0x82);
                    ms.WriteByte((byte)(len >> 8 & 0xff));
                    ms.WriteByte((byte)(len & 0xff));
                }
            };
            //写入一块数据
            Action<byte[]> writeBlock = (byts) => {
                var addZero = (byts[0] >> 4) >= 0x8;
                ms.WriteByte(0x02);
                var len = byts.Length + (addZero ? 1 : 0);
                writeLenByte(len);

                if (addZero)
                {
                    ms.WriteByte(0x00);
                }
                ms.Write(byts, 0, byts.Length);
            };
            //根据后续内容长度写入长度数据
            Func<int, byte[], byte[]> writeLen = (index, byts) => {
                var len = byts.Length - index;

                ms.SetLength(0);
                ms.Write(byts, 0, index);
                writeLenByte(len);
                ms.Write(byts, index, len);

                return ms.ToArray();
            };


            if (rsa.PublicOnly || convertToPublic)
            {
                /****生成公钥****/
                var param = rsa.ExportParameters(false);


                //写入总字节数,不含本段长度,额外需要24字节的头,后续计算好填入
                ms.WriteByte(0x30);
                var index1 = (int)ms.Length;

                //固定内容
                // encoded OID sequence for PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
                ms.writeAll(_SeqOID);

                //从0x00开始的后续长度
                ms.WriteByte(0x03);
                var index2 = (int)ms.Length;
                ms.WriteByte(0x00);

                //后续内容长度
                ms.WriteByte(0x30);
                var index3 = (int)ms.Length;

                //写入Modulus
                writeBlock(param.Modulus);

                //写入Exponent
                writeBlock(param.Exponent);


                //计算空缺的长度
                var byts = ms.ToArray();

                byts = writeLen(index3, byts);
                byts = writeLen(index2, byts);
                byts = writeLen(index1, byts);


                return "-----BEGIN PUBLIC KEY-----\n" + RSAUnitHelper.TextBreak(RSAUnitHelper.Base64EncodeBytes(byts), 64) + "\n-----END PUBLIC KEY-----";
            }
            else
            {
                /****生成私钥****/
                var param = rsa.ExportParameters(true);

                //写入总字节数,后续写入
                ms.WriteByte(0x30);
                int index1 = (int)ms.Length;

                //写入版本号
                ms.writeAll(_Ver);

                //PKCS8 多一段数据
                int index2 = -1, index3 = -1;
                if (usePKCS8)
                {
                    //固定内容
                    ms.writeAll(_SeqOID);

                    //后续内容长度
                    ms.WriteByte(0x04);
                    index2 = (int)ms.Length;

                    //后续内容长度
                    ms.WriteByte(0x30);
                    index3 = (int)ms.Length;

                    //写入版本号
                    ms.writeAll(_Ver);
                }

                //写入数据
                writeBlock(param.Modulus);
                writeBlock(param.Exponent);
                writeBlock(param.D);
                writeBlock(param.P);
                writeBlock(param.Q);
                writeBlock(param.DP);
                writeBlock(param.DQ);
                writeBlock(param.InverseQ);


                //计算空缺的长度
                var byts = ms.ToArray();

                if (index2 != -1)
                {
                    byts = writeLen(index3, byts);
                    byts = writeLen(index2, byts);
                }
                byts = writeLen(index1, byts);


                var flag = " PRIVATE KEY";
                if (!usePKCS8)
                {
                    flag = " RSA" + flag;
                }
                return "-----BEGIN" + flag + "-----\n" + RSAUnitHelper.TextBreak(RSAUnitHelper.Base64EncodeBytes(byts), 64) + "\n-----END" + flag + "-----";
            }
        }
    }

如果有部分密钥加密解密报错可以使用PemHelper.FromPEM替代FromXmlString
可以看到js加签和C#加签结果一样,所以验签也是通过的

java代码实现

SHA256withRSAUtil.java

package com.wujialiang;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class SHA256withRSAUtil {

    private static final String RSA = "RSA";
    private static final String SHA256WITHRSA = "SHA256withRSA";

    /**
     * 生成RSA密钥
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA);
        keyPairGenerator.initialize(2048, new SecureRandom());
        return keyPairGenerator.genKeyPair();
    }

    /**
     * 获取私钥
     * @param base64
     * @return
     */
    public static PrivateKey getPrivateKey(String base64) throws Exception {
        // 解码Base64字符串回字节数组
        byte[] encodedPrivateKey = Base64.getDecoder().decode(base64);

        // 使用PKCS8EncodedKeySpec和KeyFactory来加载私钥
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
        KeyFactory kf = KeyFactory.getInstance(RSA);
        PrivateKey privateKey = kf.generatePrivate(keySpec);
        return privateKey;
    }

    /**
     * 获取私钥
     * @param base64
     * @return
     */
    public static PublicKey getPublicKey(String base64) throws Exception {
        // 解码Base64字符串回字节数组
        byte[] encodedPrivateKey = Base64.getDecoder().decode(base64);

        // 使用PKCS8EncodedKeySpec和KeyFactory来加载私钥
        //PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedPrivateKey);
        KeyFactory kf = KeyFactory.getInstance(RSA);
        PublicKey publicKey = kf.generatePublic(keySpec);
        return publicKey;
    }

    /**
     * 使用私钥对明文进行签名
     *
     * @param plainText  明文
     * @param privateKey 私钥
     * @return 签名结果
     * @throws Exception 签名异常
     */
    public static String sign(String plainText, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance(SHA256WITHRSA);
        signature.initSign(privateKey);
        signature.update(plainText.getBytes());
        return Base64.getEncoder().encodeToString(signature.sign());
    }


    /**
     * 使用公钥对签名进行验证
     *
     * @param plainText 明文
     * @param signature 签名结果
     * @param publicKey 公钥
     * @return 验证结果,true表示验证通过,false表示验证失败
     * @throws Exception 验证异常
     */
    public static boolean verify(String plainText, String signature, PublicKey publicKey) throws Exception {
        Signature signatureInstance = Signature.getInstance(SHA256WITHRSA);
        signatureInstance.initVerify(publicKey);
        signatureInstance.update(plainText.getBytes());
        byte[] decodedSignature = Base64.getDecoder().decode(signature);
        return signatureInstance.verify(decodedSignature);
    }
}

使用

package com.wujialiang;

/**
 * Hello world!
 */
public class App {
    public static void main(String[] args) {
        // 生成RSA密钥对
//        KeyPair keyPair = generateKeyPair();
//        PrivateKey privateKey = keyPair.getPrivate();
//        PublicKey publicKey = keyPair.getPublic();
        // 公钥
        String pk = //"-----BEGIN PUBLIC KEY-----\n" +
                "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD3XSdz1MnzazBEN5KOfTx0IyVJ\n" +
                        "Z5wb57isrCuHDhnYXwtmdhQalgII0fozeeFpMpAvlnmHC1kpW7XVGvZnLx3bWbCE\n" +
                        "bf+pMSW4kmQuI+5cxRUJbCl7sdaODBrINgERHPICVC18AJLThEVMHyjuR6Jn4zQm\n" +
                        "yYNbReSktY/BrFTvMQIDAQAB\n"
                //+"-----END PUBLIC KEY-----"
                ;

        // 私钥
        String priK = //"-----BEGIN PRIVATE KEY-----\n" +
                "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAPddJ3PUyfNrMEQ3\n" +
                        "ko59PHQjJUlnnBvnuKysK4cOGdhfC2Z2FBqWAgjR+jN54WkykC+WeYcLWSlbtdUa\n" +
                        "9mcvHdtZsIRt/6kxJbiSZC4j7lzFFQlsKXux1o4MGsg2AREc8gJULXwAktOERUwf\n" +
                        "KO5HomfjNCbJg1tF5KS1j8GsVO8xAgMBAAECgYEA6eG1JMrj63jEmStmMb1txG1a\n" +
                        "mu4Q5z2QGgtr2HVXsIIlGEq6tWxyHf7TL4qkuz9onuYKn8n2Eqm44fZtVaBx+5ES\n" +
                        "zRpIvlTvaxmVu0HZ1hYAzUw1XyRnXNMKpL5tT4GCjm8+QGPzlGxgXI1sNg8r9Jaw\n" +
                        "9zRUYeA6LQR9RIMkHWUCQQD8QojjVoGjtiunoh/N8iplhUszZIavAEvmDIE+kVy+\n" +
                        "pA7hvlukLw6JMc7cfTcnHyxDo9iHVIzrWlTuKRq9KWVLAkEA+wgJS2sgtldnCVn6\n" +
                        "tJKFVwsHrWhMIU29msPPbNuWUD23BcKE/vehIyFu1ahNA/TiM40PEnzprQ5JfPxU\n" +
                        "16S78wJANTfMLTnYy7Lo7sqTLx2BuD0wqjzw9QZ4/KVytsJv8IAn65P/PVn4FRV+\n" +
                        "8KEx+3zmF7b/PT2nJRe/hycAzxtmlQJBAMrFwQxEqpXfoAEzx4lY2ZBn/nmaR/SW\n" +
                        "4VNEXCbocVC7qT1j1R5HVMgV13uKiTtq8dUGWmhqsi7x3XayNK5ECPUCQQDZaAN6\n" +
                        "tvIHApz9OLsXSw0jZirQ6KEYdharXbIVDy1W1sVE3lzLbqLdFp1bxAHQIvsYS5PM\n" +
                        "A9veSJh372RLJKkj\n"
                //+"-----END PRIVATE KEY-----"
                ;
        // 明文
        String src = "好厉害";
        src =
                "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiMTU2MjEzNTc1MDEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ4MDY5NjUyNDQ4NDY3NyIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0";


        //私钥签名
        String c = null;
        try {
            c = SHA256withRSAUtil.sign(src, SHA256withRSAUtil.getPrivateKey(priK.replace("\n","")));
            System.out.println(c);

            //公钥验签(true表示验证通过,false表示验证失败)
            System.out.println("验证结果:" + SHA256withRSAUtil.verify(src, c, SHA256withRSAUtil.getPublicKey(pk.replace("\n",""))));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

在这里插入图片描述

可以看到java加签和C#、js加签结果一样,所以验签也是通过的

参考

rsa js和java互通
C# rsa加签验签

;