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

news2024/11/24 12:21:41

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加签验签

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1826847.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java——变量作用域和生命周期

一、作用域 1、作用域简介 在Java中&#xff0c;作用域&#xff08;Scope&#xff09;指的是变量、方法和类在代码中的可见性和生命周期。理解作用域有助于编写更清晰、更高效的代码。 2、作用域 块作用域&#xff08;Block Scope&#xff09;&#xff1a; 块作用域是指在…

SQLserver前五讲课堂笔记

第一讲 基本内容 为什么要学习数据库系统?什么是数据库?什么是数据库系统?什么是数据库管理系统&#xff1f;本课程学什么以及学到什么程度? 重点难点 一组概念的区分&#xff1a;数据库、数据库系统和数据库管理系统熟悉表 的相关要素及术语熟悉数据库系统的构成(工作…

Springboot项目ES报异常query_shard_exception

详细异常信息如下&#xff1a; {"error": {"root_cause": [{"type": "query_shard_exception","reason": "failed to create query: {\n \"bool\" : {\n \"filter\" : [\n {\n \…

【docker hub镜像源失效】2024年6月6日 docker 国内镜像源失效

文章目录 概述中科大镜像源阿里镜像源其他镜像源可用的镜像源写在最后 之前违反社区规定了&#xff0c;做了和谐 概述 大家都知道使用docker hub官方镜像需要魔法&#xff0c;虽然大部人有魔法&#xff0c;但是网速也是很慢&#xff0c;还有部分同学没有&#xff0c;全靠国内各…

Linux-Https协议

文章目录 前言一、Https协议二、常见的加密方式对称加密非对称加密数据摘要&&数据指纹中间人攻击 三、Https的加密历程方案1-只使用对称加密方案2-只使用非对称加密方案3-双方都使用非对称加密方案4-非对称加密对称加密 前言 之前我们学习了Http协议&#xff0c;也试着…

Bug:SSH Failed Permission Denied(完美解决)

Bug&#xff1a;SSH Failed Permission Denied&#xff08;完美解决&#xff09; 今天我本机mac通过ssh访问linux服务器时报错&#xff1a;SSH Failed Permission Denied 思路&#xff1a; linux服务器sshd是否开启linux /etc/ssh/sshd_config配置是否正确&#xff08;是否开启…

YouTube583美元账户做到一千多万美元,125万粉的顶级交易员

油管125万粉丝的Ross Cameron,一位把583美元账户做到一千多万美元。他说他曾经也是像无头苍蝇一样交易,最终凄惨爆仓,也就是在爆仓之后,他终于开始沉下心来研究交易策略,终于终于,他有一天找到了交易模型,并用它执行至今。 Ross Cameron无疑是最成功的日内交易员之一,而…

Asp.Net Core 读取配置接口 IOptions、IOptionsMonitor以及IOptionsSnapshot

&#x1f340;简介 Options是.net Core Web api框架自带的功能&#xff0c;Options模式通过定义强类型的类来表示相关配置设置的集合&#xff0c;使得配置管理更为结构化和类型安全。 IOptions、IOptionsMonitor和IOptionsSnapshot是用于处理配置的依赖注入接口。这些接口允许…

Linux基础 (十八):Libevent 库的安装与使用

目录 一、Libevent 概述 1.0 Libevent的安装 1.0.1 使用源码方式 1.0.2 终端命令行安装 1.1 主要特性 1.2 主要组件 1.3 Libevent 使用模型 1.4 原理 1.5 使用的基本步骤 1.5.1 初始化事件基础设施 1.5.2. 创建和绑定服务器套接字 1.5.3. 设置监听事件 1.5.4. 定义…

电脑缺失d3dcompiler_47.dll会怎么样,该如何修复呢

