Criptografia em Java. Cifra de classe

Olá Habr! Apresento a você a tradução do segundo artigo "Java Cipher", de Jakob Jenkov, a partir de uma série de artigos para iniciantes que desejam aprender o básico da criptografia em Java.


Sumário:


  1. Criptografia
  2. Cifra
  3. Messagedigest
  4. Mac
  5. Assinatura
  6. Par de chaves
  7. Keygenerator
  8. KeyPairGenerator
  9. Keystore
  10. Keytool
  11. Certificado
  12. CertificateFactory
  13. CertPath

Cifra Java (Cifra)


A classe Java Cipher ( javax.crypto.Cipher ) é um algoritmo de criptografia. O termo "Cifra" é um termo padrão para um algoritmo de criptografia no mundo da criptografia. É por isso que a classe Java é chamada de Cifra , não o Encryptor / Decryptor ou qualquer outra coisa. Você pode usar uma instância de Cipher para criptografar e descriptografar dados em Java. Este capítulo explica como a classe Cipher funciona.


Criação de Cifra


Antes de usar uma cifra, você deve criar uma instância da classe Cipher chamando seu método getInstance () com um parâmetro indicando qual tipo de algoritmo de criptografia você deseja usar. Aqui está um exemplo de criação de uma instância do Java Cipher:


Cipher cipher = Cipher.getInstance("AES"); 

Este exemplo cria uma instância do Cipher usando o algoritmo de criptografia AES.


Modos de criptografia


Alguns algoritmos de criptografia podem funcionar em modos diferentes. O modo de criptografia determina os detalhes de como os dados serão criptografados. Assim, o modo de criptografia afeta parcialmente o algoritmo de criptografia. Às vezes, os modos de criptografia podem ser usados ​​em vários algoritmos de criptografia diferentes - como um método adicionado ao algoritmo de criptografia principal. É por isso que os modos são considerados separadamente dos próprios algoritmos de criptografia, mas como "adições" aos algoritmos de criptografia. Aqui estão alguns dos modos de criptografia mais conhecidos:


  • EBC - Catálogo de códigos eletrônicos ( modo Catálogo de códigos eletrônicos)
  • CBC - Encadeamento de blocos de criptografia
  • CFB - Feedback de Cifra ( Modo de Feedback de Cifra)
  • OFB - Feedback de saída
  • CTR - Contador ( Modo Contador)

Ao criar uma instância de uma cifra, você pode adicionar seu modo ao nome do algoritmo de criptografia. Para criar uma instância do AES Cipher usando o modo de acoplamento de bloco - Cipher Block Chaining (CBC), você pode fazer isso:


 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 

Como o modo de acoplamento dos blocos de criptografia também requer um "esquema de preenchimento", o esquema de preenchimento ( PKCS5Padding ) é adicionado ao final da sequência do nome do algoritmo de criptografia.
É importante saber que nem todos os algoritmos e modos de criptografia são suportados por padrão pelo provedor de criptografia Java SDK. Para criar a instância de cifra necessária com o modo e o padrão de preenchimento necessários, pode ser necessário instalar um provedor de terceiros, como o Bouncy Castle.


Inicialização de cifra


Antes de usar uma instância de Cipher, ela deve ser inicializada. A cifra é inicializada chamando seu método init () . O método init () usa dois parâmetros:


  • Mode
  • Key

Um exemplo de inicialização de uma instância de Cipher no modo de criptografia:


 Key key = ... // /    cipher.init(Cipher.ENCRYPT_MODE, key); 

E aqui está um exemplo de inicialização de uma instância de Cipher já no modo de descriptografia:


 Key key = ... ///    cipher.init(Cipher.DECRYPT_MODE, key); 

Criptografia e descriptografia de dados


Para criptografar ou descriptografar dados usando uma instância de Cipher, um desses dois métodos é chamado:


  • update()
  • doFinal()

Existem várias versões substituídas dos métodos update () e doFinal () que usam parâmetros diferentes. Considere o mais usado aqui. Se você precisar criptografar ou descriptografar um bloco de dados, basta chamar doFinal () com os dados para criptografar ou descriptografar. Um exemplo:


 byte[] plainText = "abcdefghijklmnopqrstuvwxyz".getBytes("UTF-8"); byte[] cipherText = cipher.doFinal(plainText); 

De fato, o código parece aproximadamente o mesmo no caso de descriptografia de dados. Lembre-se de que a instância Cipher deve ser inicializada no modo de descriptografia. Aqui está a aparência da descriptografia de um bloco de texto cifrado:


 byte[] plainText = cipher.doFinal(cipherText); 

