Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

623
Vistas
Cifrar datos en Javascript, Descifrar datos en C# usando claves privadas/públicas

Quiero cifrar datos en un navegador web que se envía a mi backend C# y se descifra allí.

Eso falla porque no puedo descifrar los datos generados en el frontend en el backend.

Esto es lo que hice hasta ahora.

Primero creé un par de claves privadas/públicas (en formato XmlString). Tomé la función ExportPublicKey para generar el archivo de clave pública desde aquí: https://stackoverflow.com/a/28407693/98491

 private static void GeneratePrivatePublicKeyPair() { var name = "test"; var privateKeyXmlFile = name + "_priv.xml"; var publicKeyXmlFile = name + "_pub.xml"; var publicKeyFile = name + ".pub"; using var provider = new RSACryptoServiceProvider(1024); File.WriteAllText(privateKeyXmlFile, provider.ToXmlString(true)); File.WriteAllText(publicKeyXmlFile, provider.ToXmlString(false)); using var publicKeyWriter = File.CreateText(publicKeyFile); ExportPublicKey(provider, publicKeyWriter); }

Ahora puedo usar la clave pública para cifrar datos en mi interfaz.

 (() => { const publicKey = `-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGy8btrbnSNPz7vWKfQXKxKXzg 28ZD8jCAd7gGYfUIFqKqUcogHWt5gyGvTgEhwBwBP1kYrVnBlhB2nuWHLYpJDI6b uBoqKrHtrcdgXsKumSP0OKpn0nbYxknOvNYVjUUR6plMboUBaWX1oKoR6pNzTEHS al4bIU7XMwppkR3KNQIDAQAB -----END PUBLIC KEY-----`; function getSpkiDer(spkiPem) { const pemHeader = "-----BEGIN PUBLIC KEY-----"; const pemFooter = "-----END PUBLIC KEY-----"; var pemContents = spkiPem.substring( pemHeader.length, spkiPem.length - pemFooter.length ); var binaryDerString = window.atob(pemContents); return str2ab(binaryDerString); } async function importPublicKey(spkiPem) { return await window.crypto.subtle.importKey( "spki", getSpkiDer(spkiPem), { name: "RSA-OAEP", hash: "SHA-256", }, true, ["encrypt"] ); } async function encryptRSA(key, plaintext) { let encrypted = await window.crypto.subtle.encrypt( { name: "RSA-OAEP", }, key, plaintext ); return encrypted; } function str2ab(str) { const buf = new ArrayBuffer(str.length); const bufView = new Uint8Array(buf); for (let i = 0, strLen = str.length; i < strLen; i++) { bufView[i] = str.charCodeAt(i); } return buf; } function ab2str(buf) { return String.fromCharCode.apply(null, new Uint8Array(buf)); } async function encrypt(plaintext) { const pub = await importPublicKey(publicKey); const encrypted = await encryptRSA( pub, new TextEncoder().encode(plaintext) ); const encryptedBase64 = window.btoa(ab2str(encrypted)); console.log(encryptedBase64); } encrypt("I want to decrypt this string in C#"); })();

Sin embargo: si quiero descifrar el código en mi backend nuevamente, esto falla

 private static void Decrypt() { var name = "test"; var encryptedBase64 = @"Rzabx5380rkx2+KKB+HaJP2dOXDcOC7SkYOy4HN8+Nb9HmjqeZfGQlf+ZUa6uAfAJ3oAB2iIlHlnx+iXK3XDIX3izjoW1eeiNmdOWieNCu6YXqW4denUVEv0Z4EpAmEYgVImnEzoMdmPDEcl9UHgdWUmS4Bnq6T8Yqh3UZ/4NOc="; var encrypted = Convert.FromBase64String(encryptedBase64); using var privateKey = new RSACryptoServiceProvider(); privateKey.FromXmlString(File.ReadAllText(name + "_priv.xml")); var decryptedBytes = privateKey.Decrypt(encrypted, false); var dectryptedText = Encoding.UTF8.GetString(decryptedBytes); }

privateKey.Decrypt(encrypted, false); que lanza

 Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Wrong parameter CapiHelper.DecryptKey(SafeKeyHandle safeKeyHandle, Byte[] encryptedData, Int32 encryptedDataLength, Boolean fOAEP, Byte[]& decryptedData) RSACryptoServiceProvider.Decrypt(Byte[] rgb, Boolean fOAEP)

