使用 C#、BouncyCastle 和导入的 RSA 密钥进行 RSA 签名和验证 - 内部工作 Python 示例和非工作 C# 代码示例

2024-06-20

我一直在绞尽脑汁试图获得一个使用 C# 和 BouncyCastle 进行 RSA 数据签名和验证的简单示例。

在适用于我的 Python 和 M2Crypto 的示例中,RSACryptoServiceProvider.VerifyHash() 始终返回 false。

我已经验证工作示例和 C# 示例之间的哈希签名是相同的,但我被困住了。我觉得我遗漏了一些重要的细节。

接下来是工作的 Python 代码和非工作的 C# 代码。

密钥是用以下命令生成的

openssl genrsa -out testkey.pem 1024
openssl rsa -in testkey.pem -pubout > testkey.pub

Python 代码(工作):

    private = """-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCxSHbp1ID/XHEdzVzgqYR1F/79PeMbqzuKNZChvt1gFObBhKyB
pgaHDHw3UZrO8s/hBEE/Mpe2Lh90ZAFdPIXq+HyVoznXMoJYBv0uLDApvSQbJNOd
f7T5VwmpBbkfj1NAlm39Eun9uBSokEOnB24g+bczPQPGOASrQ2Ly9afOZQIDAQAB
AoGBAIEzQIZ1OnXgVwfTLMcGg+QaUtkYizUU+9Vj6D4YrZliYjHSkS4DY2p0rOpb
7Ki5yMpCoZJ/OpWo03+tilj6zNUU6X3aHrPPSv8jcsE0sDi9zYJr/Ztk3EG23sad
bM28Bb4fV/Z0/E6FZJrmuvI2dZP/57oQSHGOhtkHFO21cW5BAkEA3l/i5Rc34YXc
WHYEsOYe0kAxS4dCmhbLWaWvsghW/TomjdxzePsO70GZZqRMdzkfA1iS1OrK+pP4
4suL2rSLrQJBAMwXFnBp4Jmek0CTSxoYf6q91eFm/IRkGLnzE1fEZ76vQOBTas8T
/mpjNQHSEywo/QB62h9A8hy7XNrfZJAMJJkCQA5TYwybKFBxDTbts3Op/4ZP+F0D
Q7klisglsmHnw6Lgoic1coLyuY2UTkucfgiYN3VBuYPZ9GWcLsZ9km7ufqkCQQCz
NVa70Qyqd+cfXfcla/u2pskHCtKTQf3AUmRavhjHBMa39CemvAy7yG9EMP4q2bcH
U9jydqnidtdbTavVHQSJAkA0zJtLzHGPtQqQaI7K6kBDXYPqloGnQxHxad0HPx2e
Vj2qv1tEsqeG6HC7aL/afXOtxcfjq4oMHbGUjDv+dGfP
-----END RSA PRIVATE KEY-----"""

public = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxSHbp1ID/XHEdzVzgqYR1F/79
PeMbqzuKNZChvt1gFObBhKyBpgaHDHw3UZrO8s/hBEE/Mpe2Lh90ZAFdPIXq+HyV
oznXMoJYBv0uLDApvSQbJNOdf7T5VwmpBbkfj1NAlm39Eun9uBSokEOnB24g+bcz
PQPGOASrQ2Ly9afOZQIDAQAB
-----END PUBLIC KEY-----"""

message = "test input string"

import base64

# Use EVP api to sign message
from M2Crypto import EVP
key = EVP.load_key_string(private)
key.reset_context(md='sha1')
key.sign_init()
key.sign_update(message)
signature = key.sign_final()

encoded = base64.b64encode(signature)
print encoded

with open("python_sig2.txt","w") as f:
    f.write(encoded)

# Use EVP api to verify signature
from M2Crypto import BIO, RSA, EVP
bio = BIO.MemoryBuffer(public)
rsa = RSA.load_pub_key_bio(bio)
pubkey = EVP.PKey()
pubkey.assign_rsa(rsa)
pubkey.reset_context(md="sha1")
pubkey.verify_init()
pubkey.verify_update(message)
decoded = base64.b64decode(encoded)
print pubkey.verify_final(decoded) == 1

C# 代码(verifyhash() 返回 false):

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;


namespace RsaSignTest
{
    class Program
    {
        private const string privateKey =
            @"-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCxSHbp1ID/XHEdzVzgqYR1F/79PeMbqzuKNZChvt1gFObBhKyB
pgaHDHw3UZrO8s/hBEE/Mpe2Lh90ZAFdPIXq+HyVoznXMoJYBv0uLDApvSQbJNOd
f7T5VwmpBbkfj1NAlm39Eun9uBSokEOnB24g+bczPQPGOASrQ2Ly9afOZQIDAQAB
AoGBAIEzQIZ1OnXgVwfTLMcGg+QaUtkYizUU+9Vj6D4YrZliYjHSkS4DY2p0rOpb
7Ki5yMpCoZJ/OpWo03+tilj6zNUU6X3aHrPPSv8jcsE0sDi9zYJr/Ztk3EG23sad
bM28Bb4fV/Z0/E6FZJrmuvI2dZP/57oQSHGOhtkHFO21cW5BAkEA3l/i5Rc34YXc
WHYEsOYe0kAxS4dCmhbLWaWvsghW/TomjdxzePsO70GZZqRMdzkfA1iS1OrK+pP4
4suL2rSLrQJBAMwXFnBp4Jmek0CTSxoYf6q91eFm/IRkGLnzE1fEZ76vQOBTas8T
/mpjNQHSEywo/QB62h9A8hy7XNrfZJAMJJkCQA5TYwybKFBxDTbts3Op/4ZP+F0D
Q7klisglsmHnw6Lgoic1coLyuY2UTkucfgiYN3VBuYPZ9GWcLsZ9km7ufqkCQQCz
NVa70Qyqd+cfXfcla/u2pskHCtKTQf3AUmRavhjHBMa39CemvAy7yG9EMP4q2bcH
U9jydqnidtdbTavVHQSJAkA0zJtLzHGPtQqQaI7K6kBDXYPqloGnQxHxad0HPx2e
Vj2qv1tEsqeG6HC7aL/afXOtxcfjq4oMHbGUjDv+dGfP
-----END RSA PRIVATE KEY-----";

        private const string publicKey =
            @"-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxSHbp1ID/XHEdzVzgqYR1F/79
PeMbqzuKNZChvt1gFObBhKyBpgaHDHw3UZrO8s/hBEE/Mpe2Lh90ZAFdPIXq+HyV
oznXMoJYBv0uLDApvSQbJNOdf7T5VwmpBbkfj1NAlm39Eun9uBSokEOnB24g+bcz
PQPGOASrQ2Ly9afOZQIDAQAB
-----END PUBLIC KEY-----";

        static void Main(string[] args)
        {
            var data = "test input string";
            var sig = SignWithPrivateKey(data);
            var valid = VerifyWithPublicKey(data,sig);
        }

        private static byte[] SignWithPrivateKey(string data)
        {
            RSACryptoServiceProvider rsa;

            using (var keyreader = new StringReader(privateKey))
            {
                var pemreader = new PemReader(keyreader);
                var y = (AsymmetricCipherKeyPair) pemreader.ReadObject();
                var rsaPrivKey = (RsaPrivateCrtKeyParameters)y.Private;
                rsa = (RSACryptoServiceProvider)RSACryptoServiceProvider.Create();
                var rsaParameters = DotNetUtilities.ToRSAParameters(rsaPrivKey);
                rsa.ImportParameters(rsaParameters);

            }

            // compute sha1 hash of the data
            var sha = new SHA1CryptoServiceProvider();
            byte[] hash = sha.ComputeHash(Encoding.ASCII.GetBytes(data));

            // actually compute the signature of the SHA1 hash of the data
            var sig = rsa.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"));

            // base64 encode the signature and write to compare to the python version
            String b64signature = Convert.ToBase64String(sig);
            using (var sigwriter = new StreamWriter(@"C:\scratch\csharp_sig2.txt"))
            {
                sigwriter.Write(b64signature);
            }

            return sig;
        }

        private static bool VerifyWithPublicKey(string data,byte[] sig)
        {
            RSACryptoServiceProvider rsa;

            using (var keyreader = new StringReader(publicKey))
            {
                var pemReader = new PemReader(keyreader);
                var y = (RsaKeyParameters) pemReader.ReadObject();
                rsa = (RSACryptoServiceProvider) RSACryptoServiceProvider.Create();
                var rsaParameters = new RSAParameters();
                rsaParameters.Modulus = y.Modulus.ToByteArray();
                rsaParameters.Exponent = y.Exponent.ToByteArray();
                rsa.ImportParameters(rsaParameters);
            }

            // compute sha1 hash of the data
            var sha = new SHA1CryptoServiceProvider();
            byte[] hash = sha.ComputeHash(Encoding.ASCII.GetBytes(data));

            // This always returns false
            return rsa.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"),sig);
        }
    }
}

此时我不知道如何继续,任何帮助将不胜感激。


您重建私钥/公钥的方式出了问题。显然在 python 中你需要这样做。

我创建了使用以下代码进行验证(以不同格式)的新密钥:

private static void GenerateKeys(out string forPubKey, out string forPrivKey)
        {
            GenerateKeys(out forPubKey, out forPrivKey, 2048, 65537, 80);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="forPubKey"></param>
        /// <param name="forPrivKey"></param>
        /// <param name="keyStrength">1024, 2048,4096</param>
        /// <param name="exponent">Typically a fermat number 3, 5, 17, 257, 65537, 4294967297, 18446744073709551617,</param>
        /// <param name="certaninty">Should be 80 or higher depending on Key strength number (exponent)</param>
        private static void GenerateKeys(out string forPubKey, out string forPrivKey, int keyStrength, int exponent, int certaninty)
        {
            // Create key
            RsaKeyPairGenerator generator = new RsaKeyPairGenerator();

            /*
             * This value should be a Fermat number. 0x10001 (F4) is current recommended value. 3 (F1) is known to be safe also.
             * 3, 5, 17, 257, 65537, 4294967297, 18446744073709551617,
             * 
             * Practically speaking, Windows does not tolerate public exponents which do not fit in a 32-bit unsigned integer. Using e=3 or e=65537 works "everywhere". 
             */
            BigInteger exponentBigInt = new BigInteger(exponent.ToString());

            var param = new RsaKeyGenerationParameters(
                exponentBigInt, // new BigInteger("10001", 16)  publicExponent
                new SecureRandom(),  // SecureRandom.getInstance("SHA1PRNG"),//prng
                keyStrength, //strength
                certaninty);//certainty
            generator.Init(param);
            AsymmetricCipherKeyPair keyPair = generator.GenerateKeyPair();

            // Save to export format
            SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public);
            byte[] ret = info.GetEncoded();
            forPubKey = Convert.ToBase64String(ret);

            //  EncryptedPrivateKeyInfo asdf = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
            //    DerObjectIdentifier.Ber,,,keyPair.Private);

            //// demonstration: how to serialise option 1
            //TextWriter textWriter = new StringWriter();
            //PemWriter pemWriter = new PemWriter(textWriter);
            //pemWriter.WriteObject(keyPair);
            //pemWriter.Writer.Flush();
            //string ret2 = textWriter.ToString();

            //// demonstration: how to serialise option 1
            //TextReader tr = new StringReader(ret2);
            //PemReader read = new PemReader(tr);
            //AsymmetricCipherKeyPair something = (AsymmetricCipherKeyPair)read.ReadObject();

            //// demonstration: how to serialise option 2 (don't know how to deserailize)
            //PrivateKeyInfo pKinfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);
            //byte[] privRet = pKinfo.GetEncoded();
            //string forPrivKey2Test = Convert.ToBase64String(privRet);



            PrivateKeyInfo pKinfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);
            byte[] privRet = pKinfo.GetEncoded();
            string forPrivKey2Test = Convert.ToBase64String(privRet);

            forPrivKey = forPrivKey2Test;
        }

然后将它们转回 RSA 对象,如下所示:

  // Private key
  RsaPrivateCrtKeyParameters kparam = ConvertToRSAPrivateKey(privateKey); 
        RSAParameters p1 = DotNetUtilities.ToRSAParameters(kparam);
        rsa = new RSACryptoServiceProvider();
        rsa.ImportParameters(p1);

 // Public key
 RsaKeyParameters kparam = ConvertToRSAPublicKey(publicKey);
        RSAParameters p1 = DotNetUtilities.ToRSAParameters(kparam);
        rsa = new RSACryptoServiceProvider();
        rsa.ImportParameters(p1);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 C#、BouncyCastle 和导入的 RSA 密钥进行 RSA 签名和验证 - 内部工作 Python 示例和非工作 C# 代码示例 的相关文章

随机推荐

  • 使用外部存储,删除文件夹时出错

    我正在使用 docker nextcloud 我创建了一个干净的实例 我想使用应用程序外部存储 我设法使用以下命令成功配置本地存储 mount id docker exec user 1000 nextcloud php occ files
  • SQLite中的ROWID是自动设置的吗?

    所以 我在 Ionic 上有这个应用程序 它使用SQLite ngCordova 插件 https github com litehelpers Cordova sqlite storage用于内部存储 在其上 我使用以下命令创建一个表 d
  • 更改 django 中的项目名称

    我将 django 项目的名称从oldname to newname使用 Pycharm 的重构 gt 重命名 我翻遍了这个项目 似乎到处都改了名字 但是当我尝试 runserver 时 这就是我得到的 Traceback most rec
  • 如何测试 httpOnly cookie 标志

    我在 websphere 中为 jsessionid cookie 设置了以下属性com ibm ws webcontainer HTTPOnlyCookies 知道如何在 Firefox 或 IE 中使用 JavaScript 进行最佳测
  • 伊德里斯统一意外失败

    我正在尝试在 Idris 中创建一个所谓的可判定解析器 起初我只是想解析自然数 但遇到了一个意想不到的问题 生成它的代码的最小示例如下 data Digit Char gt Type where Zero Digit 0 One Digit
  • 游戏如何制作火焰和烟雾效果? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我在互联网上搜索了有关粒子系统和火焰
  • 生成大随机数 php [重复]

    这个问题在这里已经有答案了 我想使用 PHP 生成一个包含 75 个字符的数字 我到处寻找 但一无所获 除了这个 http dailycoding com tools RandomNumber aspx http dailycoding c
  • 如何记录函数可能抛出的所有异常?

    如果您有一个可能引发异常的公共函数 该函数使用其他 私有或公共 辅助函数也可能引发异常 我认为您应该记录公共函数可以引发哪些异常这包括辅助函数抛出的异常 像这样 使用 Doxygen throw Exception throw Except
  • 设置asp.net验证器的顺序

    我使用 3 个验证器来验证文本框 但当在文本框中输入无效值时 所有验证器都会被触发 但我希望这些验证器按照特定的顺序工作 以便用户可以一一解决这些错误
  • 暂时禁用提交按钮

    我有一个将大文件上传到服务器的表单 像这样的事情
  • Flask-Admin 具有多对多关系中的附加字段

    我有两个表 产品 成分 和 产品成分 class ProductIngredient db Model tablename product ingredient id db Column db Integer primary key Tru
  • 如何检测Mysql/innodb中的死锁?

    我知道在 Innodb 中使用事务时不可避免地会发生死锁 并且如果应用程序代码正确处理死锁 它们是无害的 正如手册所说 只需再试一次 所以我想知道 如何检测死锁 死锁是否会发出一些特殊的 mysql 错误号 如果重要的话 我正在使用 PHP
  • PyCharm 中有 HTML 块 {%%} 的快捷方式吗?

    我正在使用 HTML 块 例如 block content 经常使用 但必须输入括号和百分比符号很麻烦 有没有捷径或其他方法可以自动执行此操作 到目前为止我刚刚发现这个 PyCharm 中有插入 的快捷方式吗 https stackover
  • rake db:migrate db:reset 和 db:schema:load 之间的区别

    和 之间的不同rake db migrate and rake db reset我很清楚 我不明白的是如何rake db schema load与前两者不同 只是为了确保我在同一页面上 rake db migrate 运行尚未运行的迁移 r
  • Android:如何在播放媒体(mp3)时在特定毫秒内显示文本

    我正在尝试做一个类似卡拉 OK 的应用程序 我想在某一毫秒到来时显示一个或多个单词 例如 1148 毫秒 gt 打印 尼古拉斯 1826 毫秒 gt 打印 是 2766 毫秒 gt 打印 旧 ms gt 显示 这是我的代码 包 com ex
  • 强化文件中的跨站脚本

    我在控制器中有以下代码 参数 base64String fileName 是从浏览器发送的 var fileContent Convert FromBase64String base64String return File fileCont
  • 没有名为flask.ext.wtf.SelectField的模块

    I found Flask jquery ajax 示例 https github com saltycrane flask jquery ajax example我尝试使用最新的库版本运行它 pip install flask flask
  • 如果 Redis 已经是堆栈的一部分,为什么 Memcached 仍然与 Redis 一起使用?

    Redis 可以执行 Memcached 提供的所有操作 LRU 缓存 项目过期以及现在版本 3 x 中的集群 目前处于测试阶段 或通过 twemproxy 等工具执行 性能也类似 此外 Redis 增加了持久性 因此您无需在服务器重新启动
  • 提高第一个查询的性能

    如果执行以下数据库 postgres 查询 则第二次调用要快得多 我猜第一个查询很慢 因为操作系统 linux 需要从磁盘获取数据 第二个查询受益于文件系统级别和 postgres 中的缓存 有没有一种方法可以优化数据库以快速获得结果fir
  • 使用 C#、BouncyCastle 和导入的 RSA 密钥进行 RSA 签名和验证 - 内部工作 Python 示例和非工作 C# 代码示例

    我一直在绞尽脑汁试图获得一个使用 C 和 BouncyCastle 进行 RSA 数据签名和验证的简单示例 在适用于我的 Python 和 M2Crypto 的示例中 RSACryptoServiceProvider VerifyHash