2010-02-16 11 views
8

Tengo el siguiente ejemplo de código en Java, y tengo que volver a representar en C#:datos de la muestra con MD5WithRSA de .PEM/.Pkcs8 archivo de claves en 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(); 

¿Es posible con el estándar .Net Crypto API, o debería usar BouncyCastle? Gracias,

b.

+0

poco fuera de tema, pero si es posible, debería evitar el uso de MD5 en cualquier aplicación – Krystian

+0

'debería' es una palabra fuerte, incluso si MD5 se ha demostrado débil en que se puede romper fácilmente (ver http : //merlot.usc.edu/csac-f06/papers/Wang05a.pdf, como se hace referencia en Wikipedia) no siempre es decisión del programador. :-) – Patrick

+0

@Krystian, fue una decisión tomada por quién construyó la interfaz hace 6 años :) – balint

Respuesta

3

Me encuentro con un problema muy similar al tratar de crear una herramienta C# nativa para empaquetar extensiones de Chrome (usando SHA1, no MD5, pero eso no es una gran diferencia). Creo que he intentado literalmente todas las soluciones posibles para .Net: System.Security.Cryptography, BouncyCastle, OpenSSL.Net y Chilkat RSA.

La mejor solución es probablemente Chilkat; su interfaz es la más limpia y directa, está bien respaldada y bien documentada, y hay un millón de ejemplos. Por ejemplo, aquí hay un código que usa su biblioteca y que hace algo muy parecido a lo que desea: http://www.example-code.com/csharp/rsa_signPkcs8.asp. Sin embargo, no es gratis (aunque $ 150 no es irrazonable, ya que he quemado 2 días tratando de resolver esto, ¡y gano un poco más de $ 75 por día!).

Como alternativa gratuita, JavaScience ofrece varias utilidades de cifrado en formato de origen para varios idiomas (incluido C#/.Net) en http://www.jensign.com/JavaScience/cryptoutils/index.html. El que sobresale más de lo que intenta hacer es opensslkey (http://www.jensign.com/opensslkey/index.html), que le permitirá generar un RSACryptoServiceProvider desde un archivo .pem. A continuación, puede utilizar ese proveedor para firmar su código:

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

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

No recomendaré el uso de Chilkat porque depende de la plataforma (debe usar diferentes bibliotecas para x86 y x64) y no está seguro sobre RSA, pero su implementación de criptografía simétrica no es compatible con 'System.Security.Cryptography'. – Regent

1

This SO question responde a la parte PKCS # 8 de su código. El resto de las clases RSA de .NET son una extraña mezcla de clases parcialmente superpuestas que son muy difíciles de comprender. Ciertamente, parece que el soporte de firmas se encuentra en cualquiera de las clases RSACryptoServiceProvider y/o RSAPKCS1SignatureFormatter.

1

Descargo de responsabilidad: Sé Java y la criptografía, pero mi conocimiento de C# y .NET es muy limitado. Estoy escribiendo aquí solo bajo la influencia de mis habilidades de Google-fu.

Suponiendo que se podía descifrar una clave privada RSA PKCS # 8 codificado, a continuación, por lo que leí en MSDN, el resto del código debería tener este aspecto:

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

Las clases pertinentes están en el espacio de nombre System.Security.Cryptography.

En cuanto a la decodificación de blob de clave PKCS # 8 (es decir, rellenando los campos rsp), encontré this page que describe una utilidad de línea de comandos en C# que puede realizar ese trabajo. El código fuente se proporciona y es un único archivo C#. Por lo que leo en él, ese código decodifica el archivo PKCS # 8 "manualmente"; indirectamente, esto debería significar que .NET (2.0) en bruto no tiene facilidades para la decodificación del archivo de claves PKCS # 8 (de lo contrario, el autor de esa herramienta no se habría tomado la molestia de implementar dicha decodificación). Para la tarea que tiene entre manos, puede eliminar de ese archivo fuente las piezas que necesita, omitiendo todo lo relacionado con PEM y el cifrado simétrico; su punto de entrada sería la función DecodePrivateKeyInfo(), que aparentemente espera un archivo PKCS # 8 no cifrado DER codificado, al igual que el PKCS8EncodedKeySpec de Java.

+0

Tim, mantén la calma, estoy verificando todas las respuestas – balint

9

Otra forma es utilizar GNC (criptografía de próxima generación), junto con la seguridad.DLL de la criptografía de CodePlex

A continuación, se puede escribir:

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

Actualizado gracias a Simon Mourier: con .Net 4.6, que ya no necesita una biblioteca separada

+0

¡Nunca escuché esto antes! ¿Conoces ejemplos adicionales? – LamonteCristo

+0

Hay ejemplos en la revista MSDN: http://msdn.microsoft.com/en-us/magazine/cc163389.aspx – Timores

+1

Tenga en cuenta que esto ahora está incluido en .NET Framework 4.6. Este es realmente el camino a seguir para los desarrollos .NET de hoy. –

0

Puede utilizar este código. Al principio, debería descargar "BouncyCastle.Crypto.dll" de 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); 
    } 
} 
Cuestiones relacionadas