Página 1 de 1

Problemas al generar sello con librería OpenSSLKey.cs

Publicado: Sab Jun 04, 2016 6:58 pm
por QenK
Hola, estoy usando la librería OpenSSLKey en C# para generar el sello digital a partir del .key del CSD y la cadena original. Hasta ahora no había tenido ningún problema, pero me acaba de llegar un cliente que usa CSD de los nuevos de 2048 (no sé si tenga algo que ver) y ahora ya no me funciona. Este es el código que estoy usando:

Código: Seleccionar todo

           SecureString passwordSeguro = new SecureString();
                    passwordSeguro.Clear();
                    foreach (char c in porg.PassLlavePrivada.ToCharArray())
                        passwordSeguro.AppendChar(c);
                    RSACryptoServiceProvider rsa = opensslkey.DecodeEncryptedPrivateKeyInfo(porg.LlavePrivada, passwordSeguro);
                    SHA1CryptoServiceProvider hasher = new SHA1CryptoServiceProvider();
                    byte[] bytesFirmados = rsa.SignData(Encoding.UTF8.GetBytes(strCadenaOriginal), hasher);
                    sello = Convert.ToBase64String(bytesFirmados);


porg.LlavePrivada contiene el .key sin alterar.
porg.PassLlavePrivada es la contraseña de llave privada.

El problema es que al llamar al método DecodeEncryptedPrivateKeyInfo, éste devuelve null, que es lo que normalmente ocurre cuando la contraseña no coincide con el .key, sin embargo he validado con el ValidaCFD que efectivamente sí se corresponden, entonces no sé que otra cosa pueda ser.

¿Alguien sabe a qué puede deberse? O alguien que me pueda pasar un ejemplo con otra librería (Bouncycastle u otra), tal vez cambiando el método se solucione el problema.

Gracias y saludos.

Re: Problemas al generar sello con librería OpenSSLKey.cs

Publicado: Lun Jun 06, 2016 1:25 pm
por QenK
bueno, después de varios días clavado en esto, por fin he dado con la solución.

Parece ser que la librería OpenSSLKey.cs tiene algún tipo de problema que hace que no funcione el firmado con determinadas llaves.

La solución es utilizar la librería BouncyCastle en su lugar.

Dejo el código por si le sirve a alguien.

Código: Seleccionar todo


// 1) Desencriptar la llave privada, el primer parametro es la contraseña de llave privada y el segundo es la llave privada en formato binario.
Org.BouncyCastle.Crypto.AsymmetricKeyParameter asp = Org.BouncyCastle.Security.PrivateKeyFactory.DecryptKey(porg.PassLlavePrivada.ToCharArray(), porg.LlavePrivada);

// 2) Convertir a parámetros de RSA
Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters key = (Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters)asp;

// 3) Crear el firmador con SHA1
Org.BouncyCastle.Crypto.ISigner sig = Org.BouncyCastle.Security.SignerUtilities.GetSigner("SHA1withRSA");

// 4) Inicializar el firmador con la llave privada
sig.Init(true, key);

// 5) Pasar la cadena original a formato binario
byte[] bytes = Encoding.UTF8.GetBytes(strCadenaOriginal);

// 6) Encriptar
sig.BlockUpdate(bytes, 0, bytes.Length);
byte[] bytesFirmados = sig.GenerateSignature();

// 7) Finalmente obtenemos el sello
sello = Convert.ToBase64String(bytesFirmados);


Re: Problemas al generar sello con librería OpenSSLKey.cs

Publicado: Jue Dic 15, 2016 10:42 am
por javiergalindor
Gracias por el código. Yo también estaba usando la librería OpenSSLKey.cs e igual que a ti me pasó que para una llave de prueba que tengo en particular no me funcionó pero con la librería BouncyCastle sí.

Re: Problemas al generar sello con librería OpenSSLKey.cs

Publicado: Lun Ago 28, 2017 9:37 am
por Cexti
He tenido el mismo problema con solo algunos certificados y de momento lo que realicé fue generar un nuevo CSD y asunto arreglado.

Este fin de semana tuve la necesidad de investigar a fondo ya que no era posible esperar a generar otro CSD y logré resolverlo; ya lo probé con varios casos y funciona correcto.

El problema es con este metodo:

Dim rsa As RSACryptoServiceProvider = opensslkey.DecodeEncryptedPrivateKeyInfo(llavePrivadaBytes, passwordSeguro)

Se produce un error, regresa nulo y por lo mismo no puede firmar la cadena original, la solucuón es dentro de un metodo que existe y el cual anexo. Por alguna causa los parámetros no tienen la longitud correcta y solo se rellena para cubrir el tamaño y con eso no marque error, utilizando la función ConvertRSAParametersField(byte[] bs, int size) que aparece al final