Se você precisar criptografar ou descriptografar um arquivo grande dividido em vários blocos, update () será chamado uma vez para cada bloco de dados e terminará chamando o método doFinal () com o último bloco de dados. Aqui está um exemplo de criptografia de vários blocos de dados:


 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); 

A razão pela qual a chamada doFinal () é necessária para o último bloco de dados é porque alguns algoritmos de criptografia precisam complementar os dados para se ajustarem a um tamanho específico de bloco de criptografia (por exemplo, um limite de 8 bytes). Não é necessário suplementar dados criptografados intermediários. Portanto, o método update () é chamado para os blocos de dados intermediários e a chamada doFinal () para o último bloco de dados.
Ao descriptografar vários blocos de dados, você também chama o método update () para blocos de dados intermediários e o método doFinal () para o último bloco. Exemplo de descriptografia de vários blocos de dados:


 byte[] plainText1 = cipher.update(cipherText1); byte[] plainText2 = cipher.update(cipherText2); byte[] plainText3 = cipher.doFinal(cipherText3); 

Novamente, a instância de cifra deve ser inicializada no modo de descriptografia para que este exemplo funcione.


Criptografia / descriptografia de uma parte de uma matriz de bytes


Os métodos de criptografia e descriptografia da classe Cipher podem criptografar ou descriptografar alguns dos dados armazenados em uma matriz de bytes. O método update () e / ou doFinal () precisa passar o deslocamento e o comprimento.


 int offset = 10; int length = 24; byte[] cipherText = cipher.doFinal(data, offset, length); 

Neste exemplo, os bytes do índice 10 e 24 bytes avançados serão criptografados (ou descriptografados, dependendo da inicialização da cifra).


Criptografia / descriptografia para uma matriz de bytes existente


Todos os exemplos de criptografia e descriptografia neste capítulo retornam dados criptografados ou descriptografados em uma nova matriz de bytes. No entanto, também é possível criptografar ou descriptografar dados em uma matriz de bytes existente. Isso pode ser útil para reduzir o número de matrizes de bytes criadas. Para fazer isso, passe a matriz de bytes de destino como parâmetro para o método update () e / ou doFinal () .


 int offset = 10; int length = 24; byte[] dest = new byte[1024]; cipher.doFinal(data, offset, length, dest); 

Neste exemplo, os dados são criptografados de 10 índices 24 bytes para a matriz de bytes de destino com deslocamento 0. Se você deseja definir um deslocamento diferente para a matriz de bytes de destino, existem as versões update () e doFinal () que aceitam um parâmetro de compensação adicional. Um exemplo de chamada do método doFinal () com um deslocamento na matriz de destino:


 int offset = 10; int length = 24; byte[] dest = new byte[1024]; int destOffset = 12 cipher.doFinal(data, offset, length, dest, destOffset); 

Reutilizando uma Instância de uma Cifra


Inicializar uma instância de Cipher é uma operação cara e reutilizar instâncias de Cipher é uma boa idéia. Felizmente, a classe Cipher foi projetada com reutilização em mente. Quando você chama o método doFinal () na instância Cipher, ele retorna ao estado em que estava imediatamente após a inicialização. A instância de Cipher pode ser usada para criptografar ou descriptografar mais dados.


Um exemplo de reutilização de uma instância de Java Cipher:


 Cipher cipher = Cipher.getInstance("AES"); Key key = ... ///    cipher.init(Cipher.ENCRYPT_MODE, key); byte[] data1 = "abcdefghijklmnopqrstuvwxyz".getBytes("UTF-8"); byte[] data2 = "zyxwvutsrqponmlkjihgfedcba".getBytes("UTF-8"); byte[] cipherText1 = cipher.update(data1); byte[] cipherText2 = cipher.doFinal(data2); byte[] data3 = "01234567890123456789012345".getBytes("UTF-8"); byte[] cipherText3 = cipher.doFinal(data3); 

Primeiro, uma instância de Cipher é criada e inicializada e depois usada para criptografar dois blocos de dados consistentes. Observe a chamada para update () e, em seguida, doFinal () para esses dois blocos de dados. Depois disso, a instância Cipher pode ser usada novamente para criptografar os dados. Isso é feito chamando doFinal () com um terceiro bloco de dados. Após esta chamada para doFinal (), você pode criptografar outro bloco de dados com a mesma instância do Java Cipher.

Source: https://habr.com/ru/post/pt444814/


All Articles