C# RSA和公钥与dotnet的互操作

C# RSA和公钥与dotnet的互操作,c#,java,digital-signature,bouncycastle,C#,Java,Digital Signature,Bouncycastle,您好,我使用的代码来自,您能让我知道为什么签名验证不起作用吗 Java signer正在将BouncyCastleProvider与SHA1withRSA一起使用,下面是dotnet验证代码 using System; using System.IO; using System.Collections.Generic; using System.Linq; using System.Text; using System.Security.Cryptography; using System.Se

您好,我使用的代码来自,您能让我知道为什么签名验证不起作用吗

Java signer正在将BouncyCastleProvider与SHA1withRSA一起使用,下面是dotnet验证代码

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string pubkey = @"MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMf54mcK3EYJn9tT9BhRoTX+8AkqojIyeSfog9ncYEye0VXyBULGg2lAQsDRt8lZsvPioORZW7eB6IKawshoWUsCAwEAAQ==";
            String signature = "770bb2610bf6b2602ce2b3ad8489054f4ed59c9b0c9299327f76ecbc60a8bb9a725cfae901fc189d4bafcf73a2f4aed8dffe9842f7b6196ddfcd040c7271c7ca";
            String signData = "C2:AE:D6:2B:DF:A4";
            byte[] expectedSig = System.Convert.FromBase64String(signature);
            byte[] baKey = System.Convert.FromBase64String(pubkey);

            byte[] data = Encoding.UTF8.GetBytes(signData);

            //Console.WriteLine(p.VerifyData(data, new SHA1CryptoServiceProvider(), expectedSig));

            /* Init alg */
            ISigner signer = SignerUtilities.GetSigner("SHA1withRSA");
            /* Populate key */
            signer.Init(false, DecodeX509PublicKey2(baKey));
            /* Calculate the signature and see if it matches */
            signer.BlockUpdate(data, 0, data.Length);

            Console.WriteLine(signer.VerifySignature(expectedSig));
            Console.In.ReadLine();
        }

        public static RsaKeyParameters DecodeX509PublicKey2(byte[] x509key)
        {
            byte[] SeqOID = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };

            MemoryStream ms = new MemoryStream(x509key);
            BinaryReader reader = new BinaryReader(ms);

            if (reader.ReadByte() == 0x30)
                ReadASNLength(reader); //skip the size
            else
                return null;

            int identifierSize = 0; //total length of Object Identifier section
            if (reader.ReadByte() == 0x30)
                identifierSize = ReadASNLength(reader);
            else
                return null;

            if (reader.ReadByte() == 0x06) //is the next element an object identifier?
            {
                int oidLength = ReadASNLength(reader);
                byte[] oidBytes = new byte[oidLength];
                reader.Read(oidBytes, 0, oidBytes.Length);
                if (oidBytes.SequenceEqual(SeqOID) == false) //is the object identifier rsaEncryption PKCS#1?
                    return null;

                int remainingBytes = identifierSize - 2 - oidBytes.Length;
                reader.ReadBytes(remainingBytes);
            }

            if (reader.ReadByte() == 0x03) //is the next element a bit string?
            {
                ReadASNLength(reader); //skip the size
                reader.ReadByte(); //skip unused bits indicator
                if (reader.ReadByte() == 0x30)
                {
                    ReadASNLength(reader); //skip the size
                    if (reader.ReadByte() == 0x02) //is it an integer?
                    {
                        int modulusSize = ReadASNLength(reader);
                        byte[] modulus = new byte[modulusSize];
                        reader.Read(modulus, 0, modulus.Length);
                        if (modulus[0] == 0x00) //strip off the first byte if it's 0
                        {
                            byte[] tempModulus = new byte[modulus.Length - 1];
                            Array.Copy(modulus, 1, tempModulus, 0, modulus.Length - 1);
                            modulus = tempModulus;
                        }
                        Array.Reverse(modulus); //convert to big-endian

                        if (reader.ReadByte() == 0x02) //is it an integer?
                        {
                            int exponentSize = ReadASNLength(reader);
                            byte[] exponent = new byte[exponentSize];
                            reader.Read(exponent, 0, exponent.Length);
                            Array.Reverse(exponent); //convert to big-endian

                            //RSAParameters RSAKeyInfo = new RSAParameters();
                            //RSAKeyInfo.Modulus = modulus;
                            //RSAKeyInfo.Exponent = exponent;

                            return MakeKey(BitConverter.ToString(modulus).Replace("-", string.Empty), BitConverter.ToString(exponent).Replace("-", string.Empty), false);
                        }
                    }
                }
            }
            return null;
        }

        public static RsaKeyParameters MakeKey(String modulusHexString, String exponentHexString, bool isPrivateKey)
        {
            var modulus = new Org.BouncyCastle.Math.BigInteger(modulusHexString, 16);
            var exponent = new Org.BouncyCastle.Math.BigInteger(exponentHexString, 16);

            return new RsaKeyParameters(isPrivateKey, modulus, exponent);
        }

        public static RSACryptoServiceProvider DecodeX509PublicKey(byte[] x509key)
        {
            byte[] SeqOID = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };

            MemoryStream ms = new MemoryStream(x509key);
            BinaryReader reader = new BinaryReader(ms);

            if (reader.ReadByte() == 0x30)
                ReadASNLength(reader); //skip the size
            else
                return null;

            int identifierSize = 0; //total length of Object Identifier section
            if (reader.ReadByte() == 0x30)
                identifierSize = ReadASNLength(reader);
            else
                return null;

            if (reader.ReadByte() == 0x06) //is the next element an object identifier?
            {
                int oidLength = ReadASNLength(reader);
                byte[] oidBytes = new byte[oidLength];
                reader.Read(oidBytes, 0, oidBytes.Length);
                if (oidBytes.SequenceEqual(SeqOID) == false) //is the object identifier rsaEncryption PKCS#1?
                    return null;

                int remainingBytes = identifierSize - 2 - oidBytes.Length;
                reader.ReadBytes(remainingBytes);
            }

            if (reader.ReadByte() == 0x03) //is the next element a bit string?
            {
                ReadASNLength(reader); //skip the size
                reader.ReadByte(); //skip unused bits indicator
                if (reader.ReadByte() == 0x30)
                {
                    ReadASNLength(reader); //skip the size
                    if (reader.ReadByte() == 0x02) //is it an integer?
                    {
                        int modulusSize = ReadASNLength(reader);
                        byte[] modulus = new byte[modulusSize];
                        reader.Read(modulus, 0, modulus.Length);
                        if (modulus[0] == 0x00) //strip off the first byte if it's 0
                        {
                            byte[] tempModulus = new byte[modulus.Length - 1];
                            Array.Copy(modulus, 1, tempModulus, 0, modulus.Length - 1);
                            modulus = tempModulus;
                        }
                        Array.Reverse(modulus); //convert to big-endian

                        if (reader.ReadByte() == 0x02) //is it an integer?
                        {
                            int exponentSize = ReadASNLength(reader);
                            byte[] exponent = new byte[exponentSize];
                            reader.Read(exponent, 0, exponent.Length);
                            Array.Reverse(exponent); //convert to big-endian

                            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
                            RSAParameters RSAKeyInfo = new RSAParameters();
                            RSAKeyInfo.Modulus = modulus;
                            RSAKeyInfo.Exponent = exponent;
                            RSA.ImportParameters(RSAKeyInfo);
                            return RSA;
                        }
                    }
                }
            }
            return null;
        }

        public static int ReadASNLength(BinaryReader reader)
        {
            //Note: this method only reads lengths up to 4 bytes long as
            //this is satisfactory for the majority of situations.
            int length = reader.ReadByte();
            if ((length & 0x00000080) == 0x00000080) //is the length greater than 1 byte
            {
                int count = length & 0x0000000f;
                byte[] lengthBytes = new byte[4];
                reader.Read(lengthBytes, 4 - count, count);
                Array.Reverse(lengthBytes); //
                length = BitConverter.ToInt32(lengthBytes, 0);
            }
            return length;
        }
    }
}
用于签名数据的Java代码:

