PHP使用字符串在C#中使用openssl_sign

时间:2018-09-05 19:24:05

标签: c#

在C#中有简单的方法吗?

 openssl_sign($input, $output, $privateKey, OPENSSL_ALGO_SHA1)
  • $input是要签名的字符串
  • $output-如果调用成功,则在此变量中返回签名。这是一个字节[]
  • $privateKey是PEM私钥(字符串)

参考:http://php.net/manual/en/function.openssl-sign.php

我从XML中获取input字符串,它被扁平化,如下所示:

<foo><bar1>qux1</bar1><bar2>qux2</bar2></foo>

我从XML中privateKey标记的内容中获得了<RSASK>字符串:

<?xml version="1.0"?>
<bla1>foo</bla1>
<bla2>bar</bla2>
<RSASK>-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBAMo8SSYPCvFBDgCqFv8o8UzznvcXO6FwUKmbDFogNIA5yQKTJc8i
VIYt6oXLfes+q5i+4oQWb6MJgTIZvcjmCL8CAQMCQQCG0ttutLH2K16rHA9UxfYz
TRSkuifA9YsbasdLmwCMAJVWbScsJcXdecXfWJJVcFTo5fFf6PIigPACHUZlSo8xb
AiEA9vjXy5u74OBS3ekQdMuKrUv5fi6z+EChhhCclVtFwhMCIQDRoMyppTxAmDDY
24QpFZQm9orgXgeqcg0vVoLCcaqUJQIhAKSl5TJn0pXq4elGCviHscjdUP7JzVAr
FuC1vbjng9a3AiEAi8CIcRjS1brLOz0Cxg5ixKRclZQFHEwIyjmsgaEcYsMCIEFT
oGduMC3vOMtKHEo8SAfDFeirfubo+FAZteQ0pyFF
-----END RSA PRIVATE KEY-----
</RSASK>

1 个答案:

答案 0 :(得分:1)

这并不容易

  1. 首先,我需要将输入字符串转换为字节[]

        ASCIIEncoding ByteConverter = new ASCIIEncoding();
        byte[] inputBytes = ByteConverter.GetBytes(input);
    
  2. 计算其SHA1哈希值

        byte[] inputHash = new SHA1CryptoServiceProvider().ComputeHash(inputBytes);
    
  3. 删除RSA PRIVATE KEY的开头和结尾并将其转换为byte []

        byte[] privateKeyBytes = Convert.FromBase64String(privateKey
            .Replace("-----BEGIN RSA PRIVATE KEY-----", string.Empty)
            .Replace("-----END RSA PRIVATE KEY-----", string.Empty)
            .Replace("\n", string.Empty));
    
  4. 然后我必须从RSACryptoServiceProvider创建一个privateKeyBytes,但必须使用Internet上的一个复杂类:

        RSACryptoServiceProvider rsa = RSAUtils.DecodeRSAPrivateKey(privateKeyBytes);
                                       // ^
                                       // Found on Internet
    
  5. 然后我终于可以签名

        byte[] output = rsa.SignHash(inputHash, "SHA1");
    

在Internet上找到的代码:

