Hola Habr! Les presento la traducción del segundo artículo "Cifrado de Java" de Jakob Jenkov de una serie de artículos para principiantes que desean aprender los conceptos básicos de la criptografía en Java.
Tabla de contenido:
- Criptografía
- Cifrado
- Messagedigest
- Mac
- Firma
- Par de llaves
- Generador de claves
- KeyPairGenerator
- Keystore
- Keytool
- Certificado
- CertificateFactory
- CertPath
Cifrado de Java (Cifrado)
La clase Java Cipher ( javax.crypto.Cipher ) es un algoritmo de cifrado. El término "Cipher" es un término estándar para un algoritmo de cifrado en el mundo de la criptografía. Esta es la razón por la cual la clase Java se llama Cipher , y no Encryptor / Decryptor u otra cosa. Puede usar una instancia de Cipher para cifrar y descifrar datos en Java. Este capítulo explica cómo funciona la clase Cipher.
Creación de cifrado
Antes de usar un cifrado, debe crear una instancia de la clase Cipher llamando a su método getInstance () con un parámetro que indique qué tipo de algoritmo de cifrado desea usar. Aquí hay un ejemplo de cómo crear una instancia de Java Cipher:
Cipher cipher = Cipher.getInstance("AES");
Este ejemplo crea una instancia de Cipher utilizando el algoritmo de cifrado AES.
Modos de cifrado
Algunos algoritmos de cifrado pueden funcionar en diferentes modos. El modo de cifrado determina los detalles de cómo se cifrarán los datos. Por lo tanto, el modo de cifrado afecta parcialmente el algoritmo de cifrado. Los modos de cifrado a veces se pueden usar en varios algoritmos de cifrado diferentes, como un método que se agrega al algoritmo de cifrado principal. Es por eso que los modos se consideran por separado de los propios algoritmos de cifrado, sino más bien como "adiciones" a los algoritmos de cifrado. Estos son algunos de los modos de cifrado más conocidos:
- EBC - Libro de códigos electrónicos ( Modo de libro de códigos electrónicos)
- CBC - Encadenamiento de bloques de cifrado
- CFB - Cipher Feedback ( Modo de retroalimentación de cifrado)
- OFB - Comentarios de salida
- CTR - Contador ( modo de contador)
Al crear una instancia de un cifrado, puede agregar su modo al nombre del algoritmo de cifrado. Para crear una instancia de AES Cipher utilizando el modo de acoplamiento de bloques - Cipher Block Chaining (CBC), puede hacer esto:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
Dado que el modo de acoplamiento de los bloques de cifrado también requiere un "esquema de relleno", el esquema de relleno ( PKCS5Padding ) se agrega al final de la cadena del nombre del algoritmo de cifrado.
Es importante saber que el proveedor de cifrado Java SDK no admite todos los algoritmos y modos de cifrado de manera predeterminada. Para crear la instancia de cifrado que necesita con el modo requerido y el patrón de relleno, es posible que necesite instalar un proveedor externo, como Bouncy Castle.
Inicialización de cifrado
Antes de usar una instancia de Cipher, debe inicializarse. El cifrado se inicializa llamando a su método init () . El método init () toma dos parámetros:
Un ejemplo de inicialización de una instancia de Cipher en modo de cifrado:
Key key = ...
Y aquí hay un ejemplo de inicialización de una instancia de Cipher que ya está en modo de descifrado:
Key key = ...
Cifrado y descifrado de datos
Para cifrar o descifrar datos utilizando una instancia de Cipher, uno de estos dos métodos se llama:
Hay varias versiones anuladas de los métodos update () y doFinal () que toman diferentes parámetros. Considere el más utilizado aquí. Si necesita cifrar o descifrar un bloque de datos, simplemente llame a doFinal () con los datos para cifrar o descifrar. Un ejemplo:
byte[] plainText = "abcdefghijklmnopqrstuvwxyz".getBytes("UTF-8"); byte[] cipherText = cipher.doFinal(plainText);
De hecho, el código se ve aproximadamente igual en el caso de descifrado de datos. Solo recuerde que la instancia de Cipher debe inicializarse en modo de descifrado. Así es como se ve el descifrado de un bloque de texto cifrado:
byte[] plainText = cipher.doFinal(cipherText);
Si necesita cifrar o descifrar un archivo grande dividido en varios bloques, se llama a update () una vez para cada bloque de datos y finaliza con una llamada al método doFinal () con el último bloque de datos. Aquí hay un ejemplo de encriptación de múltiples bloques de datos:
byte[] data1 = "abcdefghijklmnopqrstuvwxyz".getBytes("UTF-8"); byte[] data2 = "zyxwvutsrqponmlkjihgfedcba".getBytes("UTF-8"); byte[] data3 = "01234567890123456789012345".getBytes("UTF-8"); byte[] cipherText1 = cipher.update(data1); byte[] cipherText2 = cipher.update(data2); byte[] cipherText3 = cipher.doFinal(data3);
La razón por la que se necesita la llamada doFinal () para el último bloque de datos es porque algunos algoritmos de cifrado necesitan complementar los datos para ajustarse a un tamaño de bloque de cifrado específico (por ejemplo, un límite de 8 bytes). No es necesario complementar los datos cifrados intermedios. Por lo tanto, se llama al método update () para los bloques de datos intermedios y se llama a la llamada doFinal () para el último bloque de datos.
Al descifrar varios bloques de datos, también se llama al método update () para bloques de datos intermedios y al método doFinal () para el último bloque. Ejemplo de descifrado de varios bloques de datos:
byte[] plainText1 = cipher.update(cipherText1); byte[] plainText2 = cipher.update(cipherText2); byte[] plainText3 = cipher.doFinal(cipherText3);
Nuevamente, la instancia de cifrado debe inicializarse en modo de descifrado para que este ejemplo funcione.
Cifrado / descifrado de una parte de una matriz de bytes
Los métodos de cifrado y descifrado de la clase Cipher pueden cifrar o descifrar algunos de los datos almacenados en una matriz de bytes. El método update () y / o doFinal () necesita pasar el desplazamiento y la longitud.
int offset = 10; int length = 24; byte[] cipherText = cipher.doFinal(data, offset, length);
En este ejemplo, los bytes del índice 10 y 24 bytes en adelante se cifrarán (o descifrarán, dependiendo de la inicialización del cifrado).
Cifrado / descifrado a una matriz de bytes existente
Todos los ejemplos de cifrado y descifrado en este capítulo devuelven datos cifrados o descifrados en una nueva matriz de bytes. Sin embargo, también es posible cifrar o descifrar datos en una matriz de bytes existente. Esto puede ser útil para reducir la cantidad de conjuntos de bytes creados. Para hacer esto, pase la matriz de bytes de destino como parámetro al método update () y / o doFinal () .
int offset = 10; int length = 24; byte[] dest = new byte[1024]; cipher.doFinal(data, offset, length, dest);
En este ejemplo, los datos se cifran desde 10 índices de 24 bytes hacia adelante a la matriz de bytes de destino con desplazamiento 0. Si desea establecer una compensación diferente para la matriz de bytes de destino, hay versiones de actualización () y doFinal () que aceptan un parámetro de compensación adicional. Un ejemplo de llamar al método doFinal () con un desplazamiento en la matriz dest:
int offset = 10; int length = 24; byte[] dest = new byte[1024]; int destOffset = 12 cipher.doFinal(data, offset, length, dest, destOffset);
Reutilizando una instancia de un cifrado
Inicializar una instancia de Cipher es una operación costosa y reutilizar las instancias de Cipher es una buena idea. Afortunadamente, la clase Cipher ha sido diseñada teniendo en cuenta la reutilización. Cuando llama al método doFinal () en la instancia de Cipher, vuelve al estado en el que se encontraba inmediatamente después de la inicialización. La instancia de Cipher se puede usar para cifrar o descifrar más datos.
Un ejemplo de reutilización de una instancia de Java Cipher:
Cipher cipher = Cipher.getInstance("AES"); Key key = ...
Primero, se crea e inicializa una instancia de Cipher, y luego se usa para cifrar dos bloques de datos consistentes. Observe la llamada a update () y luego a doFinal () para estos dos bloques de datos. Después de eso, la instancia de Cipher se puede usar nuevamente para cifrar los datos. Esto se hace llamando a doFinal () con un tercer bloque de datos. Después de esta llamada a doFinal (), puede cifrar otro bloque de datos con la misma instancia de Java Cipher.