2008-12-11 19 views
20

Para una aplicación web, me gustaría crear un sistema de licencias simple pero efectivo. En C#, esto es un poco difícil, ya que mi método de descifrado podría ser visto por cualquier persona que tenga instalado Reflector.¿Un método efectivo para encriptar un archivo de licencia?

¿Cuáles son algunos métodos para encriptar archivos en C# que son bastante inviolables?

+2

Cualquier cosa que intente, si su aplicación necesita descifrar su archivo de licencia, cada usuario recomendado puede hacerlo. Piense en otra forma de licenciar su softare. –

Respuesta

37

Parece que quiere usar la criptografía pública/privada para firmar un token de licencia (un fragmento o archivo XML, por ejemplo) para que pueda detectar la manipulación. La forma más sencilla de manejarlo es realizar los siguientes pasos:

1) Genere un par de llaves para su empresa. Puede hacer esto en la línea de comando de Visual Studio usando la herramienta SN. La sintaxis es:

sn -k c:\keypair.snk 

2) Utilice el par de claves para nombrar fuerte (es decir, signo) la aplicación cliente. Puede configurar esto usando la pestaña de firma en la página de propiedades en su aplicación

3) Cree una licencia para su cliente, este debe ser un documento XML y fírmelo con su clave privada. Esto implica simplemente calcular una firma digital y pasos para lograr que se puede encontrar en:

http://msdn.microsoft.com/en-us/library/ms229745.aspx

4) En el cliente, al comprobar la licencia se carga el XmlDocument y utiliza su clave pública para verificar la firma de demostrar que la licencia no ha sido manipulada.Los detalles sobre cómo hacer esto se pueden encontrar en:

http://msdn.microsoft.com/en-us/library/ms229950.aspx

Para conseguir alrededor de distribución de claves (es decir, asegurando que su cliente está utilizando la clave pública correcta) en realidad se puede tirar de la clave pública del conjunto firmado en sí. Asegurándose de que no tiene otra clave para distribuir e incluso si alguien manipula el ensamblado, el .NET Framework morirá con una excepción de seguridad porque el nombre fuerte ya no coincidirá con el ensamblado.

para tirar de la clave pública del conjunto cliente desea utilizar un código similar a:

/// <summary> 
    /// Retrieves an RSA public key from a signed assembly 
    /// </summary> 
    /// <param name="assembly">Signed assembly to retrieve the key from</param> 
    /// <returns>RSA Crypto Service Provider initialised with the key from the assembly</returns> 
    public static RSACryptoServiceProvider GetPublicKeyFromAssembly(Assembly assembly) 
    { 
     if (assembly == null) 
      throw new ArgumentNullException("assembly", "Assembly may not be null"); 

     byte[] pubkey = assembly.GetName().GetPublicKey(); 
     if (pubkey.Length == 0) 
      throw new ArgumentException("No public key in assembly."); 

     RSAParameters rsaParams = EncryptionUtils.GetRSAParameters(pubkey); 
     RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); 
     rsa.ImportParameters(rsaParams); 

     return rsa; 
    } 

He subido una clase de muestra con una gran cantidad de utilidades de cifrado votos en Snipt en: http://snipt.net/Wolfwyrd/encryption-utilities/ para ayudar a conseguir tu en camino.

También he incluido un programa de muestra en: https://snipt.net/Wolfwyrd/sign-and-verify-example/. El ejemplo requiere que lo agregue a una solución con la biblioteca de utilidades de cifrado y proporcione un archivo XML de prueba y un archivo SNK para la firma. El proyecto debe configurarse para que se firme con el SNK que genere. Demuestra cómo firmar el archivo XML de prueba utilizando una clave privada del SNK y luego verificar desde la clave pública en el ensamblado.

actualización

Agregado un up to date blog post con una buena racha detallada a través de los archivos de licencia

+0

Exactamente lo que dije a continuación. –

+0

Código de cifrado extremadamente útil. Gracias Wolfwyrd por ponerlo a disposición. –

+0

@ Wolfdryrd: las utilidades que ha puesto a disposición, ¿podría proporcionar algunas instrucciones breves sobre cómo usarlas? – Ian

1

¿Por qué tendrías que encriptarlo? Si se trata de una alteración, tiene miedo (por ejemplo, que alguien aumente la cantidad de usuarios), ¿podría simplemente firmarla con, p. el certificado digital de su organización en su lugar?

0

o tal vez desea vincular una licencia a una máquina en particular, por ejemplo, generando la clave de licencia basada en el valor md5 de la unidad c de la pc. entonces su licencia sería específica de la máquina.

+0

¿Te refieres al número de serie del disco C correcto? no los contenidos. Y asegúrese de no utilizar el ID de volumen, que puede copiarse fácilmente. – Martin

+0

Hashing el disco es una mala idea, demasiados datos. Es mejor usar DPAPI (machine-scope) para proteger un GUID (solo crear si aún no existe) como una "ID de máquina". Utilice el DPAPI de ámbito de usuario para proteger una "ID de usuario". – devstuff

