2010-02-16 3 views
8

Ho il seguente codice di esempio in Java, e ho bisogno di rivivere in C#:dati firmare con MD5WithRSA da .pem/.Pkcs8 file di chiavi 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(); 

E 'possibile con il API standard .Net Crypto o dovrei usare BouncyCastle? Grazie,

b.

+0

un po 'off-topic, ma, se possibile, si dovrebbe assolutamente evitare di utilizzare MD5 in tutte le applicazioni – Krystian

+0

'Dovrebbe' è una parola forte, anche se MD5 è stato dimostrato debole che può essere facilmente rotto (vedi http : //merlot.usc.edu/csac-f06/papers/Wang05a.pdf, come riportato da Wikipedia) non è sempre compito del programmatore decidere. :-) – Patrick

+0

@Krystian, è stata una decisione presa da chi ha costruito l'interfaccia 6 anni fa :) – balint

risposta

3

Mi sto imbattendo in un problema molto simile cercando di creare uno strumento nativo C# per il confezionamento di estensioni di Chrome (utilizzando SHA1, non MD5, ma questa non è una grande differenza). Credo di aver provato letteralmente ogni possibile soluzione per .Net: System.Security.Cryptography, BouncyCastle, OpenSSL.Net e Chilkat RSA.

La soluzione migliore è probabilmente Chilkat; la loro interfaccia è la più pulita e più diretta, è ben supportata e ben documentata, e ci sono un milione di esempi. Ad esempio, ecco un codice usando la loro libreria che fa qualcosa di molto vicino a quello che vuoi: http://www.example-code.com/csharp/rsa_signPkcs8.asp. Tuttavia, non è gratuito (anche se $ 150 non è irragionevole, visto che ho bruciato 2 giorni cercando di capirlo, e guadagno un po 'più di $ 75 al giorno!).

Come alternativa gratuita, JavaScience offre una serie di utilità di crittografia in formato sorgente per più lingue (incluso C# /. Net) al numero http://www.jensign.com/JavaScience/cryptoutils/index.html. Quello che è più saliente di ciò che stai cercando di fare è opensslkey (http://www.jensign.com/opensslkey/index.html), che ti permetterà di generare un RSACryptoServiceProvider da un file .pem. È quindi possibile utilizzare tale provider per firmare il codice:

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

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

Non ti consiglio di usare Chilkat perché dipende dalla piattaforma (devi usare librerie diverse per x86 e x64) e, non sono sicuro di RSA, ma la loro implementazione della crittografia simmetrica non è compatibile con 'System.Security.Cryptography'. – Regent

1

This SO question risponde alla parte PKCS # 8 del codice. Il resto delle classi .NET RSA sono un bizzarro miscuglio di classi parzialmente sovrapposte che sono molto difficili da comprendere. Sembra certamente che il supporto della firma sia in una delle classi RSACryptoServiceProvider e/o RSAPKCS1SignatureFormatter.

1

Disclaimer: Conosco Java e la crittografia, ma la mia conoscenza di C# e .NET è molto limitata. Sto scrivendo qui solo sotto l'influenza delle mie competenze di Google-fu.

Supponendo che si potrebbe decodificare una chiave privata RSA PKCS # 8-encoded, poi, da quanto ho letto su MSDN, il resto del codice dovrebbe essere simile a questo:

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

Le classi rilevanti sono in lo spazio dei nomi System.Security.Cryptography.

Come per la decodifica blob dei tasti PKCS n. Il codice sorgente è fornito ed è un singolo file C#. Da quello che ho letto, quel codice decodifica il file PKCS # 8 "manualmente"; indirettamente, questo dovrebbe significare che .NET (2.0) non ha funzionalità per la decodifica dei file chiave PKCS # 8 (altrimenti l'autore di tale strumento non sarebbe andato incontro al problema di implementare tale decodifica). Per il tuo compito a portata di mano, puoi recuperare da quel file sorgente le parti di cui hai bisogno, saltando qualsiasi cosa su PEM e la crittografia simmetrica; il tuo punto di ingresso sarebbe la funzione DecodePrivateKeyInfo(), che a quanto pare si aspetta un file PKCS # 8 non codificato DER codificato, proprio come Java PKCS8EncodedKeySpec.

+0

Tim, stai calmo, sto controllando tutte le risposte – balint

9

Un altro modo è quello di usare CNG (Cryptography Next Generation), insieme con la sicurezza.La crittografia DLL da CodePlex

Poi si può scrivere:

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

aggiornati grazie a Simon Mourier: con .Net 4.6, non è più necessario una libreria separata

+0

Mai sentito parlare di questo prima! Conosci altri esempi? – LamonteCristo

+0

Esistono alcuni esempi nella rivista MSDN: http://msdn.microsoft.com/en-us/magazine/cc163389.aspx – Timores

+1

Nota questo è ora incluso in .NET Framework 4.6. Questo è davvero il modo di procedere per gli sviluppi .NET di oggi. –

0

È possibile utilizzare questo codice. Per prima cosa devi scaricare "BouncyCastle.Crypto.dll" da 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); 
    } 
} 
Problemi correlati