Lo que necesito es encriptar la cadena que aparecerá en código de barras 2D (PDF-417) para que cuando alguien tenga una idea para escanear no tenga nada legible.
Otros requerimientos:
- no debería ser complicado
- no debe consistir en infraestructura RSA, PKI, pares de claves, etc.
Debe ser lo suficientemente simple como para deshacerse de las personas que están husmeando, y fácil de descifrar para otras compañías interesadas en obtener esos datos. Nos llaman, les decimos el estándar o les damos una clave simple que luego se puede usar para descifrar.
Probablemente esas compañías podrían usar diferentes tecnologías, por lo que sería bueno cumplir con algún estándar que no esté vinculado a alguna plataforma o tecnología especial.
¿Que sugieres? ¿Hay alguna clase de Java haciendo encrypt()
y decrypt()
sin muchas complicaciones para lograr altos estándares de seguridad?
fuente
Respuestas:
Prefacio
Explicaré los conceptos básicos de la criptografía simétrica segura a continuación y señalaré los errores comunes que veo en línea cuando las personas implementan criptografía por su cuenta con la biblioteca estándar de Java. Si desea omitir todos los detalles, vaya a la nueva biblioteca de Google. Tink importe eso en su proyecto y use el modo AES-GCM para todos sus cifrados y estará seguro.
Ahora, si quieres aprender los detalles esenciales sobre cómo cifrar en Java, sigue leyendo :)
Cifrados de bloque
Lo primero que debe hacer primero es elegir una clave simétrica Block Cipher. Un Block Cipher es una función / programa de computadora utilizado para crear Pseudoaleatoriedad. La pseudoaleatoriedad es una aleatoriedad falsa que ninguna computadora que no sea una Computadora Cuántica podría distinguir entre la aleatoriedad real y la aleatoriedad real. Block Cipher es como el componente básico de la criptografía, y cuando se usa con diferentes modos o esquemas podemos crear cifrados.
Ahora, con respecto a los algoritmos de cifrado de bloque disponibles en la actualidad, asegúrese de NUNCA , repito NUNCA use DES , incluso diría que NUNCA use 3DES . El único Block Cipher que incluso el lanzamiento de la NSA de Snowden pudo verificar que está realmente tan cerca de Pseudo-Random como sea posible es AES 256 . También existe AES 128; la diferencia es que AES 256 funciona en bloques de 256 bits, mientras que AES 128 funciona en bloques de 128. Con todo, AES 128 se considera seguro, aunque se han descubierto algunas debilidades, pero 256 es tan sólido como parece.
Dato curioso El DES fue roto por la NSA cuando se fundó inicialmente y en realidad mantuvo un secreto durante unos años. Aunque algunas personas todavía afirman que 3DES es seguro, hay bastantes trabajos de investigación que han encontrado y analizado las debilidades en 3DES .
Modos de cifrado
El cifrado se crea cuando toma un cifrado de bloque y usa un esquema específico para que la aleatoriedad se combine con una clave para crear algo que sea reversible siempre que conozca la clave. Esto se conoce como modo de cifrado.
Aquí hay un ejemplo de un modo de cifrado y el modo más simple conocido como BCE para que pueda comprender visualmente lo que está sucediendo:
Los modos de cifrado que verá más comúnmente en línea son los siguientes:
BCE CTR, CBC, GCM
Existen otros modos fuera de los enumerados y los investigadores siempre están trabajando hacia nuevos modos para mejorar los problemas existentes.
Ahora pasemos a las implementaciones y lo que es seguro. NUNCA use BCE, esto es malo para ocultar datos repetidos como lo muestra el famoso pingüino de Linux .
Al implementar en Java, tenga en cuenta que si usa el siguiente código, el modo ECB se establece de manera predeterminada:
... ¡PELIGRO ESTA ES UNA VULNERABILIDAD! y desafortunadamente, esto se ve en todo StackOverflow y en línea en tutoriales y ejemplos.
Nonces y IVs
En respuesta al problema encontrado con el modo BCE, se crearon los sustantivos también conocidos como IV. La idea es que generemos una nueva variable aleatoria y la adjuntemos a cada encriptación para que cuando encriptes dos mensajes que sean iguales salgan diferentes. La belleza detrás de esto es que un IV o nonce es de conocimiento público. Eso significa que un atacante puede tener acceso a esto, pero mientras no tengan su clave, no pueden hacer nada con ese conocimiento.
Los problemas comunes que veré es que las personas establecerán el IV como un valor estático como en el mismo valor fijo en su código. y aquí está el escollo de los IV en el momento en que repite uno, realmente compromete la seguridad completa de su cifrado.
Generando un IV al azar
Nota: SHA1 está roto, pero no pude encontrar cómo implementar SHA256 en este caso de uso correctamente, por lo que si alguien quiere resolver esto y actualizarlo, ¡sería increíble! Además, los ataques SHA1 aún no son convencionales, ya que puede demorar algunos años en que un gran clúster se rompa. Mira los detalles aquí.
Implementación de CTR
No se requiere relleno para el modo CTR.
Implementación de CBC
Si elige implementar el modo CBC, hágalo con PKCS7Padding de la siguiente manera:
Vulnerabilidad de CBC y CTR y por qué debería usar GCM
Aunque algunos otros modos, como CBC y CTR, son seguros, se topan con el problema de que un atacante puede voltear los datos cifrados, cambiando su valor cuando se descifra. Entonces, digamos que encripta un mensaje bancario imaginario "Vender 100", su mensaje encriptado se ve así "eu23ng", el atacante cambia un poco a "eu53ng" y, de repente, cuando desencripta su mensaje, se lee como "Vender 900".
Para evitar esto, la mayoría de Internet usa GCM, y cada vez que ve HTTPS probablemente estén usando GCM. GCM firma el mensaje cifrado con un hash y lo verifica para verificar que el mensaje no se haya cambiado con esta firma.
Evitaría implementar GCM debido a su complejidad. Es mejor usar la nueva biblioteca de Google Tink porque aquí nuevamente, si repite accidentalmente un IV, está comprometiendo la clave en el caso de GCM, que es el último defecto de seguridad. Los nuevos investigadores están trabajando hacia modos de encriptación resistentes a la repetición IV, donde incluso si repite la IV, la clave no está en peligro, pero esto aún no se ha generalizado.
Ahora, si desea implementar GCM, aquí hay un enlace a una buena implementación de GCM . Sin embargo, no puedo garantizar la seguridad o si está implementada correctamente, pero baja la base. También tenga en cuenta que con GCM no hay relleno.
Claves vs Contraseñas
Otra nota muy importante, es que cuando se trata de criptografía, una clave y una contraseña no son lo mismo. Una clave en criptografía debe tener una cierta cantidad de entropía y aleatoriedad para considerarse segura. Es por eso que debe asegurarse de utilizar las bibliotecas criptográficas adecuadas para generar la clave para usted.
Entonces, realmente tiene dos implementaciones que puede hacer aquí, la primera es usar el código que se encuentra en este hilo de StackOverflow para la generación aleatoria de claves . Esta solución utiliza un generador de números aleatorios seguro para crear una clave desde cero que puede utilizar.
La otra opción menos segura es usar la entrada del usuario, como una contraseña. El problema como discutimos es que la contraseña no tiene suficiente entropía, por lo que tendríamos que usar PBKDF2 , un algoritmo que toma la contraseña y la fortalece. Aquí hay una implementación de StackOverflow que me gustó . Sin embargo, la biblioteca Google Tink tiene todo esto incorporado y deberías aprovecharlo.
Desarrolladores de Android
Un punto importante a señalar aquí es saber que su código de Android es de ingeniería inversa y la mayoría de los casos la mayoría del código de Java también lo es. Eso significa que si almacena la contraseña en texto sin formato en su código. Un hacker puede recuperarlo fácilmente. Por lo general, para este tipo de cifrado, desea utilizar la Criptografía asimétrica, etc. Esto está fuera del alcance de esta publicación, así que evitaré sumergirme en él.
Una lectura interesante de 2013 : señala que el 88% de las implementaciones de Crypto en Android se realizaron de forma incorrecta.
Pensamientos finales
Una vez más, sugeriría evitar implementar la biblioteca java para crypto directamente y usar Google Tink , le ahorrará el dolor de cabeza ya que realmente han hecho un buen trabajo al implementar todos los algoritmos correctamente. E incluso entonces, asegúrese de verificar los problemas que aparecen en el github de Tink, las vulnerabilidades emergentes aquí y allá.
Si tiene alguna pregunta o comentario, ¡no dude en comentar! La seguridad siempre está cambiando y debe hacer todo lo posible para mantenerse al día :)
fuente
getInstanceStrong()
método deCipher
es preferible a SHA1PRNGRecomiendo usar algunos cifradores simétricos estándar que están ampliamente disponibles como DES , 3DES o AES . Si bien ese no es el algoritmo más seguro, hay un montón de implementaciones y solo tendría que dar la clave a cualquiera que se suponga que descifre la información en el código de barras. javax.crypto.Cipher es con lo que quieres trabajar aquí.
Supongamos que los bytes para cifrar están en
A continuación, necesitará la clave y los bytes del vector de inicialización
Ahora puede inicializar Cipher para el algoritmo que seleccione:
El cifrado sería así:
Y descifrado como este:
fuente
DESede
algoritmo? Dado que esta es una pregunta (y respuesta) popular, sería una pena alentar a las personas a usar DES, ya que el cifrado es muy débil para los estándares actuales.Estoy usando Sun's Base64Encoder / Decoder que se encuentra en Sun's JRE, para evitar otro JAR en lib. Eso es peligroso desde el punto de usar OpenJDK o el JRE de otro. Además de eso, ¿hay alguna otra razón por la que debería considerar usar Apache commons lib con Encoder / Decoder?
fuente
gracias he hecho esta clase usando tu código tal vez alguien lo encuentre útil
objeto crypter
fuente
Actualización el 12-DIC-2019
A diferencia de otros modos como CBC, el modo GCM no requiere que el IV sea impredecible. El único requisito es que el IV debe ser único para cada invocación con una clave determinada. Si se repite una vez para una clave determinada, la seguridad puede verse comprometida. Una manera fácil de lograr esto es usar un IV aleatorio de un fuerte generador de números pseudoaleatorios como se muestra a continuación.
También es posible usar una secuencia o marca de tiempo como IV, pero puede que no sea tan trivial como puede parecer. Por ejemplo, si el sistema no realiza un seguimiento correcto de las secuencias ya utilizadas como IV en un almacén persistente, una invocación puede repetir un IV después de reiniciar el sistema. Del mismo modo, no hay reloj perfecto. El reloj de la computadora se reajusta, etc.
Además, la clave debe girarse después de cada 2 ^ 32 invocaciones. Para obtener más detalles sobre el requisito IV, consulte esta respuesta y las recomendaciones del NIST .
Este es el código de cifrado y descifrado que acabo de escribir en Java 8 considerando los siguientes puntos. Espero que alguien encuentre esto útil:
Algoritmo de cifrado : el cifrado de bloque AES con clave de 256 bits se considera lo suficientemente seguro. Para cifrar un mensaje completo, se debe seleccionar un modo. Se recomienda el cifrado autenticado (que proporciona confidencialidad e integridad). GCM, CCM y EAX son los modos de cifrado autenticado más utilizados. Generalmente se prefiere GCM y funciona bien en arquitecturas Intel que proporcionan instrucciones dedicadas para GCM. Todos estos tres modos son modos basados en CTR (basados en contador) y, por lo tanto, no necesitan relleno. Como resultado, no son vulnerables a los ataques relacionados con el relleno
Se requiere un vector de inicialización (IV) para GCM. El IV no es un secreto. El único requisito es que sea aleatorio o impredecible. En Java, la
SecuredRandom
clase está destinada a producir números pseudoaleatorios criptográficamente fuertes. El algoritmo de generación de números pseudoaleatorios puede especificarse en elgetInstance()
método. Sin embargo, desde Java 8, la forma recomendada es utilizar elgetInstanceStrong()
método que utilizará el algoritmo más fuerte configurado y proporcionado por elProvider
NIST recomienda 96 bit IV para GCM para promover la interoperabilidad, eficiencia y simplicidad de diseño
Para garantizar una seguridad adicional, en la siguiente implementación
SecureRandom
se vuelve a sembrar después de producir cada 2 ^ 16 bytes de generación de bytes pseudoaleatoriosEl destinatario debe conocer el IV para poder descifrar el texto cifrado. Por lo tanto, el IV debe transferirse junto con el texto cifrado. Algunas implementaciones envían el IV como AD (datos asociados), lo que significa que la etiqueta de autenticación se calculará tanto en el texto cifrado como en el IV. Sin embargo, eso no es obligatorio. El IV se puede simplemente pre-escribir con el texto cifrado porque si el IV se cambia durante la transmisión debido a un ataque deliberado o un error del sistema de red / archivo, la validación de la etiqueta de autenticación fallará de todos modos
Las cadenas no deben usarse para contener el mensaje de texto claro o la clave, ya que las cadenas son inmutables y, por lo tanto, no podemos borrarlas después de su uso. Estas cadenas sin borrar permanecen en la memoria y pueden aparecer en un volcado de almacenamiento dinámico. Por la misma razón, el cliente que llama a estos métodos de cifrado o descifrado debe borrar todas las variables o matrices que contienen el mensaje o la clave después de que ya no sean necesarias.
Ningún proveedor está codificado en el código siguiendo las recomendaciones generales
Finalmente, para la transmisión a través de la red o el almacenamiento, la clave o el texto cifrado deben codificarse utilizando la codificación Base64. Los detalles de Base64 se pueden encontrar aquí . Se debe seguir el enfoque de Java 8
Las matrices de bytes se pueden borrar usando:
Sin embargo, a partir de Java 8, no hay una manera fácil de borrar
SecretKeyspec
y,SecretKey
dado que las implementaciones de estas dos interfaces no parecen haber implementado el métododestroy()
de la interfazDestroyable
. En el siguiente código, se escribe un método separado para borrarSecretKeySpec
ySecretKey
usar la reflexión.La clave debe generarse utilizando uno de los dos enfoques mencionados a continuación.
Tenga en cuenta que las claves son secretos como las contraseñas, pero a diferencia de las contraseñas destinadas al uso humano, las claves deben ser utilizadas por algoritmos criptográficos y, por lo tanto, deben generarse utilizando la forma anterior.
La clave de cifrado se puede generar principalmente de dos maneras:
Sin ninguna contraseña
Con contraseña
Actualización basada en comentarios
Como señaló @MaartenBodewes, mi respuesta no manejó ninguna,
String
como lo requiere la pregunta. Por lo tanto, intentaré llenar ese vacío en caso de que alguien tropiece con esta respuesta y se pregunte sobre el manejoString
.Como se indicó anteriormente en la respuesta, el manejo de información confidencial en a no
String
es, en general, una buena idea porqueString
es inmutable y, por lo tanto, no podemos borrarlo después de su uso. Y como sabemos, incluso cuando aString
no tiene una referencia fuerte, el recolector de basura no se apresura de inmediato a sacarlo del montón. Por lo tanto,String
sigue existiendo en la memoria durante una ventana de tiempo desconocida a pesar de que no es accesible para el programa. El problema con eso es que un volcado del montón durante ese período de tiempo revelaría la información confidencial. Por lo tanto, siempre es mejor manejar toda la información confidencial en una matriz de bytes o matriz de caracteres y luego llenar la matriz con 0 una vez que se cumpla su propósito.Sin embargo, con todo ese conocimiento, si todavía terminamos en una situación en la que la información confidencial que se va a cifrar se encuentra en una
String
, primero debemos convertirla en una matriz de bytes e invocar las funcionesencrypt
ydecrypt
que se introdujeron anteriormente. (La otra clave de entrada se puede generar utilizando el fragmento de código proporcionado anteriormente).A
String
se puede convertir en bytes de la siguiente manera:A partir de Java 8,
String
se almacena internamente en el montón conUTF-16
codificación. Sin embargo, hemos utilizadoUTF-8
aquí, ya que generalmente ocupa menos espacio queUTF-16
, especialmente para los caracteres ASCII.Del mismo modo, la matriz de bytes cifrada también se puede convertir en una cadena de la siguiente manera:
fuente
String
usando las funciones creadas anteriormente sería trivial. Sin embargo, después de leer su comentario, entiendo que puede no ser obvio. Seguramente editaré para agregar esos detalles.Qué tal esto:
Funciona bien para mí y es bastante compacto.
fuente
input.length <= secret.length
mantenga y nosecret
se reutilice nunca, esto es seguro y se llama aone-time-pad
. En los casos deinput.length > secret.length
esto es una variante del cifrado de Vigenère y se considera muy débil.Puedes usar Jasypt
Con Jasypt, cifrar y verificar una contraseña puede ser tan simple como ...
Cifrado:
Descifrado:
Gradle:
caracteristicas:
fuente
Jasypt
proporciona? No puedo entenderlo desde su sitio web. ¿Es indistinguible bajo ataques de texto sin formato elegido? ¿Integridad? Confidencialidad?Aquí está mi implementación de meta64.com como Spring Singleton. Si desea crear una instancia de Ciper para cada llamada que también funcionaría, y luego podría eliminar las llamadas 'sincronizadas', pero tenga cuidado con 'Cipher' no es seguro para subprocesos.
fuente
Aquí una solución simple con solo
java.*
yjavax.crypto.*
dependencias para el cifrado de bytes que proporciona confidencialidad e integridad . Será indistinguible bajo un ataque de texto sin formato elegido para mensajes cortos del orden de kilobytes.Se utiliza
AES
en elGCM
modo sin relleno, se deriva una clave de 128 bitsPBKDF2
con muchas iteraciones y una sal estática de la contraseña proporcionada. Esto asegura que las contraseñas de forzamiento bruto sean difíciles y distribuya la entropía por toda la clave.Se genera un vector de inicialización aleatorio (IV) y se antepondrá al texto cifrado. Además, el byte estático
0x01
se antepone como el primer byte como una 'versión'.Todo el mensaje entra en el código de autenticación de mensaje (MAC) generado por
AES/GCM
.Aquí va, clase de cifrado de dependencias externas cero que proporciona confidencialidad e integridad :
Aquí el proyecto completo con una buena CLI: https://github.com/trichner/tcrypt
Editar: ahora con apropiado
encryptString
ydecryptString
fuente
encryptString
decryptString
Consideraría usar algo como https://www.bouncycastle.org/ Es una biblioteca preconstruida que te permite encriptar lo que quieras con una cantidad de Ciphers diferentes. Entiendo que solo quieres protegerte de espiar, pero si realmente desea proteger la información, el uso de Base64 no lo protegerá realmente.
fuente
Aquí hay algunos enlaces en los que puede leer qué admite Java
Cifrar / descifrar un flujo de datos.
JCERefGuide
Ejemplos de cifrado de Java
fuente
Como muchos de los chicos ya han dicho, debes usar un cifrador estándar que se usa demasiado como DES o AES.
Un ejemplo simple de cómo puede cifrar y descifrar una cadena en Java utilizando AES .
fuente
Aquí hay una solución copiar / pegar. También recomiendo leer y votar la respuesta de @ Konstantino a pesar de que no proporciona ningún código. El vector de inicialización (IV) es como una sal: no tiene que mantenerse en secreto. Soy nuevo en GCM y aparentemente AAD es opcional y solo se usa en ciertas circunstancias. Establezca la clave en la variable de entorno
SECRET_KEY_BASE
. Use algo como KeePass para generar una contraseña de 32 caracteres. Esta solución sigue el modelo de mi solución Ruby.Aquí hay un ejemplo:
fuente
Es posible que desee considerar alguna herramienta automatizada para hacer la generación del código de cifrado / descifrado, por ejemplo. https://www.stringencrypt.com/java-encryption/
Puede generar diferentes códigos de cifrado y descifrado cada vez para el cifrado de cadenas o archivos.
Es bastante útil cuando se trata de encriptación rápida de cadenas sin usar RSA, AES, etc.
Resultados de muestra:
Lo usamos todo el tiempo en nuestra empresa.
fuente
fuente
fuente