y privateKey.Decrypt(encrypted, false); que lanza

 System.Security.Cryptography.CryptographicException: Cryptography_OAEPDecoding, CapiHelper.DecryptKey(SafeKeyHandle safeKeyHandle, Byte[] encryptedData, Int32 encryptedDataLength, Boolean fOAEP, Byte[]& decryptedData) RSACryptoServiceProvider.Decrypt(Byte[] rgb, Boolean fOAEP)

Nota: Verifiqué que puedo cifrar/descifrar con éxito los datos en el backend con las claves privadas/públicas en formato xml.

Y verifiqué que puedo cifrar/descifrar con éxito los datos en la interfaz con el

claves privadas/públicas en formato PEM.

Lo que no funciona es descifrar una cadena en C# que está cifrada en la interfaz con javascript.

¿Qué estoy haciendo mal?

Para referencia (recién generado para este propósito)

llave privada

 -----BEGIN PRIVATE KEY----- MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAMbLxu2tudI0/Pu9 Yp9BcrEpfODbxkPyMIB3uAZh9QgWoqpRyiAda3mDIa9OASHAHAE/WRitWcGWEHae 5YctikkMjpu4Gioqse2tx2Bewq6ZI/Q4qmfSdtjGSc681hWNRRHqmUxuhQFpZfWg qhHqk3NMQdJqXhshTtczCmmRHco1AgMBAAECgYEAokAVN02wOQm4ZPp4cMSpCEF1 Q8z8L96OiXusvcDbjWN0FhC1KKr6We2V44+FyvcRpE8At+xcMmz5OOeNLFwV3QLZ GOYjZXP5dmRC3mG7HOv0Iu4QqAQCMEzLf998+6RwA24U74ysm+6CVCeVWZLtJSi/ UdQm3jho086iQF9UOo0CQQDjjhZl/fOqqb9nvW3rvSNwsdzSYoGpfx22uzrJplN2 wpFO6XCorAGMO6lHI3Ua8A0OSNO1ybkhG2iZOkPoEGWHAkEA36VhsUFNQr4RO7gL oWpB+D2QtciZjnHm+QGRlfDl1mq527LHnHURrBQVRcHR3OgQbJ1wsSi4IjcKJ3l6 EtcBYwJBAKRTtIsc1D0XbljdLCcEJDa6yuvHJTmgyXVvSenbSgTGRycEX03/QPLj FsB/s46rcdIx92kc7qsg3u1gbS+Fv7sCQQC5QHaxqxPiayo/O2524FuQ0v5hda6s rXDTZhdACnF3sKQPdgGeeeKPlXshczDxOVERh0BnnwEXZlwE4rzZijtdAkEA2gXb e/4gNIAuowBdgs1nXtuLKTP/HJzPIfil6zcF82Jc5dy7lR7nJCl088w0t1a0ebx5 LrC2qjX4SMEUbMTkNg== -----END PRIVATE KEY-----`

Llave pública

 -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGy8btrbnSNPz7vWKfQXKxKXzg 28ZD8jCAd7gGYfUIFqKqUcogHWt5gyGvTgEhwBwBP1kYrVnBlhB2nuWHLYpJDI6b uBoqKrHtrcdgXsKumSP0OKpn0nbYxknOvNYVjUUR6plMboUBaWX1oKoR6pNzTEHS al4bIU7XMwppkR3KNQIDAQAB -----END PUBLIC KEY-----

clave privada xml

 <RSAKeyValue><Modulus>xsvG7a250jT8+71in0FysSl84NvGQ/IwgHe4BmH1CBaiqlHKIB1reYMhr04BIcAcAT9ZGK1ZwZYQdp7lhy2KSQyOm7gaKiqx7a3HYF7Crpkj9DiqZ9J22MZJzrzWFY1FEeqZTG6FAWll9aCqEeqTc0xB0mpeGyFO1zMKaZEdyjU=</Modulus><Exponent>AQAB</Exponent><P>444WZf3zqqm/Z71t670jcLHc0mKBqX8dtrs6yaZTdsKRTulwqKwBjDupRyN1GvANDkjTtcm5IRtomTpD6BBlhw==</P><Q>36VhsUFNQr4RO7gLoWpB+D2QtciZjnHm+QGRlfDl1mq527LHnHURrBQVRcHR3OgQbJ1wsSi4IjcKJ3l6EtcBYw==</Q><DP>pFO0ixzUPRduWN0sJwQkNrrK68clOaDJdW9J6dtKBMZHJwRfTf9A8uMWwH+zjqtx0jH3aRzuqyDe7WBtL4W/uw==</DP><DQ>uUB2sasT4msqPztuduBbkNL+YXWurK1w02YXQApxd7CkD3YBnnnij5V7IXMw8TlREYdAZ58BF2ZcBOK82Yo7XQ==</DQ><InverseQ>2gXbe/4gNIAuowBdgs1nXtuLKTP/HJzPIfil6zcF82Jc5dy7lR7nJCl088w0t1a0ebx5LrC2qjX4SMEUbMTkNg==</InverseQ><D>okAVN02wOQm4ZPp4cMSpCEF1Q8z8L96OiXusvcDbjWN0FhC1KKr6We2V44+FyvcRpE8At+xcMmz5OOeNLFwV3QLZGOYjZXP5dmRC3mG7HOv0Iu4QqAQCMEzLf998+6RwA24U74ysm+6CVCeVWZLtJSi/UdQm3jho086iQF9UOo0=</D></RSAKeyValue>

clave pública xml

 <RSAKeyValue><Modulus>xsvG7a250jT8+71in0FysSl84NvGQ/IwgHe4BmH1CBaiqlHKIB1reYMhr04BIcAcAT9ZGK1ZwZYQdp7lhy2KSQyOm7gaKiqx7a3HYF7Crpkj9DiqZ9J22MZJzrzWFY1FEeqZTG6FAWll9aCqEeqTc0xB0mpeGyFO1zMKaZEdyjU=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>

Actualizar

Solo para dejar en claro lo que quiero lograr. Soy consciente de que usar un privado en un navegador puede ser una mala idea. Pero en mi caso esto es obligatorio:

aplicación 1

Aplicación web interna que necesita escribir datos cifrados en una etiqueta NDEF utilizando la API web NFC y es la que necesita la clave privada.

aplicación 2

Aplicación web que lee los datos cifrados de la etiqueta NEDF y los transfiere a una aplicación web .NET (aplicación 3)

aplicación 3

Lee los datos cifrados de la aplicación 2 y los descifra.

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

Debe cifrar con la clave privada y luego descifrar con la clave pública

over 4 years ago · Santiago Trujillo Denunciar

0

Ambos códigos usan rellenos diferentes, en el lado de JavaScript OAEP (con SHA256), en el lado de C# PKCS#1 v1.5. Para que el descifrado sea posible en el lado de C#, allí también se debe usar OAEP con SHA256.

No ha especificado una versión de .NET. Bajo .NET Core 3.0+ o .NET 5+ el descifrado es posible, por ejemplo, con:

 ... using var privateKey = RSA.Create(); ... var decryptedBytes = privateKey.Decrypt(encrypted, RSAEncryptionPadding.OaepSHA256); ...

y da como texto sin formato para el texto cifrado y las claves publicados: El conejito salta a la hora del té .


RSACryptoServiceProvider.Decrypt(Byte[], Boolean) usa PKCS#1 v1.5 si el segundo parámetro se establece en false . Si el segundo parámetro se establece en true , se aplica OAEP, pero con SHA1.

RSACryptoServiceProvider.Decrypt(Byte[], RSAEncryptionPadding) permite configurar OAEP con SHA256, pero se produce un error de tiempo de ejecución porque solo se admite SHA1 (ver Observaciones ).

Por lo tanto, es necesario un cambio a, por ejemplo RSA.Decrypt(Byte[], RSAEncryptionPadding) para OAEP con SHA256.

over 4 years ago · Santiago Trujillo Denunciar

0

Además de la respuesta correcta de @Topaco, el descifrado aún es posible en versiones anteriores de .NET cambiando el algoritmo hash a SHA-1 tanto en Javascript como en C# de la siguiente manera:

 async function importPublicKey(spkiPem) { return await window.crypto.subtle.importKey( "spki", getSpkiDer(spkiPem), { name: "RSA-OAEP", hash: "SHA-1", //// <- SHA-1 here for older .NET decryption }, true, ["encrypt"] ); }

y

 using (var privateKey = RSA.Create()) { privateKey.FromXmlString(privKey); var dectryptedBytes = privateKey.Decrypt(encrypted, RSAEncryptionPadding.OaepSHA1); // ^^^^^^^^^ OaepSHA1 here for older versions of .NET ^^^^^^ var dectryptedText = Encoding.UTF8.GetString(dectryptedBytes); }
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda