首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >验证使用RSA 2048位密钥、SHA256算法和PKCSv1.5填充生成的签名

验证使用RSA 2048位密钥、SHA256算法和PKCSv1.5填充生成的签名
EN

Stack Overflow用户
提问于 2015-09-10 14:37:01
回答 2查看 12.2K关注 0票数 3

我有一个UWA ()用KeyCredential.RequestSignAsync方法对一些数据进行签名。

该签名由以下内容创建:

并且可以使用以下代码在相同的UWA中验证:

代码语言:javascript
复制
public static bool VerifySignature(
    IBuffer buffPublicKey,
    IBuffer buffMessageData,
    IBuffer buffSignature)
{
    bool b = false;

    // Open the algorithm provider
    var algProv = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaSignPkcs1Sha256);

    // Import the public key
    var ckey = algProv.ImportPublicKey(buffPublicKey);

    // Verify
    b = CryptographicEngine.VerifySignature(ckey, buffMessageData, buffSignature);

    return b;
}

我需要验证这个签名,但是在一个常规的C#应用程序中(不是UWA)。在传输之前,公钥、消息和签名正在用CryptographicBuffer.EncodeToBase64String编码到基数64。

因此,根据我尝试使用的System.Security.Cryptography命名空间:

代码语言:javascript
复制
public static bool VerifySignature(string base64PublicKey, string base64Data, string base64Signature)
{
    bool b = false;

    byte[] publicKey = Convert.FromBase64String(base64PublicKey);
    byte[] data = Convert.FromBase64String(base64Data);
    byte[] signature = Convert.FromBase64String(base64Signature);

    using (var rsa = new RSACryptoServiceProvider(2048))
    {
        // Import public key
        rsa.ImportCspBlob(publicKey);

        // Create signature verifier with the rsa key
        var signatureDeformatter = new RSAPKCS1SignatureDeformatter(rsa);

        // Set the hash algorithm to SHA256.
        signatureDeformatter.SetHashAlgorithm("SHA256");

        b = signatureDeformatter.VerifySignature(data, siganture);
    }

    return b;
}

但是获得一个带有System.Security.Cryptography.CryptographicException附加信息的:provider.的坏版本:

rsa.ImportCspBlob(publicKey);

,使用该公钥验证签名的正确方法是什么?

编辑:示例值(base64编码)

  • MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp6HzbSgZPkJPfZJWydFAKdzUWlQcGHCTZhghg8HwHOfRZp3QZ/iiDORVzdIlW6XYPz76aAn8Nxm/v4NbsQsFPbwIcc7CPOJe21VT+7f6ocZ4kef0dqxUOGuK1FynrqzsAeYoaeTW+w/HElXODOEzZs3CfyE3d4hy3TTM/mVyQGV1FO/hHWB/zXq7ryQ8hXP/ueJimmJvitB7UweemRxvEYfVx52VVAgzg1RqVWeRj8L/obfm0lwQtIAHdDOnIi/cwpsyKQNikjMsf4dFgt14fcOgFdSG06jB840GnOsRZM04CWZQ9ttwAvoNGK/zjriRYGySQ4Ey0K0l5G3UVr56mQIDAQAB :PublicKey
  • 数据: dGF0b0Bmcm9td2luMzIuY29t
  • 签名: lWKRRgWBA2lBAfUvBS+54s9kmHTH3nJwcvYYmjCg5QpWQ9joY7Rzpq0zZjOhyxASXoAN4Vz8+mqSqPWi/4DFH7947ZWZSbopPfxiI7jjDRMAVymG0B+dRVjiMow48ZvhgP/FGSZqeLAei77Z0aAmwN2TBxkClqBpt9uy+nkI7V/TJGAbbLcWfiPWNVOGsU0smoFDQLlJjkocahNSOqjj+9PPFVqbc/VVHQWsSoq1ZxtCPILFwPCCtUCDITXrU/riGMFJ282p/3rfhDJKYis9/izR98/zgBLRoCew8zu8Za4UNWaHaR3HP/6voQI2NiVSKtss1VjvwjwXYIOh56yeSw==
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-09-14 21:02:54

考虑到X509SubjectPublicKeyInfo格式编码的PublicKey是ASN.1,并且rsa.ImportCspBlob(publicKey)希望blob与非托管Microsoft加密API (CAPI)兼容,我已经创建了一个基于这个解决方案的助手方法,该方法提取公钥参数。

使用以下代码,将成功地验证签名:

代码语言:javascript
复制
using System;
using System.IO;
using System.Security.Cryptography;


namespace ConsoleApplication2
{
    class Program
    {

