2

I need to sign some data with one private key using Algorithm SHA1RSA ,Rsa Key length 2048 with 64 base encoding.My code is like this

string sPayload = "";
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create("URI");
httpWebRequest.ContentType = "application/json; charset=utf-8";
httpWebRequest.Method = WebRequestMethods.Http.Post;

using (StreamWriter streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
    sPayload = "{\"id\":\"14123213213\"," +
                "\"uid\":\"teller\"," +
                "\"pwd\":\"abc123\"," +
                "\"apiKey\":\"2343243\"," +
                "\"agentRefNo\":\"234324324\"}";

    httpWebRequest.Headers.Add("SIGNATURE", Convert.ToBase64String(new System.Security.Cryptography.SHA1CryptoServiceProvider().ComputeHash(Encoding.ASCII.GetBytes(sPayload))));
    
    streamWriter.Write(sPayload);
    streamWriter.Flush();
    streamWriter.Close();
}

System.Net.ServicePointManager.Expect100Continue = false;

HttpWebResponse httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();

using (StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
    string result = streamReader.ReadToEnd();
}

In the Header name Signature i need to pass the signed data(sPayload) using the private key.But using above code an error is getting as "invalid signature" from third party and i'am not sure whether the Encryption part is correct or not.

httpWebRequest.Headers.Add("SIGNATURE", Convert.ToBase64String(new System.Security.Cryptography.SHA1CryptoServiceProvider().ComputeHash(Encoding.ASCII.GetBytes(sPayload))));

Third party had provide one certificate(cert,sha1) and key.should i refer that to the code?

Mark A. Donohoe
  • 28,442
  • 25
  • 137
  • 286
  • There's nothing wrong with .NET's classes. Your code though simply generates a hash, it doesn't sign anything. Without knowing what kind of signature you want to generate though, it's impossible to help. Even if the other side simply requests a hash of the data, you need to make sure you are hashing the same payload the other side expects to receive. A single byte error (eg a wrong escape sequence) will create completely different hash values. Do you have any input/output examples? – Panagiotis Kanavos Aug 05 '15 at 11:04
  • Also PLEASE extract the important code to different lines if not a separate method that can be tested. You've put all the important work of your signing method in a single very long line that's impossible to read – Panagiotis Kanavos Aug 05 '15 at 11:08
  • need to generate signature using Algorithm: SHA1RSA, RSA Key length:2048, Encoding: Base64.Payload should be signed with the private key provided by the other side and the request structure is { id: "string", uid: "string", pwd: "string", apiKey: "string", agentRefNo: "string" } –  Aug 05 '15 at 11:18
  • Yes, you need to import the certificate that contains the public key. That public key can then be used to sign (although usually you can just indicate the certificate in the code and the signature class will retrieve the public key itself). – Maarten Bodewes Aug 11 '15 at 20:41
  • Also see [Signing and verifying signatures with RSA C#](https://stackoverflow.com/q/8437288/608639), [how to sign bytes using my own rsa private key using rs256 algorithm?](https://stackoverflow.com/q/25909044/608639), [Signing data with private key in c#](https://stackoverflow.com/q/31828420/608639), [How can I sign a file using RSA and SHA256 with .NET?](https://stackoverflow.com/q/7444586/608639), [Signing a string with RSA private key on .NET?](https://stackoverflow.com/q/3169829/608639), etc. – jww May 30 '17 at 13:54

1 Answers1

5

You have computed the SHA-1 hash of sPayload, not the RSA-SHA1 signature.

If you have an X509Certificate2:

using (RSA rsa = cert.GetRSAPrivateKey())
{
    return rsa.SignData(sPayload, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
}

If you already have a raw RSA key then just leave off the using statement.

If you have to compute the hash of sPayload for some other reason you can do it like

byte[] hash;
byte[] signature;

using (HashAlgorithm hasher = SHA1.Create())
using (RSA rsa = cert.GetRSAPrivateKey())
{
    hash = hasher.ComputeHash(sPayload);
    signature = rsa.SignHash(hash, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
}

SignHash still requires the HashAlgorithmName value because the algorithm identifier is embedded within the signature.

bartonjs
  • 30,352
  • 2
  • 71
  • 111