1

Is there an easy way to do this in C# ?

 openssl_sign($input, $output, $privateKey, OPENSSL_ALGO_SHA1)
  • $input is a string to be signed
  • $output - If the call was successful the signature is returned in this variable. It is a byte[]
  • $privateKey is a PEM private key (string)

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

I'm getting the input string from an XML, it is flattenned, like this:

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

I'm getting the privateKey string from the content of the <RSASK> tag in an XML:

<?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>
2
  • how is this "too broad"? it is NOT BROAD. There are 2 strings and an output byte[]. That is not broad. Commented Sep 5, 2018 at 19:29
  • You should take a look at this post: stackoverflow.com/questions/36931840/… Commented Sep 5, 2018 at 19:31

1 Answer 1

3

It wasn't easy at all:

  1. First, I needed to convert the input string to a byte[]

        ASCIIEncoding ByteConverter = new ASCIIEncoding();
        byte[] inputBytes = ByteConverter.GetBytes(input);
    
  2. Compute its SHA1 Hash

        byte[] inputHash = new SHA1CryptoServiceProvider().ComputeHash(inputBytes);
    
  3. Remove the beginning and end of the RSA PRIVATE KEY and convert it to 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. Then I had to create a RSACryptoServiceProvider from privateKeyBytes but I had to use a complicated class found on Internet:

        RSACryptoServiceProvider rsa = RSAUtils.DecodeRSAPrivateKey(privateKeyBytes);
                                       // ^
                                       // Found on Internet
    
  5. Then I finally could sign

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

Code found on the 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;
    }

}





Testing that it works.

Php Test

$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));

The PHP output is:

pqjXHHQLJmyFPMRvxScN7tYHvIsty0pqL2LLYaG43jMmnfiZfllLA0wb32lP+HBJ/tf8nziSeorvjlx410ZImw==

C# Test

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));

The C# output is:

pqjXHHQLJmyFPMRvxScN7tYHvIsty0pqL2LLYaG43jMmnfiZfllLA0wb32lP+HBJ/tf8nziSeorvjlx410ZImw==
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.