1

La única manera de proporcionar algún tipo de seguridad con la licencia es forzar un inicio de sesión en línea contra las credenciales que mantiene (realmente hablado).

Todos los demás métodos toman más tiempo, y por lo tanto más dinero, para implementar, en cuanto a descifrar y abusar de su software en lugar de comprar una licencia.

.NET tiene algunas buenas clases criptográficas, pero como mencionaste, si estás codificando la descripción de la licencia, cualquiera puede descompilarla fácilmente.

7

Utilice un archivo XML firmado. Firma con la parte de clave privada de un par de llaves y compruébalo con la parte de clave pública en tu software. Esto le da la oportunidad de verificar si la licencia ha sido modificada y también verificar si el archivo de licencia es válido.

La firma y comprobación de un archivo XML firmado está documentada en MSDN.

Por supuesto, es lógico que firme el archivo de licencia en su propia empresa y envíe el archivo de licencia al cliente, que luego coloca el archivo de licencia en una carpeta para que lo lea.

Por supuesto, las personas pueden cortar/hackear su ensamblaje distribuido y arrancar la comprobación del signo xml, pero nuevamente, siempre podrán hacerlo, haga lo que haga.

+0

Encontré los materiales de MSDN de los que estaba hablando y la firma XML parece lo suficientemente simple. Sin embargo, ¿podría explicar algo más sobre la parte de clave pública/privada de su respuesta? No vi nada sobre el uso de dos claves diferentes para firmar y verificar un archivo XML. –

+0

usa 'sn -k' para generar un par de claves. Este par de claves se utiliza para firmar el XML. Para verificar el XML, usa la parte pública. No incluya toda la clave en su código. Use sn -p para extraer la parte pública de un archivo. Use eso en su código que distribuye para verificar la licencia. –

-1

RE: No incluya toda la clave en el código. Use sn -p para extraer la parte pública de un archivo. Use eso en su código que distribuye para verificar la licencia.

Usando el código de los artículos de MSDN, creé una aplicación pequeña (LicMaker) para facilitar esto. La aplicación está firmada con el par de claves completo. La entrada es un archivo de licencia .XML sin firmar. El resultado es la firma XML + original en un archivo .LIC firmado. Mi producto también está firmado por el mismo archivo de par de claves completo. El producto verifica que el archivo .LIC no ha sido manipulado. Funciona genial. No usé sn -p para esta solución.

1

Parece que las muestras de MSDN usan parámetros predeterminados y esto da como resultado la firma específica de la máquina, de modo que no puede iniciar sesión en una máquina y verificar en otra máquina arbitraria. Modifiqué la lógica en esas muestras para usar las claves en mi snk en la máquina de firma y las claves de mi ensamblaje en la máquina de verificación. Esto se hizo usando la lógica de la muestra y las rutinas de MSDN en el ejemplo (muy bien hecho) de ExcryptionUtils.cs vinculado anteriormente.

Para firmar el archivo, he usado esta:

RSACryptoServiceProvider rsaKey = EncryptionUtils.GetRSAFromSnkFile(keyFilePath); 

Para verificar el archivo, he usado esto:

RSACryptoServiceProvider rsaKey = EncryptionUtils.GetPublicKeyFromAssembly 
    (System.Reflection.Assembly.GetExecutingAssembly()); 

Por cierto: he observado que la verificación de firmas XML hace caso omiso de los comentarios XML.

5

La respuesta de Wolfwyrd es excelente, pero solo quería ofrecer una versión más simple del método GetPublicKeyFromAssembly de Wolfwyrd (que usa muchos métodos auxiliares de la biblioteca que Wolfwyrd proporcionó graciosamente).

En esta versión, esto es todo lo que necesita el código:

/// <summary> 
/// Extracts an RSA public key from a signed assembly 
/// </summary> 
/// <param name="assembly">Signed assembly to extract the key from</param> 
/// <returns>RSA Crypto Service Provider initialised with the public key from the assembly</returns> 
private RSACryptoServiceProvider GetPublicKeyFromAssembly(Assembly assembly) 
{ 
    // Extract public key - note that public key stored in assembly has an extra 3 headers 
    // (12 bytes) at the front that are not part of a CAPI public key blob, so they must be removed 
    byte[] rawPublicKeyData = assembly.GetName().GetPublicKey(); 

    int extraHeadersLen = 12; 
    int bytesToRead = rawPublicKeyData.Length - extraHeadersLen; 
    byte[] publicKeyData = new byte[bytesToRead]; 
    Buffer.BlockCopy(rawPublicKeyData, extraHeadersLen, publicKeyData, 0, bytesToRead); 

    RSACryptoServiceProvider publicKey = new RSACryptoServiceProvider(); 
    publicKey.ImportCspBlob(publicKeyData); 

    return publicKey; 
} 
+0

Además agradable, +1 – Wolfwyrd

Cuestiones relacionadas