Подписать данные с помощью MD5WithRSA из файла ключей .Pem / .Pkcs8 в C # - PullRequest
8 голосов
/ 16 февраля 2010

У меня есть следующий пример кода на Java, и мне нужно воспроизвести его на 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();

Возможно ли это с помощью стандартного .Net Crypto API или мне следует использовать BouncyCastle? Спасибо,

б.

Ответы [ 5 ]

9 голосов
/ 26 февраля 2010

Другой способ - использовать CNG (криптография следующего поколения) вместе с DLL-библиотекой Security.Cryptography из CodePlex

Тогда вы можете написать:

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

Обновлено благодаря Саймону Мурье: с .Net 4.6 вам больше не нужна отдельная библиотека

3 голосов
/ 19 февраля 2010

Я сталкиваюсь с очень похожей проблемой, пытаясь создать собственный инструмент C # для упаковки расширений Chrome (используя SHA1, а не MD5, но это не большая разница). Я считаю, что я испробовал буквально все возможные решения для .Net: System.Security.Cryptography, BouncyCastle, OpenSSL.Net и Chilkat RSA.

Лучшее решение, вероятно, Chilkat; их интерфейс - самый чистый и простой, он хорошо поддерживается и хорошо документирован, и есть миллион примеров. Например, вот некоторый код, использующий их библиотеку, который делает что-то очень близкое к тому, что вы хотите: http://www.example -code.com / csharp / rsa_signPkcs8.asp . Тем не менее, это не бесплатно (хотя 150 долларов не является необоснованным, учитывая, что я потратил 2 дня, пытаясь это выяснить, и я зарабатываю чуть больше 75 долларов в день!).

В качестве бесплатной альтернативы JavaScience предлагает несколько криптографических утилит в исходном виде для нескольких языков (включая C # /. Net) по адресу http://www.jensign.com/JavaScience/cryptoutils/index.html.. Наиболее очевидным из того, что вы пытаетесь сделать, является opensslkey. (http://www.jensign.com/opensslkey/index.html),, который позволит вам сгенерировать RSACryptoServiceProvider из файла .pem. Затем вы можете использовать этого провайдера для подписи своего кода:

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

        signature = rsa.SignData(data, new MD5CryptoServiceProvider());
1 голос
/ 19 февраля 2010

Отказ от ответственности: Я знаю Java и криптографию, но мои знания C # и .NET очень ограничены. Я пишу здесь только под влиянием моих навыков Google-фу.

Если предположить, что вы могли бы декодировать закрытый ключ RSA в кодировке PKCS # 8, то из того, что я прочитал в MSDN, остальная часть кода должна выглядеть следующим образом:

byte[] hv = MD5.Create().ComputeHash(data);
RSACryptoServiceProvider rsp = new RSACryptoServiceProvider();
RSAParameters rsp = new RSAParameters();
// here fill rsp fields by decoding pkcs8PrivateKey
rsp.ImportParameters(key);
RSAPKCS1SignatureFormatter rf = new RSAPKCS1SignatureFormatter(rsp);
rf.SetHashAlgorithm("MD5");
byte[] signature = rf.CreateSignature(hv);

Соответствующие классы находятся в пространстве имен System.Security.Cryptography.

Что касается декодирования ключевого объекта PKCS # 8 (т.е. заполнения полей rsp), я обнаружил эту страницу , которая описывает утилиту командной строки в C #, которая может выполнять эту работу. Исходный код предоставляется и представляет собой один файл C #. Из того, что я прочитал в нем, этот код декодирует файл PKCS # 8 «вручную»; косвенно это должно означать, что в raw .NET (2.0) нет средств для декодирования файла ключей PKCS # 8 (в противном случае автор этого инструмента не стал бы сталкиваться с проблемой реализации такого декодирования). Для выполнения поставленной задачи вы можете извлечь из этого исходного файла те части, которые вам нужны, пропуская что-либо о PEM и симметричном шифровании; вашей точкой входа будет функция DecodePrivateKeyInfo(), которая, очевидно, ожидает кодированный DER-файл незашифрованный файл PKCS # 8, как и Java PKCS8EncodedKeySpec.

.
1 голос
/ 17 февраля 2010

Этот вопрос SO отвечает на часть PKCS # 8 вашего кода. Остальные классы .NET RSA представляют собой причудливую путаницу частично перекрывающихся классов, которые очень трудно понять. Похоже, что поддержка подписи поддерживается в классах RSACryptoServiceProvider и / или RSAPKCS1SignatureFormatter.

0 голосов
/ 12 января 2017

Вы можете использовать этот код. Сначала вы должны скачать "BouncyCastle.Crypto.dll" из 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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...