public class RSAUtils
{
    public static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
    {
        byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;

        // --------- Set up stream to decode the asn.1 encoded RSA private key ------
        MemoryStream mem = new MemoryStream(privkey);
        BinaryReader binr = new BinaryReader(mem);  //wrap Memory Stream with BinaryReader for easy reading
        byte bt = 0;
        ushort twobytes = 0;
        int elems = 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 null;

            twobytes = binr.ReadUInt16();
            if (twobytes != 0x0102) //version number
                return null;
            bt = binr.ReadByte();
            if (bt != 0x00)
                return null;


            //------ all private key components are Integer sequences ----
            elems = GetIntegerSize(binr);
            MODULUS = binr.ReadBytes(elems);

            elems = GetIntegerSize(binr);
            E = binr.ReadBytes(elems);

            elems = GetIntegerSize(binr);
            D = binr.ReadBytes(elems);

            elems = GetIntegerSize(binr);
            P = binr.ReadBytes(elems);

            elems = GetIntegerSize(binr);
            Q = binr.ReadBytes(elems);

            elems = GetIntegerSize(binr);
            DP = binr.ReadBytes(elems);

            elems = GetIntegerSize(binr);
            DQ = binr.ReadBytes(elems);

            elems = GetIntegerSize(binr);
            IQ = binr.ReadBytes(elems);

            // ------- create RSACryptoServiceProvider instance and initialize with public key -----
            CspParameters CspParameters = new CspParameters();
            CspParameters.Flags = CspProviderFlags.UseMachineKeyStore;
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(1024, CspParameters);
            RSAParameters RSAparams = new RSAParameters();
            RSAparams.Modulus = MODULUS;
            RSAparams.Exponent = E;
            RSAparams.D = D;
            RSAparams.P = P;
            RSAparams.Q = Q;
            RSAparams.DP = DP;
            RSAparams.DQ = DQ;
            RSAparams.InverseQ = IQ;
            RSA.ImportParameters(RSAparams);
            return RSA;
        }
        catch (Exception ex)
        {
            return null;
        }
        finally
        {
            binr.Close();
        }
    }

    private static int GetIntegerSize(BinaryReader binr)
    {
        byte bt = 0;
        byte lowbyte = 0x00;
        byte highbyte = 0x00;
        int count = 0;
        bt = binr.ReadByte();
        if (bt != 0x02)      //expect integer
            return 0;
        bt = binr.ReadByte();

        if (bt == 0x81)
            count = binr.ReadByte();    // data size in next byte
        else
            if (bt == 0x82)
            {
                highbyte = binr.ReadByte();    // data size in next 2 bytes
                lowbyte = binr.ReadByte();
                byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
                count = BitConverter.ToInt32(modint, 0);
            }
            else
            {
                count = bt;      // we already have the data size
            }

        while (binr.ReadByte() == 0x00)
        {    //remove high order zeros in data
            count -= 1;
        }
        binr.BaseStream.Seek(-1, SeekOrigin.Current);        //last ReadByte wasn't a removed zero, so back up a byte
        return count;
    }

}





测试它是否有效。

Php测试

$input = "<DD><RE>97975000-5</RE><TD>33</TD><F>27</F><FE>2003-09-08</FE><RR>8414240-9</RR><RSR>JORGE GONZALEZ LTDA</RSR><MNT>502946</MNT><IT1>Cajon AFECTO</IT1><CAF version=\"1.0\"><DA><RE>97975000-5</RE><RS>RUT DE PRUEBA</RS><TD>33</TD><RNG><D>1</D><H>200</H></RNG><FA>2003-09-04</FA><RSAPK><M>0a4O6Kbx8Qj3K4iWSP4w7KneZYeJ+g/prihYtIEolKt3cykSxl1zO8vSXu397QhTmsX7SBEudTUx++2zDXBhZw==</M><E>Aw==</E></RSAPK><IDK>100</IDK></DA><FRMA algoritmo=\"SHA1withRSA\">g1AQX0sy8NJugX52k2hTJEZAE9Cuul6pqYBdFxj1N17umW7zG/hAavCALKByHzdYAfZ3LhGTXCai5zNxOo4lDQ==</FRMA></CAF><TSTED>2003-09-08T12:28:31</TSTED></DD>";
$privateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIBOwIBAAJBANGuDuim8fEI9yuIlkj+MOyp3mWHifoP6a4oWLSBKJSrd3MpEsZdczvL0l7t/e0IU5rF+0gRLnU1Mfvtsw1wYWcCAQMCQQCLyV9FxKFLW09yWw7bVCCdxpRDr7FRX/EexZB4VhsNxm/vtJfDZyYle0Lfy42LlcsXxPm1w6Q6NnjuW+AeBy67AiEA7iMi5q5xjswqq+49RP55o//jqdZL/pC9rdnUKxsNRMMCIQDhaHdIctErN2hCIP9knS3+9zra4R+5jSXOvI+3xVhWjQIhAJ7CF0R0S7SIHHKe04NUURf/7RvkMqm108k74sdnXi3XAiEAlkWk2vc2HM+a1sCqQxNz/098ketqe7NuidMKeoOQObMCIQCkFAMS9IcPcMjk7zI2r/4EEW63PSXyN7MFAX7TYe25mw==\n-----END RSA PRIVATE KEY-----";
openssl_sign($input, $output, $privateKey, OPENSSL_ALGO_SHA1);
echo(base64_encode($output));