private static final java.security.Signature signer;
static final String transformation = "RSA/ECB/PKCS1Padding";
static {
    try {
        signer = java.security.Signature.getInstance("SHA1withRSA");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
}

static String sign(String clearText) {
    String signed = null;
    try {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        byte[] data = clearText.getBytes("UTF-8");
        signer.initSign(getPrivateKey());
        signer.update(data);
        byte[] digitalSignature = signer.sign();
        //--toHex
        signed = org.apache.commons.codec.binary.Hex.encodeHexString(digitalSignature);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return signed;
}

KeyPair generateKeyPair() {
    KeyPair kp = null;
    // Generate a key-pair
    KeyPairGenerator kpg;
    SecureRandom secureRandom;
    try {
        kpg = KeyPairGenerator.getInstance("RSA");
        secureRandom = SecureRandom.getInstance("SHA1PRNG", "SUN");
        secureRandom.setSeed(secureRandomSeed);
        kpg.initialize(512, secureRandom);
        kp = kpg.generateKeyPair();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return kp;
}
下面是C#中用于签名和验证的代码:

static void test3()
{
    AsymmetricCipherKeyPair keys = generateNewKeys();
    /* Init alg */
    ISigner sig = SignerUtilities.GetSigner("SHA1withRSA");

    /* Populate key */
    sig.Init(true, keys.Private);

    /* Get the bytes to be signed from the string */
    var bytes = Encoding.UTF8.GetBytes(signData);

    /* Calc the signature */
    sig.BlockUpdate(bytes, 0, bytes.Length);
    byte[] signature = sig.GenerateSignature();

    /* Base 64 encode the sig so its 8-bit clean */
    var signedString = Convert.ToBase64String(signature);
    Console.WriteLine(signedString);

    string expectedSignature = signedString;
    /* Init alg */
    ISigner signer = SignerUtilities.GetSigner("SHA1withRSA");

    /* Populate key */
    signer.Init(false, keys.Public);

    /* Get the signature into bytes */
    var expectedSig = Convert.FromBase64String(expectedSignature);

    /* Get the bytes to be signed from the string */
    var msgBytes = Encoding.UTF8.GetBytes(signData);

    /* Calculate the signature and see if it matches */
    signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
    /*Verify*/
    bool result= signer.VerifySignature(expectedSig);
    Console.WriteLine(result);
}

这里有几个问题

String signature = "770bb ... 1c7ca";
...
byte[] expectedSig = System.Convert.FromBase64String(signature);
您正在对签名进行Base64解码,但它不是Base64编码的,而是十六进制编码的

第二个问题是
DecodeX509PublicKey
方法(这是我的错误,因为我在中提供了此代码)。具体问题行如下

Array.Reverse(modulus); //convert to big-endian


我反复读到ASN.1和.NETAPI对它们的键使用了相反的Endience,因此我的印象是需要颠倒Endience来解释这一点。(我确实应该做一个测试,比如你的签名验证,而不是仅仅查看内存中的键值>这里有几个问题

String signature = "770bb ... 1c7ca";
...
byte[] expectedSig = System.Convert.FromBase64String(signature);
您正在对签名进行Base64解码,但它不是Base64编码的,而是十六进制编码的

第二个问题是
DecodeX509PublicKey
方法(这是我的错误,因为我在中提供了此代码)。具体问题行如下

Array.Reverse(modulus); //convert to big-endian


我反复读到ASN.1和.Net API对它们的密钥使用相反的Endience,因此我的印象是需要反转Endience来解释这一点。(我确实应该做一个测试,比如签名验证,而不是只查看内存中的键值>。你能解释一下吗“signature is verify”是?签名是由java使用与RSA相同的算法生成的,带有提供程序BouncyCastleProvider。verify是使用“signData”来验证预期的签名。您可以发布用于生成签名的java代码以及任何相关的测试数据吗?(因此我们有一些东西要测试。)我添加了生成签名数据的java代码。看起来C需要不对称密码密钥对??你能解释一下什么是“签名”吗“is?签名是由java使用与RSA相同的算法SHA1和提供程序BouncyCastleProvider生成的。Verify使用“signData”来验证预期的签名。您能否发布用于生成签名的java代码以及任何相关的测试数据?(因此,我们有一些东西要测试。)我添加了生成签名数据的java代码。看起来C需要不对称密码密钥对??
static {
    try {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

...

String signed = null;
try {
    java.security.Signature signer = java.security.Signature.getInstance("SHA1withRSA", "BC");
    byte[] data = clearText.getBytes("UTF-8");
    signer.initSign(getPrivateKey());

...