c# - ejemplo - CryptographicException "Clave no válida para usar en un estado específico" mientras intenta exportar RSAParameters de una clave privada X509
rsa c# ejemplo (6)
AFAIK esto debería funcionar y es probable que tengas un error / algunas limitaciones. Aquí hay algunas preguntas que pueden ayudarlo a descubrir dónde está el problema.
¿Cómo se creó el archivo PKCS # 12 (PFX)? He visto algunas claves que a CryptoAPI no le gustan (parámetros RSA poco comunes). ¿Puedes usar otra herramienta (solo para estar seguro)?
¿Se puede exportar la instancia de
PrivateKey
a XML, por ejemplo,ToXmlString(true)
, y luego cargarla (importar) de nuevo?Las versiones anteriores del marco tenían algunos problemas al importar una clave que tenía un tamaño diferente al de la instancia actual (por defecto a 1024 bits). ¿Cuál es el tamaño de su clave pública RSA en su certificado?
También tenga en cuenta que esta no es la forma en que debe cifrar los datos utilizando RSA. El tamaño del cifrado sin formato se limita a la clave pública que se utiliza. Looping por encima de este límite solo le daría un rendimiento realmente malo.
El truco es usar un algoritmo simétrico (como AES ) con una clave totalmente aleatoria y luego encriptar esta clave (wrap) usando la clave pública RSA. Puede encontrar el código C # para hacerlo en mi antigua entrada de blog sobre el tema.
Estoy mirando esto por un buen rato y gracias a la documentación de MSDN no puedo entender qué está pasando. Básicamente estoy cargando un archivo PFX del disco en un X509Certificate2
e intento encriptar una cadena usando la clave pública y descifrarla usando la clave privada.
¿Por qué estoy desconcertado? El cifrado / descifrado funciona cuando paso la referencia al propio RSACryptoServiceProvider
:
byte[] ed1 = EncryptRSA("foo1", x.PublicKey.Key as RSACryptoServiceProvider);
string foo1 = DecryptRSA(ed1, x.PrivateKey as RSACryptoServiceProvider);
Pero si exporta y pasa el RSAParameter
:
byte[] ed = EncryptRSA("foo", (x.PublicKey.Key as RSACryptoServiceProvider).ExportParameters(false));
string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider).ExportParameters(true));
... arroja una "clave no válida para usar en un estado específico". excepción al intentar exportar la clave privada a RSAParameter
. Tenga en cuenta que el certificado del que se genera el PFX está marcado como exportable (es decir, utilicé el indicador pe al crear el certificado). ¿Alguna idea de qué está causando la excepción?
static void Main(string[] args)
{
X509Certificate2 x = new X509Certificate2(@"C:/temp/certs/1/test.pfx", "test");
x.FriendlyName = "My test Cert";
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
try
{
store.Add(x);
}
finally
{
store.Close();
}
byte[] ed1 = EncryptRSA("foo1", x.PublicKey.Key as RSACryptoServiceProvider);
string foo1 = DecryptRSA(ed1, x.PrivateKey as RSACryptoServiceProvider);
byte[] ed = EncryptRSA("foo", (x.PublicKey.Key as RSACryptoServiceProvider).ExportParameters(false));
string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider).ExportParameters(true));
}
private static byte[] EncryptRSA(string data, RSAParameters rsaParameters)
{
UnicodeEncoding bytConvertor = new UnicodeEncoding();
byte[] plainData = bytConvertor.GetBytes(data);
RSACryptoServiceProvider publicKey = new RSACryptoServiceProvider();
publicKey.ImportParameters(rsaParameters);
return publicKey.Encrypt(plainData, true);
}
private static string DecryptRSA(byte[] data, RSAParameters rsaParameters)
{
UnicodeEncoding bytConvertor = new UnicodeEncoding();
RSACryptoServiceProvider privateKey = new RSACryptoServiceProvider();
privateKey.ImportParameters(rsaParameters);
byte[] deData = privateKey.Decrypt(data, true);
return bytConvertor.GetString(deData);
}
private static byte[] EncryptRSA(string data, RSACryptoServiceProvider publicKey)
{
UnicodeEncoding bytConvertor = new UnicodeEncoding();
byte[] plainData = bytConvertor.GetBytes(data);
return publicKey.Encrypt(plainData, true);
}
private static string DecryptRSA(byte[] data, RSACryptoServiceProvider privateKey)
{
UnicodeEncoding bytConvertor = new UnicodeEncoding();
byte[] deData = privateKey.Decrypt(data, true);
return bytConvertor.GetString(deData);
}
Solo para aclarar en el código anterior, la parte en negrita está lanzando: string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider)**.ExportParameters(true)**);
Creo que el problema puede ser que la clave no está marcada como exportable. Hay otro constructor para X509Certificate2
que toma una enumeración X509KeyStorageFlags. Intenta reemplazar la línea:
X509Certificate2 x = new X509Certificate2(@"C:/temp/certs/1/test.pfx", "test");
Con este:
X509Certificate2 x = new X509Certificate2(@"C:/temp/certs/1/test.pfx", "test", X509KeyStorageFlags.Exportable);
Me he encontrado con un problema similar, y X509KeyStorageFlags.Exportable
resolvió mi problema.
No soy exactamente un experto en estas cosas, pero hice un Google rápido, y encontré esto:
http://social.msdn.microsoft.com/Forums/en/clr/thread/4e3ada0a-bcaf-4c67-bdef-a6b15f5bfdce
"si tiene más de 245 bytes en su matriz de bytes que pasa a su método RSACryptoServiceProvider.Encrypt (byte [] rgb, bool fOAEP) arrojará una excepción".
Para el problema que encontré, un cambio de código no era una opción, ya que la misma biblioteca estaba instalada y funcionaba en otro lugar.
La respuesta de Iridium me llevó a buscar exportar la clave y pude hacerlo como parte del Asistente de importación de certificados de MMC.
Espero que esto ayude a alguien más. Montones de gracias
Para otros que terminan aquí a través de Google, pero no usan ningún X509Certificate2, si llama a ToXmlString en RSACryptoServiceProvider pero solo ha cargado una clave pública, recibirá este mensaje también. La solución es esta (observe la última línea):
var rsaAlg = new RSACryptoServiceProvider();
rsaAlg.ImportParameters(rsaParameters);
var xml = rsaAlg.ToXmlString(!rsaAlg.PublicOnly);