Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sign data with MD5WithRSA from .Pem/.Pkcs8 keyfile in C#

I've got the following code sample in Java, and I need to re-enact it in C#:

PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(pkcs8PrivateKey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privKey = keyFactory.generatePrivate(privKeySpec);
Signature sign = Signature.getInstance("MD5withRSA");

sign.initSign(privKey);
sign.update(data);
byte[] signature = sign.sign();

Is it possible with the standard .Net Crypto API, or should I use BouncyCastle? Thanks,

b.

like image 485
balint Avatar asked Feb 16 '10 17:02

balint


3 Answers

Another way is to use CNG (Cryptography Next Generation), along with the Security.Cryptography DLL from CodePlex

Then you can write:

byte[] dataToSign = Encoding.UTF8.GetBytes("Data to sign");
using (CngKey signingKey = CngKey.Import(pkcs8PrivateKey, CngKeyBlobFormat.Pkcs8PrivateBlob))
  using (RSACng rsa = new RSACng(signingKey))
  {
    rsa.SignatureHashAlgorithm = CngAlgorithm.MD5;
    return rsa.SignData(dataToSign);
  }

Updated thanks to Simon Mourier: with .Net 4.6, you no longer need a separate library

like image 147
Timores Avatar answered Nov 08 '22 21:11

Timores


I am running into a very similar problem trying to create a native C# tool for packing Chrome extensions (using SHA1, not MD5, but that's not a big difference). I believe I have tried literally every possible solution for .Net: System.Security.Cryptography, BouncyCastle, OpenSSL.Net and Chilkat RSA.

The best solution is probably Chilkat; their interface is the cleanest and most straightforward, it's well-supported and well-documented, and there are a million examples. For instance, here's some code using their library that does something very close to what you want: http://www.example-code.com/csharp/rsa_signPkcs8.asp. However, it's not free (though $150 is not unreasonable, seeing as I have burned 2 days trying to figure this out, and I make a bit more than $75 a day!).

As a free alternative, JavaScience offers up a number of crypto utilities in source form for multiple languages (including C#/.Net) at http://www.jensign.com/JavaScience/cryptoutils/index.html. The one that's most salient to what you are trying to do is opensslkey (http://www.jensign.com/opensslkey/index.html), which will let you generate a RSACryptoServiceProvider from a .pem file. You can then use that provider to sign your code:

        string pemContents = new StreamReader("pkcs8privatekey.pem").ReadToEnd();
        var der = opensslkey.DecodePkcs8PrivateKey(pemContents);
        RSACryptoServiceProvider rsa = opensslkey.DecodePrivateKeyInfo(der);

        signature = rsa.SignData(data, new MD5CryptoServiceProvider());
like image 3
Tim Keating Avatar answered Nov 08 '22 22:11

Tim Keating


You can use this code . At the first you should download "BouncyCastle.Crypto.dll" from http://www.bouncycastle.org/csharp/ .

/// <summary>
/// MD5withRSA Signing
/// https://www.vrast.cn
/// keyle_xiao 2017.1.12
/// </summary>
public class MD5withRSASigning
{
    public Encoding encoding = Encoding.UTF8;
    public string SignerSymbol = "MD5withRSA";

    public MD5withRSASigning() { }

    public MD5withRSASigning(Encoding e, string s)
    {
        encoding = e;
        SignerSymbol = s;
    }

    private AsymmetricKeyParameter CreateKEY(bool isPrivate, string key)
    {
        byte[] keyInfoByte = Convert.FromBase64String(key);

        if (isPrivate)
            return PrivateKeyFactory.CreateKey(keyInfoByte);
        else
            return PublicKeyFactory.CreateKey(keyInfoByte);
    }

    public string Sign(string content, string privatekey)
    {
        ISigner sig = SignerUtilities.GetSigner(SignerSymbol);

        sig.Init(true, CreateKEY(true, privatekey));

        var bytes = encoding.GetBytes(content);

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

        return signedString;
    }

    public bool Verify(string content, string signData, string publickey)
    {
        ISigner signer = SignerUtilities.GetSigner(SignerSymbol);

        signer.Init(false, CreateKEY(false, publickey));

        var expectedSig = Convert.FromBase64String(signData);

        /* Get the bytes to be signed from the string */
        var msgBytes = encoding.GetBytes(content);

        /* Calculate the signature and see if it matches */
        signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
        return signer.VerifySignature(expectedSig);
    }
}
like image 2
keyle Avatar answered Nov 08 '22 23:11

keyle