        static void Main(string[] args)
        {
            var verified = false;

            byte[] data = Convert.FromBase64String("dGF0b0Bmcm9td2luMzIuY29t");
            byte[] signature = Convert.FromBase64String("lWKRRgWBA2lBAfUvBS+54s9kmHTH3nJwcvYYmjCg5QpWQ9joY7Rzpq0zZjOhyxASXoAN4Vz8+mqSqPWi/4DFH7947ZWZSbopPfxiI7jjDRMAVymG0B+dRVjiMow48ZvhgP/FGSZqeLAei77Z0aAmwN2TBxkClqBpt9uy+nkI7V/TJGAbbLcWfiPWNVOGsU0smoFDQLlJjkocahNSOqjj+9PPFVqbc/VVHQWsSoq1ZxtCPILFwPCCtUCDITXrU/riGMFJ282p/3rfhDJKYis9/izR98/zgBLRoCew8zu8Za4UNWaHaR3HP/6voQI2NiVSKtss1VjvwjwXYIOh56yeSw==");
            byte[] publicKey = Convert.FromBase64String("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp6HzbSgZPkJPfZJWydFAKdzUWlQcGHCTZhghg8HwHOfRZp3QZ/iiDORVzdIlW6XYPz76aAn8Nxm/v4NbsQsFPbwIcc7CPOJe21VT+7f6ocZ4kef0dqxUOGuK1FynrqzsAeYoaeTW+w/HElXODOEzZs3CfyE3d4hy3TTM/mVyQGV1FO/hHWB/zXq7ryQ8hXP/ueJimmJvitB7UweemRxvEYfVx52VVAgzg1RqVWeRj8L/obfm0lwQtIAHdDOnIi/cwpsyKQNikjMsf4dFgt14fcOgFdSG06jB840GnOsRZM04CWZQ9ttwAvoNGK/zjriRYGySQ4Ey0K0l5G3UVr56mQIDAQAB");

            byte[] modulus;
            byte[] exponent;
            ExtractPublicKeyParameters(publicKey, out modulus, out exponent);

            using (var rsa = new RSACryptoServiceProvider())
            {
                // Create parameters
                var rsaParam = new RSAParameters()
                {
                    Modulus = modulus,
                    Exponent = exponent
                };

                // Import public key
                rsa.ImportParameters(rsaParam);

                // Create signature verifier with the rsa key
                var signatureDeformatter = new RSAPKCS1SignatureDeformatter(rsa);

                // Set the hash algorithm to SHA256.
                signatureDeformatter.SetHashAlgorithm("SHA256");

                // Compute hash
                byte[] hash;
                using (SHA256 sha256 = SHA256.Create())
                {
                    hash = sha256.ComputeHash(data);
                }

                verified = signatureDeformatter.VerifySignature(hash, signature);
            } 

        }

        // encoded OID sequence for  PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
        static readonly byte[] SeqOid = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };

        public static void ExtractPublicKeyParameters(byte[] publicKey, out byte[] modulus, out byte[] exponent)
        {
            modulus = new byte[0];
            exponent = new byte[0];

            byte[] seq = new byte[15];

            // ---------  Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob  ------
            MemoryStream mem = new MemoryStream(publicKey);
            BinaryReader binr = new BinaryReader(mem);    //wrap Memory Stream with BinaryReader for easy reading
            byte bt = 0;
            ushort twobytes = 0;

            try
            {

                twobytes = binr.ReadUInt16();
                if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
                    binr.ReadByte();    //advance 1 byte
                else if (twobytes == 0x8230)
                    binr.ReadInt16();   //advance 2 bytes
                else
                    return;

                seq = binr.ReadBytes(15);       //read the Sequence OID
                if (!CompareBytearrays(seq, SeqOid))    //make sure Sequence for OID is correct
                    return;

                twobytes = binr.ReadUInt16();
                if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81)
                    binr.ReadByte();    //advance 1 byte
                else if (twobytes == 0x8203)
                    binr.ReadInt16();   //advance 2 bytes
                else
                    return;

                bt = binr.ReadByte();
                if (bt != 0x00)     //expect null byte next
                    return;

                twobytes = binr.ReadUInt16();
                if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
                    binr.ReadByte();    //advance 1 byte
                else if (twobytes == 0x8230)
                    binr.ReadInt16();   //advance 2 bytes
                else
                    return;

                twobytes = binr.ReadUInt16();
                byte lowbyte = 0x00;
                byte highbyte = 0x00;

                if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81)
                    lowbyte = binr.ReadByte();  // read next bytes which is bytes in modulus
                else if (twobytes == 0x8202)
                {
                    highbyte = binr.ReadByte(); //advance 2 bytes
                    lowbyte = binr.ReadByte();
                }
                else
                    return;
                byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };   //reverse byte order since asn.1 key uses big endian order
                int modsize = BitConverter.ToInt32(modint, 0);

                int firstbyte = binr.PeekChar();
                if (firstbyte == 0x00)
                {   //if first byte (highest order) of modulus is zero, don't include it
                    binr.ReadByte();    //skip this null byte
                    modsize -= 1;   //reduce modulus buffer size by 1
                }

                modulus = binr.ReadBytes(modsize);   //read the modulus bytes

                if (binr.ReadByte() != 0x02)            //expect an Integer for the exponent data
                    return;
                int expbytes = (int)binr.ReadByte();        // should only need one byte for actual exponent data (for all useful values)
                exponent = binr.ReadBytes(expbytes);
            }

            finally
            {
                binr.Close();
            }
        }

        private static bool CompareBytearrays(byte[] a, byte[] b)
        {
            if (a.Length != b.Length)
                return false;
            int i = 0;
            foreach (byte c in a)
            {
                if (c != b[i])
                    return false;
                i++;
            }
            return true;
        }
    }
}
票数 4
EN