PHP输出为:

pqjXHHQLJmyFPMRvxScN7tYHvIsty0pqL2LLYaG43jMmnfiZfllLA0wb32lP+HBJ/tf8nziSeorvjlx410ZImw==

C#测试

string input = "<DD><RE>97975000-5</RE><TD>33</TD><F>27</F><FE>2003-09-08</FE><RR>8414240-9</RR><RSR>JORGE GONZALEZ LTDA</RSR><MNT>502946</MNT><IT1>Cajon AFECTO</IT1><CAF version=\"1.0\"><DA><RE>97975000-5</RE><RS>RUT DE PRUEBA</RS><TD>33</TD><RNG><D>1</D><H>200</H></RNG><FA>2003-09-04</FA><RSAPK><M>0a4O6Kbx8Qj3K4iWSP4w7KneZYeJ+g/prihYtIEolKt3cykSxl1zO8vSXu397QhTmsX7SBEudTUx++2zDXBhZw==</M><E>Aw==</E></RSAPK><IDK>100</IDK></DA><FRMA algoritmo=\"SHA1withRSA\">g1AQX0sy8NJugX52k2hTJEZAE9Cuul6pqYBdFxj1N17umW7zG/hAavCALKByHzdYAfZ3LhGTXCai5zNxOo4lDQ==</FRMA></CAF><TSTED>2003-09-08T12:28:31</TSTED></DD>";
string privateKey = "-----BEGIN RSA PRIVATE KEY-----\nMIIBOwIBAAJBANGuDuim8fEI9yuIlkj+MOyp3mWHifoP6a4oWLSBKJSrd3MpEsZdczvL0l7t/e0IU5rF+0gRLnU1Mfvtsw1wYWcCAQMCQQCLyV9FxKFLW09yWw7bVCCdxpRDr7FRX/EexZB4VhsNxm/vtJfDZyYle0Lfy42LlcsXxPm1w6Q6NnjuW+AeBy67AiEA7iMi5q5xjswqq+49RP55o//jqdZL/pC9rdnUKxsNRMMCIQDhaHdIctErN2hCIP9knS3+9zra4R+5jSXOvI+3xVhWjQIhAJ7CF0R0S7SIHHKe04NUURf/7RvkMqm108k74sdnXi3XAiEAlkWk2vc2HM+a1sCqQxNz/098ketqe7NuidMKeoOQObMCIQCkFAMS9IcPcMjk7zI2r/4EEW63PSXyN7MFAX7TYe25mw==\n-----END RSA PRIVATE KEY-----";

ASCIIEncoding ByteConverter = new ASCIIEncoding();
byte[] inputBytes = ByteConverter.GetBytes(input);

byte[] inputHash = new SHA1CryptoServiceProvider().ComputeHash(inputBytes);

byte[] privateKeyBytes = Convert.FromBase64String(privateKey
    .Replace("-----BEGIN RSA PRIVATE KEY-----", string.Empty)
    .Replace("-----END RSA PRIVATE KEY-----", string.Empty)
    .Replace("\n", string.Empty));

RSACryptoServiceProvider rsa = RSAUtils.DecodeRSAPrivateKey(privateKeyBytes);

byte[] output = rsa.SignHash(inputHash, "SHA1");

Console.WriteLine(Convert.ToBase64String(output));

C#输出为:

pqjXHHQLJmyFPMRvxScN7tYHvIsty0pqL2LLYaG43jMmnfiZfllLA0wb32lP+HBJ/tf8nziSeorvjlx410ZImw==