在计算机使用过程中&#xff0c;我们常常会遇到一些错误提示&#xff0c;其中之一就是“缺少d3dcompiler47.dll文件”。那么&#xff0c;d3dcompiler47.dll到底是什么&#xff1f;为什么计算机会缺失它&#xff1f;它会对电脑产生什么具体影响&#xff1f;如何解决这个问题&…

【CT】LeetCode手撕—25. K 个一组翻转链表

目录 题目1-思路2- 实现⭐25. K 个一组翻转链表——题解思路 3- ACM实现 题目 原题连接&#xff1a;25. K 个一组翻转链表 1-思路 1. dummyHead&#xff1a;设置虚拟头结点&#xff0c;通过虚拟头结点保证每个结点的地位相同2. 定位 pre 和 end 拆链&#xff1a;借助 pre 、s…

(新)Spring Security如何实现登录认证(实战篇)

一、回顾认证流程详解 概念速查: Authentication接口: 它的实现类&#xff0c;表示当前访问系统的用户&#xff0c;封装了用户相关信息。 AuthenticationManager接口&#xff1a;定义了认证Authentication的方法 UserDetailsService接口&#xff1a;加载用户特定数据的核心接…

软件体系结构笔记(自用)

来自《软件体系结构原理、方法与实践&#xff08;第三版&#xff09;》清华大学出版社 张友生编著 1-8章12章 复习笔记 如有错误&#xff0c;欢迎指正&#xff01;&#xff01;&#xff01;

Python使用策略模式生成TCP数据包

使用策略模式&#xff08;Strategy Pattern&#xff09;来灵活地生成不同类型的TCP数据包。 包括三次握手、数据传输和四次挥手。 from scapy.all import * from scapy.all import Ether, IP, TCP, UDP, wrpcap from abc import ABC, abstractmethodclass TcpPacketStrategy(A…

网络安全技术实验六 入侵检测技术实践

一、实验目的和要求 理解基于网络的入侵检测系统的基本原理&#xff0c;掌握snort IDS工作机理&#xff1b; 学习应用snort三种方式工作&#xff1b;熟练编写snort规则&#xff1b; 完成snort数据包记录、日志查看、字符串匹配、ARP欺骗攻击检测、端口扫描工具检测等功能。 …

微信小游戏插件申请,微信小程序插件管理

微信小游戏的插件申请与小程序不一样&#xff0c;官方没有提供一个统一的管理入口进行申请插件&#xff0c;以及查看插件&#xff0c;没有小程序方便的&#xff1b; 小程序申请查看插件入口如下图所示&#xff1a; 小游戏的插件可以通过以下的方式进行申请&#xff1a; 如下…

代码随想录-Day31

455. 分发饼干 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 i&#xff0c;都有一个胃口值 g[i]&#xff0c;这是能让孩子们满足胃口的饼干的最小尺寸&#xff1b;并且每块饼干 j&#xff0c;都…

OpenCV形态学

什么事形态学处理 基于图像形态进行处理的一些基本方法&#xff1b; 这些处理方法基本是对二进制图像进行处理&#xff1b; 卷积核决定着图像出来后的效果。 一 图像二值化 什么是二值化 将图像的每个像素变成两种值&#xff0c;如0,255. 全局二值化。 局部二值化。 thres…

小学奥数-图像找规律之招聘测评题

文章目录 长得差不多平移&#xff08;1&#xff09;&#xff08;2&#xff09; 旋转规律&#xff08;1&#xff09; 翻转规律 长得有点不一样叠加 参考 比如腾讯给他投简历之后会发一个在线测评&#xff0c;这些题目有和公务员考试很像的 长得差不多 几张图长得差不多的时候&a…

TCP/IP协议深入解析,初学者必看!

简介 在信息技术飞速发展的今天&#xff0c;网络已成为人类社会不可或缺的部分。实现网络中计算机相互通信的关键之一便是TCP/IP协议。作为互联网的基础&#xff0c;TCP/IP协议确保了全球范围内的数据交换和信息共享。 TCP/IP&#xff08;传输控制协议/网际协议&#xff09;是…