Problemas al generar sello con librería OpenSSLKey.cs

Es tan comun este tema que he decidido abrir un foro especial para este caso. Se trata de programadores que tienen problemas para crear el Sello Digital y que no pasan la validacion
QenK
Mensajes: 53
Registrado: Jue Ene 02, 2014 9:03 pm

Problemas al generar sello con librería OpenSSLKey.cs

Mensajepor QenK » Sab Jun 04, 2016 7:58 pm

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.

QenK
Mensajes: 53
Registrado: Jue Ene 02, 2014 9:03 pm

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

Mensajepor QenK » Lun Jun 06, 2016 2:25 pm

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


javiergalindor
Mensajes: 1
Registrado: Jue Dic 15, 2016 11:37 am

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

Mensajepor javiergalindor » Jue Dic 15, 2016 11:42 am

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í.

Cexti
Mensajes: 2
Registrado: Jue Jun 22, 2017 1:09 pm

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

Mensajepor Cexti » Lun Ago 28, 2017 10:37 am

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
Saludos...
Luis M

cemani
Mensajes: 1
Registrado: Dom Sep 24, 2017 4:29 pm

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

Mensajepor cemani » Dom Sep 24, 2017 4:33 pm

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

Avatar de Usuario
Dado
Mensajes: 15824
Registrado: Mar Jul 06, 2010 8:56 pm

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

Mensajepor Dado » Dom Nov 05, 2017 12:44 pm

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
ADDENDAS? VALIDACION? CODIGO PARA PROGRAMAR TU PROPIA SOLUCION? TODO LO TENEMOS EN WWW.VALIDACFD.COM VISITANOS !!


Volver a “SELLO DIGITAL INVALIDO”

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 5 invitados