it-swarm-es.com

Clave de licencia / generador de número de serie y verificador

Necesito un generador de número de serie y un corrector adjunto. Me gustaría poder establecer una sal (y tal vez una longitud). El generador solo debe producir números de serie que pasen la prueba del verificador. Esos números solo deben representar una pequeña fracción de todos los números posibles de la longitud dada.

El algoritmo no necesita ser criptográficamente seguro. Más bien, debería ser muy fácil de implementar (en JavaScript) y debería ser muy rápido.

Para aclarar: si compra software comercial, a veces está protegido con un número de serie/una clave. Si lo escribe, el software lo verifica algorítmicamente (verificando si cumple ciertas propiedades), en lugar de buscar una gran base de datos. También estoy bastante seguro de que todas las claves se generaron algorítmicamente en lugar de a mano. Y solo una pequeña fracción de todas las claves posibles de una longitud determinada son realmente válidas, por lo que es difícil adivinar las claves.

Sal: no sé si la sal es la palabra correcta, pero el algoritmo debe tener al menos un parámetro, cuya elección altera las claves generadas (para que varias personas puedan usar el mismo algoritmo y no tengan miedo a las colisiones).

16
Dave

Si no hay una necesidad real de seguridad, entonces aquí hay un generador de números de serie muy rápido, con un verificador:

  • Usuario un contador. Inicialícelo en 0. Cuando desee un nuevo número de serie, incremente su contador en 1000; El nuevo valor del contador es el número de serie. El verificador funciona así: un número de serie es válido si termina con tres ceros. El inspector solo aceptará uno de cada 1000 números.

Si esta solución no le agrada, entonces necesita seguridad, y esto requiere criptografía.

La solución segura criptográficamente es tener números de serie firmados: el número de serie es la codificación de alguna carga útil (por ejemplo, un contador de todos los números de serie que ha generado) y una firma sobre la carga útil. El generador tiene una clave privada, que utiliza para calcular las firmas; el corrector solo conoce la clave pública correspondiente. El problema con esta configuración no es realmente sobre el tiempo de verificación, incluso en Javascript; más bien, es el tamaño de la firma lo que es un problema. Supongo que el número de serie será, en algún momento, escrito por un usuario. El tamaño teórico mínimo para una firma criptográficamente segura es de aproximadamente 80 bits (dado que las firmas se pueden verificar solo con la clave pública, un atacante podría probar todas las secuencias de bits posibles, y generalmente requerimos un nivel de seguridad de al menos 280) Sin embargo, las firmas más pequeñas entre los "esquemas asumidos como seguros" están más cerca de 160 bits (con BLS , que usa un emparejamiento, que es un poco complejo implementar) o 320 bits (con DSA o ECDSA ). Se está trabajando en sistemas de firmas con firmas más cortas ( Quartz , o McEliece-Niederreiter ) pero existe bastante controversia sobre su seguridad.

Incluso con letras mayúsculas y dígitos (36 caracteres posibles, y allí tiene 'I' y '1', y también 'O' y '0'), una firma de 160 bits utilizará 31 caracteres. Junto con la carga útil, terminará con números de serie de una longitud de aproximadamente 35, que probablemente sea demasiado para un usuario promedio para escribir (pero no por un gran margen; una firma de 80 bits encajaría muy bien).

Si no utiliza un esquema de firma, debe tener en cuenta que un atacante razonablemente determinado podrá ser capaz, a través de algún desmontaje, de sortear el corrector, o incluso aprender lo suficiente como para poder producir sus propios números de serie (que el verificador aceptará con gusto). En ese momento, no obtendrá seguridad cuantificada: no podrá decir: "mi esquema es seguro hasta un presupuesto de 3.800 millones de dólares". Más bien, irá como: "mi esquema es seguro hasta que aparezca un estudiante lo suficientemente ingenioso y aburrido, realice ingeniería inversa del código del verificador y publique el resultado en Facebook".

El esquema clásico no realmente seguro se vería así:

  • Use el contador del esquema anterior (el que termina con tres ceros). Codifíquelo como un bloque de 64 bits. Cifre ese bloque con alguna clave simétrica codificada, utilizando un cifrado de bloque. El verificador conoce la clave y verifica el número de serie descifrándolo (con la misma clave simétrica codificada) y observando los ceros finales.

