2010-02-16 13 views
8

ich das folgende Codebeispiel in Java haben, und ich brauche es in C# nachzustellen:Sign Daten mit MD5WithRSA von .PEM/.Pkcs8 keyfile 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(); 

Ist es möglich, mit der Standard .Net Crypto API, oder sollte ich BouncyCastle verwenden? Danke,

b.

+0

etwas off-topic, aber wenn möglich, sollten Sie mit MD5 in beliebigen Anwendungen auf jeden Fall vermeiden – Krystian

+0

‚Soll‘ ist ein starkes Wort, auch wenn MD5 schwach erwiesen ist, dass sie leicht gebrochen werden kann (siehe http : //merlot.usc.edu/csac-f06/papers/Wang05a.pdf, wie von Wikipedia referenziert) es ist nicht immer Sache des Programmierers zu entscheiden. :-) – Patrick

+0

@Krystian, es war eine Entscheidung von wem die Schnittstelle vor 6 Jahren gebaut :) – balint

Antwort

3

Ich stoße auf ein sehr ähnliches Problem beim Erstellen eines nativen C# -Tools zum Packen von Chrome-Erweiterungen (mit SHA1, nicht MD5, aber das ist kein großer Unterschied). Ich glaube, ich habe buchstäblich jede mögliche Lösung für .Net: System.Security.Cryptography, BouncyCastle, OpenSSL.Net und Chilkat RSA versucht.

Die beste Lösung ist wahrscheinlich Chilkat; ihre Schnittstelle ist die sauberste und einfachste, sie ist gut unterstützt und gut dokumentiert, und es gibt eine Million Beispiele. Zum Beispiel ist hier ein Code, der ihre Bibliothek verwendet, die etwas sehr nahe an dem was Sie wollen: http://www.example-code.com/csharp/rsa_signPkcs8.asp. Allerdings ist es nicht kostenlos (obwohl $ 150 nicht unvernünftig ist, da ich 2 Tage verbrannte, um das herauszufinden, und ich mache ein bisschen mehr als $ 75 pro Tag!).

Als kostenlose Alternative bietet JavaScience eine Reihe von Kryptoprogrammen in Quellform für mehrere Sprachen (einschließlich C# /. Net) unter http://www.jensign.com/JavaScience/cryptoutils/index.html an. Das, was am meisten hervorsticht, was Sie versuchen, ist opensslkey (http://www.jensign.com/opensslkey/index.html), mit dem Sie einen RSACryptoServiceProvider aus einer .pem-Datei generieren können. Sie können dann diesen Anbieter verwenden Sie den Code zu unterzeichnen:

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

     signature = rsa.SignData(data, new MD5CryptoServiceProvider()); 
+0

Ich werde Chilkat nicht empfehlen, weil es plattformabhängig ist (Sie müssen verschiedene Bibliotheken für x86 und x64 verwenden) und nicht sicher über RSA, aber ihre Implementierung der symmetrischen Kryptographie ist nicht kompatibel mit 'System.Security.Cryptography'. – Regent

1

This SO question beantwortet den PKCS # 8-Teil Ihres Codes. Der Rest der .NET RSA-Klassen ist ein bizarres Durcheinander von teilweise überlappenden Klassen, die sehr schwer zu ergründen sind. Es scheint, dass die Signaturunterstützung in einer der Klassen RSACryptoServiceProvider und/oder RSAPKCS1SignatureFormatter liegt.

1

Haftungsausschluss: Ich kenne Java und Kryptographie, aber mein Wissen über C# und .NET ist sehr begrenzt. Ich schreibe hier nur unter dem Einfluss meiner Google-Fu-Fähigkeiten.

Unter der Annahme, dass Sie einen PKCS # 8-kodierten privaten RSA-Schlüssel entschlüsseln könnten, dann, von dem, was ich auf MSDN lesen, der Rest des Codes sollte wie folgt aussehen:

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

Die entsprechenden Klassen sind in der System.Security.Cryptography Namensraum.

Wie für die Schlüssel Blob Decodierung PKCS # 8 (d. H. Ausfüllen der Felder rsp), fand ich this page, die ein Befehlszeilenprogramm in C# beschreibt, die diesen Job ausführen kann. Der Quellcode wird bereitgestellt und ist eine einzelne C# -Datei. Von dem, was ich darin gelesen habe, dekodiert dieser Code die PKCS # 8-Datei "manuell"; indirekt sollte dies bedeuten, dass Raw .NET (2.0) nicht über Funktionen für die PKCS # 8-Schlüsseldateidekodierung verfügt (andernfalls wäre der Autor dieses Tools nicht in die Schwierigkeiten geraten, eine solche Dekodierung zu implementieren). Für Ihre anstehende Aufgabe können Sie die benötigten Teile aus dieser Quelldatei aufspüren und alles über PEM und symmetrische Verschlüsselung überspringen. Ihr Einstiegspunkt wäre die DecodePrivateKeyInfo()-Funktion, die offensichtlich eine DER-codierte unverschlüsselte PKCS # 8-Datei erwartet, genau wie Javas PKCS8EncodedKeySpec.

+0

Tim, bleib ruhig, ich überprüfe alle Antworten – balint

9

Ein anderer Weg ist CNG (Cryptography Next Generation) zu verwenden, zusammen mit der Sicherheit.Cryptography DLL von CodePlex

Dann können Sie schreiben:

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

Aktualisiert dank Simon Mourier: mit .Net 4.6, müssen Sie nicht mehr eine separate Bibliothek

+0

Noch nie davon gehört! Kennen Sie weitere Beispiele? – LamonteCristo

+0

Im MSDN-Magazin gibt es Beispiele: http://msdn.microsoft.com/en-us/magazine/cc163389.aspx – Timores

+1

Hinweis: Dies ist jetzt in .NET Framework 4.6 enthalten. Dies ist wirklich der Weg für heutige .NET-Entwicklungen. –

0

Sie diesen Code verwenden können. Als erstes sollten Sie "BouncyCastle.Crypto.dll" von http://www.bouncycastle.org/csharp/ herunterladen.

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