Stack Overflow用户

发布于 2015-09-11 22:12:43

公钥采用在SubjectPublicKeyInfo第15页上定义的https://www.rfc-editor.org/rfc/rfc3280格式。

我不知道有任何(公共)标准类可以解码这些类,但是Bouncy有类,您可以使用这些类来获得带有公钥信息的RSA实例。

此外,在调用signatureDeformatter.VerifySignature( data,siganture)时,您需要传递数据的散列,而不是数据本身。

关于所有这些,我认为您的代码应该是:

代码语言:javascript
复制
using System;
using System.Linq;
using System.Security.Cryptography;
using Org.BouncyCastle.Asn1;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            byte[] data = Convert.FromBase64String("dGF0b0Bmcm9td2luMzIuY29t");
            byte[] signature = Convert.FromBase64String("lWKRRgWBA2lBAfUvBS+54s9kmHTH3nJwcvYYmjCg5QpWQ9joY7Rzpq0zZjOhyxASXoAN4Vz8+mqSqPWi/4DFH7947ZWZSbopPfxiI7jjDRMAVymG0B+dRVjiMow48ZvhgP/FGSZqeLAei77Z0aAmwN2TBxkClqBpt9uy+nkI7V/TJGAbbLcWfiPWNVOGsU0smoFDQLlJjkocahNSOqjj+9PPFVqbc/VVHQWsSoq1ZxtCPILFwPCCtUCDITXrU/riGMFJ282p/3rfhDJKYis9/izR98/zgBLRoCew8zu8Za4UNWaHaR3HP/6voQI2NiVSKtss1VjvwjwXYIOh56yeSw==");
            byte[] publicKey = Convert.FromBase64String("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp6HzbSgZPkJPfZJWydFAKdzUWlQcGHCTZhghg8HwHOfRZp3QZ/iiDORVzdIlW6XYPz76aAn8Nxm/v4NbsQsFPbwIcc7CPOJe21VT+7f6ocZ4kef0dqxUOGuK1FynrqzsAeYoaeTW+w/HElXODOEzZs3CfyE3d4hy3TTM/mVyQGV1FO/hHWB/zXq7ryQ8hXP/ueJimmJvitB7UweemRxvEYfVx52VVAgzg1RqVWeRj8L/obfm0lwQtIAHdDOnIi/cwpsyKQNikjMsf4dFgt14fcOgFdSG06jB840GnOsRZM04CWZQ9ttwAvoNGK/zjriRYGySQ4Ey0K0l5G3UVr56mQIDAQAB");
            
            byte[] hash;
            using (SHA256 sha256 = SHA256.Create())
            {
                hash = sha256.ComputeHash(data);
            }

            bool b = false;
            var rsaParam = GetPublicKeyRSAParameters(publicKey);

            using (var rsa = new RSACryptoServiceProvider())
            {
                // Import public key
                rsa.ImportParameters(rsaParam);

                // Create signature verifier with the rsa key
                var signatureDeformatter = new RSAPKCS1SignatureDeformatter(rsa);

                // Set the hash algorithm to SHA256.
                signatureDeformatter.SetHashAlgorithm("SHA256");

                b = signatureDeformatter.VerifySignature(hash, signature);
            } 
        }

        public static RSAParameters GetPublicKeyRSAParameters(byte[] subjectPublicKeyInfoBytes)
        {
            var publicKeyObject = (DerSequence)Asn1Object.FromByteArray(subjectPublicKeyInfoBytes);
            var rsaPublicKeyParametersBitString = (DerBitString)publicKeyObject[1];

            var rsaPublicKeyParametersObject = (DerSequence)Asn1Object.FromByteArray(rsaPublicKeyParametersBitString.GetBytes());

            var modulus = ((DerInteger)rsaPublicKeyParametersObject[0]).Value.ToByteArray().Skip(1).ToArray();
            var exponent = ((DerInteger)rsaPublicKeyParametersObject[1]).Value.ToByteArray();

            return new RSAParameters() { Modulus = modulus, Exponent = exponent };
        }
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32504866

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档