2012-02-14 17 views
16

En pocas palabras, este es mi problema:base 64 codificados de clave pública para verificar la firma RSA

private string publicKeyString = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVGUzbydMZS+fnkGTsUkDKEyFOGwghR234d5GjPnMIC0RFtXtw2tdcNM8I9Qk+h6fnPHiA7r27iHBfdxTP3oegQJWpbY2RMwSmOs02eQqpKx4QtIjWqkKk2Gmck5cll9GCoI8AUAA5e0D02T0ZgINDmo5yGPhGAAmqYrm8YiupwQIDAQAB"; 

/* Some transformation required, using publicKeyString to initiate a new RSACryptoServiceProvider object 
*/ 

//for now: 
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); 

byte[] selfComputedHash = new byte[]; //left out of the example 
byte[] signature = new byte[]; 

bool result = rsa.VerifyHash(selfComputedHash, CryptoConfig.MapNameToOID("SHA1"), signature); 

Como se puede ver, el problema está iniciando una nueva RSACryptoServiceProvider con la cadena de clave pública dada codificada en Base64. Pude hacer la creación de instancias usando un objeto RSAParameters, cargado con byte [] para Módulo y Exponente derivado de esta cadena de clave pública usando un comando de shell OpenSSL. Pero dado que esta clave pública puede cambiar en el futuro, quiero poder almacenarla en su forma original en una base de datos. Debe haber una manera más directa de lidiar con esto.

Muchos de los ejemplos que he leído hasta ahora evitan este problema exportando e importando las claves privadas y públicas generadas hacia y desde un objeto contenedor de clave y utilizándolo en el mismo código y por lo tanto no transfiriendo 'la clave en alguna cadena forma fuera de memoria. Algunas personas han expresado el mismo problema, tanto aquí en StackOverflow como en otros sitios, pero todavía no he podido encontrar una respuesta satisfactoria.

Cualquier idea es más que bienvenida.

Información de fondo: Mi compañero de comunicación calcula un SHA1-hash de 20 bytes a partir de una cadena de entrada de longitud variable, compuesta de la información contenida en varios campos de un mensaje codificado en ASCII. Este hash está firmado por RSA con la clave privada de mi compañero y enviado junto con el mensaje ASCII. Al llegar, calculo el hash SHA1 yo mismo, usando los mismos campos del mensaje ASCII y luego trato de verificar si estos campos no fueron alterados llamando a VerifyHash.

La clave se proporciona en 2 formas: regular y 'noNL'. La versión noNL se incluye en el código anterior, la versión normal es la siguiente:

-----BEGIN PUBLIC KEY----- 
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVGUzbydMZS+fnkGTsUkDKEyFO 
GwghR234d5GjPnMIC0RFtXtw2tdcNM8I9Qk+h6fnPHiA7r27iHBfdxTP3oegQJWp 
bY2RMwSmOs02eQqpKx4QtIjWqkKk2Gmck5cll9GCoI8AUAA5e0D02T0ZgINDmo5y 
GPhGAAmqYrm8YiupwQIDAQAB 
-----END PUBLIC KEY----- 

Respuesta

13

Su cadena es la codificación base64 de un SubjectPublicKeyInfo. Se puede utilizar para decodificar Bouncycastle.net así:

byte[] publicKeyBytes = Convert.FromBase64String(publicKeyString); 
AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(publicKeyBytes); 
RsaKeyParameters rsaKeyParameters = (RsaKeyParameters) asymmetricKeyParameter; 
RSAParameters rsaParameters = new RSAParameters(); 
rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned(); 
rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned(); 
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); 
rsa.ImportParameters(rsaParameters); 
+0

Gracias, eso es bastante fácil. Buscaré en la biblioteca de BouncyCastle, pero ¿está seguro de que no hay forma de lograr esto usando solo la biblioteca Criptografía en .NET? – jscheppers

+0

@jscheppers: Puedes hacerlo manualmente como poupou sugiere, pero no hay soporte directo para el formato en .NET. Una búsqueda rápida revela este ejemplo para decodificar manualmente: http://www.jensign.com/JavaScience/dotnet/pempublic/pempublic.cs, pero se ve un poco desordenado. –

+0

Creo que prefiero tu solución BouncyCastle;) Ya lo he probado en mi implementación actual y funciona. ¡Marcaré tu publicación como la respuesta! – jscheppers

4

Primera base 64 es solamente una codificación de algunos datos binarios. Hay más de una forma de codificar, en binario, una clave pública de RSA. Sin embargo, si obtuviste esto de OpenSSL es probable que tenga una estructura RSAPublicKey codificada en DER.

RSAPublicKey ::= SEQUENCE { 
    modulus   INTEGER, -- n 
    publicExponent  INTEGER } -- e 

En general lo que se necesita un decodificador ASN.1, Mono.Security.dll proporciona one, pero para una estructura tan sencilla es posible que desee hacerlo con la mano desde ASN.1 es básicamente un Tag, Longitud y Valor.

+0

La organización que proporciona las claves públicas no menciona el formato de la clave, pero como yo soy capaz de 'leer' con OpenSSL y dado que la clave contiene las teclas ----- BEGIN PUBLIC KEY ----- y ----- END PUBLIC KEY ----- (añadiré esto a mi publicación original) Estoy bastante seguro de que es una codificación DER llave. ¿Cómo harías para convertir esta cadena en una estructura ASN.1 a mano? Cuando los bytes entran en juego, no estoy tan seguro de mí mismo :) – jscheppers

+1

Tenga en cuenta que en realidad es un 'SubjectPublicKeyInfo' * que contiene * un' RSAPublicKey'. –

0

Si su socio también utiliza .NET, puede derivar de makecert https://github.com/mono/mono/blob/bf55818da11240bd108dc51b374fae3d3b5482ce/mcs/tools/security/makecert.cs de Mono para generar archivos de certificado y enviarlo directamente a usted.

En ese caso, puede cargar fácilmente certificados en lugar de bytes sin formato,

http://www.lextm.com/2012/02/simple-publicprivate-key-signing-sample-code/

+0

Esa sería una buena posibilidad, pero no tengo control sobre la forma en que se generan las claves. Las claves se proporcionan tal cual, no hay certificado disponible donde esta clave está presente. – jscheppers

Cuestiones relacionadas