Código: Seleccionar todo

        //------- Parses binary ans.1 RSA private key; returns RSACryptoServiceProvider  ---
        public static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
        {
            byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;

            // ---------  Set up stream to decode the asn.1 encoded RSA private key  ------
            MemoryStream mem = new MemoryStream(privkey);
            BinaryReader binr = new BinaryReader(mem);    //wrap Memory Stream with BinaryReader for easy reading
            byte bt = 0;
            ushort twobytes = 0;
            int elems = 0;
            try
            {
                twobytes = binr.ReadUInt16();
                if (twobytes == 0x8130)   //data read as little endian order (actual data order for Sequence is 30 81)
                    binr.ReadByte();   //advance 1 byte
                else if (twobytes == 0x8230)
                    binr.ReadInt16();   //advance 2 bytes
                else
                    return null;

                twobytes = binr.ReadUInt16();
                if (twobytes != 0x0102)   //version number
                    return null;
                bt = binr.ReadByte();
                if (bt != 0x00)
                    return null;


                //------  all private key components are Integer sequences ----
                elems = GetIntegerSize(binr);
                MODULUS = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                E = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                D = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                P = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                Q = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                DP = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                DQ = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                IQ = binr.ReadBytes(elems);

                Console.WriteLine("showing components ..");
                if (verbose)
                {
                    showBytes("\nModulus", MODULUS);
                    showBytes("\nExponent", E);
                    showBytes("\nD", D);
                    showBytes("\nP", P);
                    showBytes("\nQ", Q);
                    showBytes("\nDP", DP);
                    showBytes("\nDQ", DQ);
                    showBytes("\nIQ", IQ);
                }

                // ------- create RSACryptoServiceProvider instance and initialize with public key -----
                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
                RSAParameters RSAparams = new RSAParameters();
                RSAparams.Modulus = MODULUS;
                RSAparams.Exponent = E;
                RSAparams.P = P;
                RSAparams.Q = Q;
                //Valores Originales
                //RSAparams.D = D;
                //RSAparams.DP = DP;
                //RSAparams.DQ = DQ;
                //RSAparams.InverseQ = IQ;
                //Ajuste realizado cuando algunos CSD marca error
                RSAparams.D = ConvertRSAParametersField(D, MODULUS.Length);
                RSAparams.DP = ConvertRSAParametersField(DP, P.Length);
                RSAparams.DQ = ConvertRSAParametersField(DQ, Q.Length);
                RSAparams.InverseQ = ConvertRSAParametersField(IQ, Q.Length);
                RSA.ImportParameters(RSAparams);
                return RSA;
            }
            catch (Exception e)
            {
                Console.WriteLine("Problem decrypting: {0}", e.Message);
                return null;
            }
            finally { binr.Close(); }
        }

        private static byte[] ConvertRSAParametersField(byte[] bs, int size)
        {
            if (bs.Length == size)
                return bs;
            if (bs.Length > size)
                throw new ArgumentException("Specified size too small", "size");
            byte[] padded = new byte[size];
            Array.Copy(bs, 0, padded, size - bs.Length, bs.Length);
            return padded;
        }

Espero les pueda servir ya que es un tema que lleva mucho tiempo, saludos a todos y suerte

Re: Problemas al generar sello con librería OpenSSLKey.cs

Publicado: Dom Sep 24, 2017 3:33 pm
por cemani
Luis

tu código marca error en la sección del if verbose y las instrucciones showbytes

Código: Seleccionar todo

       if (verbose)
                {
                    showBytes("\nModulus", MODULUS);
                    showBytes("\nExponent", E);
                    showBytes("\nD", D);
                    showBytes("\nP", P);
                    showBytes("\nQ", Q);
                    showBytes("\nDP", DP);
                    showBytes("\nDQ", DQ);
                    showBytes("\nIQ", IQ);
                }

Ni verbose ni showBytes existen en el contexto actual.

Solo reemplacé el método que indicas y agregué el método adicional que mencionas.

¿Podrías revisarlo o decirme por favor como eliminar el error?

Gracias e antemano

Re: Problemas al generar sello con librería OpenSSLKey.cs

Publicado: Dom Nov 05, 2017 11:44 am
por Dado
Aqui en ValidaCFD tenemos una libreria DLL que te permite sellar y timbrar tu XML en un solo paso

Checa la informacion aqui, puedes descargar una DEMO de dicha dll, en la demo vienen ejemplos de programacion en varios lenaguajes