Esto no es realmente más seguro que el contador simple, pero al menos los números de serie serán aleatorios. Con un alfabeto de 34 caracteres (dígitos y letras mayúsculas excepto 'O' e 'I'), un bloque de 64 bits requiere 13 letras, lo que probablemente sea aceptable (un número de serie típico de Microsoft tiene 25 letras). Para el cifrado de bloque de 64 bits, recomiendo XTEA , que debería ser lo suficientemente rápido y simple de implementar.

26
Thomas Pornin

Si desea el método criptográficamente seguro, no obtendrá una conexión a Internet para verificar la serie. Esto significa que dicho esquema de protección es más adecuado para el software basado en suscripción que para el software de plataforma tradicional.

Con las conexiones a Internet es simple (dado que usa JS, supongo que es el que desea):

  1. Alguien crea una llave, esa parte tiene que saber el secreto
  2. El servidor conoce el secreto y puede decodificar los datos.
  3. El cliente envía la clave, que es un blob binario codificado en Base32 (también vea esto )
  4. El servidor descifra la clave y verifica si es válida (ya sea sintácticamente o también semánticamente)

Sin conexión a Internet, aún puede usar un esquema similar a la firma PGP para verificar que el blob que ingresó el usuario fue creado por usted. El cifrado no funcionará igual, porque el descifrado siempre requiere conocer el secreto y el gran problema aquí es:

  1. no confía en el usuario (de lo contrario no necesitaría el esquema de protección)
  2. le das al usuario el secreto, compilado en tu binario

Obviamente, ambos puntos se contradicen entre sí. Por un lado, no confía en el usuario, por otro lado, debe implementar el secreto utilizado para el descifrado.

En general, tengo que concluir que sin la conexión a Internet y la verificación de validez basada en el servidor que da como resultado la revelación de algún conocimiento (por ejemplo, contenido que es útil solo durante tanto tiempo) cualquier esquema de protección Hasta ahora he visto que es más o menos una carrera armamentista entre crackers y vendedores.


Ahora, si no es importante tener un sistema criptográficamente seguro, todavía buscaría cualquier información binaria que pueda proteger mediante un simple CRC o algo así. Lo que viene a la mente sería:

  1. Tener un número de serie monótonamente creciente
  2. XOR con su valor de sal (o cualquier otra operación reversible)
  3. Tome el CRC32 de ese valor (o Adler32 o lo que sea): agregue más sal aquí si es necesario
  4. Codifíquelo con Base32 (ayuda a la legibilidad, etc.)
  5. Solo verifique que el CRC32 tenga validez ...
6
0xC0000022L

OP escribió "debería ser muy fácil de implementar (en javascript) y debería ser muy rápido"

No está claro si "en javascript" se refiere al generador o el verificador o ambos, o si se refiere a "javascript en el navegador", o alguna otra implementación de Java/ecmascript (por ejemplo, del lado del servidor en el servidor web).

Javascript como lenguaje de implementación no es necesariamente un problema, y ​​hay un par de bibliotecas de cifrado para javascript (compatible con MD5, DES, AES, SHA, PBKDF2, HMAC):

La velocidad tampoco debería ser un gran problema (los motores de JavaScript del navegador se están volviendo bastante utilizables a ese respecto, una vez que pasa IE6/7).

Sin embargo, ninguno de los anteriores admite la criptografía de clave pública (que es necesaria para la seguridad si el "verificador" se distribuye al usuario no confiable y, por lo tanto, no se puede permitir el acceso a la clave utilizada para crear números de serie), y mucho menos los algoritmos específicos sugeridos por Thomas, arriba. Google presenta algunos resultados para implementaciones de clave pública en JavaScript (http://www-cs-students.stanford.edu/~tjw/jsbn/, http://ohdave.com/rsa/ =, http://www.hanewin.net/encrypt/rsa/rsa.htm ) pero personalmente estaría aún más nervioso por su libre de errores que las bibliotecas "más grandes" de arriba .

Quizás más significativamente, incluso con un enfoque basado en claves públicas, si el generador o el verificador se distribuyen al usuario no confiable, entonces el esquema no es seguro. Si el código del generador está disponible para el usuario no confiable, entonces pueden generar tantas claves como desee, mientras que si el verificador está disponible para el usuario no confiable, simplemente puede modificar el código JavaScript para omitir las comprobaciones. [El mismo problema surge con el código nativo, por supuesto, pero, incluso con la ofuscación, JavaScript es posiblemente más simple de atacar mediante modificaciones locales.]

Antes de implementar un esquema de seguridad en JavaScript, también debe considerar los problemas de confianza más amplios: consulte http://rdist.root.org/2010/11/29/final-post-on-javascript-crypto/ para un resumen útil.

3
Misha