Criptografía en Ruby: Desventajas frente a Java y .NET

Aunque Ruby es un lenguaje expresivo y productivo, especialmente popular en el desarrollo web con Ruby on Rails, presenta desventajas claras frente a plataformas como Java y .NET cuando se trata de implementar soluciones criptográficas complejas. 

1. Enfoque del lenguaje y comunidad

Ruby ha sido históricamente popular para desarrollo web (especialmente con Rails), automatización y scripting, no tanto para sistemas de bajo nivel, criptografía o aplicaciones de misión crítica donde el rendimiento criptográfico es clave. Java y .NET, en cambio, han sido usados más extensivamente en entornos corporativos donde la criptografía es un requerimiento común (banca, firmas digitales, etc.).

🔐 2. Bibliotecas disponibles en Ruby

Aunque no son tan completas como las de Java/.NET, sí existen bibliotecas para tareas criptográficas básicas:

  • OpenSSL: Ruby incluye bindings a la biblioteca OpenSSL, lo que permite trabajar con cifrado simétrico, asimétrico, firmas, certificados, etc.

  • RbNaCl: Una implementación moderna y segura basada en libsodium (más amigable y segura que usar OpenSSL directamente).

  • jwt: Para firmar y verificar tokens JWT.

  • bcrypt: Para hashing de contraseñas.

Pero muchas de estas bibliotecas son wrappers alrededor de código en C, y en general no hay una API tan pulida y rica como las de Java (java.securityjavax.crypto) o .NET (System.Security.Cryptography).

⚙️ 3. Rendimiento

Las herramientas criptográficas en Java y .NET suelen estar altamente optimizadas. En Ruby, el rendimiento criptográfico puede ser una preocupación en aplicaciones de alto tráfico o que requieren operaciones pesadas.

Ruby puede ayudarte a calcular un timbre electrónico (por ejemplo, para documentos tributarios en Chile, como el TED del SII), porque eso suele involucrar hashing (SHA1 o SHA256) y codificación Base64 — cosas que Ruby puede manejar perfectamente, especialmente con OpenSSL y las funciones estándar.

Pero cuando se trata de manejar certificados PFX (.p12), incluyendo:

  • Leer el contenido del PFX.

  • Extraer la clave privada y el certificado.

  • Usar la clave para firmar documentos XML (como hace el SII con XMLDsig).

  • Firmar con algoritmos como RSA-SHA1, RSA-SHA256.

  • Manejar estructuras PKCS#7 o X.509 complejas.

Ruby se queda corto o es mucho más engorroso, porque:

  1. No tiene una API nativa clara para manipular archivos .p12/.pfx (como Java con KeyStore o .NET con X509Certificate2).

  2. La manipulación de claves privadas y certificados suele requerir usar directamente OpenSSL desde Ruby, lo que se vuelve poco mantenible y propenso a errores.

  3. No existen librerías maduras para firmar XML como java.xml.crypto en Java o SignedXml en .NET.


✅ En cambio, Java ofrece:

  • KeyStore para cargar .pfx fácilmente.

  • PrivateKey, X509Certificate, y Signature para firmar documentos.

  • Bibliotecas como Apache Santuario para firmar XML con estándares como XMLDSig.

  • Módulos bien probados, estables y usados por instituciones financieras, gobiernos y empresas grandes.


🔧 Ejemplo práctico

En Ruby puedes hacer esto sin problemas:


require 'openssl' require 'base64' digest = OpenSSL::Digest::SHA1.new data = "<DD><RE>...</RE>...</DD>" hash = Base64.encode64(digest.digest(data)).strip

Pero si necesitas:

  • Firmar ese XML con un pfx.

  • Agregar la firma en formato SignedInfo, SignatureValue, etc.

→ Necesitarías Java o .NET sí o sí.


¿Estás desarrollando algo como un firmador XML para DTE en Ruby y te estás topando con este límite?

En Ruby, la única forma práctica de trabajar con un .pfx o .p12 es extraer manualmente la clave privada y el certificado y convertirlos a formato PEM usando openssl por consola o mediante scripts. Pero eso implica:

🛠️ 1. Intervención manual en la configuración de OpenSSL

Debes usar comandos como:


openssl pkcs12 -in certificado.pfx -out clave_privada.pem -nocerts -nodes openssl pkcs12 -in certificado.pfx -out certificado.pem -clcerts -nokeys

Y luego cargar esos archivos .pem desde Ruby con:


key = OpenSSL::PKey::RSA.new(File.read("clave_privada.pem")) cert = OpenSSL::X509::Certificate.new(File.read("certificado.pem"))

⚠️ 2. Riesgos de seguridad y mantenimiento

  • Dejas los archivos PEM en disco plano, lo cual puede ser riesgoso si no se protegen bien.

  • Tienes que coordinar fuera del código la exportación desde el PFX.

  • No es portable ni ideal para entornos productivos automatizados.


🚫 3. No puedes firmar XML estructurado fácilmente

Incluso con PEMs cargados en memoria, Ruby no tiene soporte directo para:

  • Generar un SignedInfo con canonicalización XML.

  • Firmar el DigestValue y colocar correctamente el SignatureValue.

  • Insertar la firma en un DocumentFragment del XML como lo requiere el SII.


✅ En Java o .NET:

Eso se hace directo desde el .pfx y todo está integrado con las APIs estándar.


Comentarios

Entradas populares de este blog

Creación de un DTE de boleta electrónica usando AppDTE Api:

Guía de Consulta de DTE

¡Nuevo Entorno de Pruebas Disponible para AppDTE API!