Criptografia de chave privada - simétrica

Criptografia de chave privada - simétrica

Criptografia de chave privada - simétrica

A criptografia usando uma chave privada tem como objetivo utilizar uma chave que serve tanto para criptografar como para descriptografar. Este tipo de criptografia é utilizado quando ambos origem e destino possuem acesso a mesma chave.

Implementando criptografia com AES

O código de implementação do uso da criptografia simétrica usando AES, apresentado a seguir é uma adaptação do código disponível no livro de DASWANI, N.; KERN, C.; KESAVAN, A. página 211.

Vamos começar declarando os atributos que vamos utilizar na classe e o construtor:

public classe CriptografiaSimetrica {
  private static final int KEY_SIZE = 16;
  private static final int IV_SIZE = 16;
  private static final int BUFFER_SIZE = 1024;

  private Cipher cifra;
  private SecretKey chave;
  private AlgorithmParameterSpec ivSpec;
  private byte[] buf = new byte[BUFFER_SIZE];
  private byte[] ivBytes = new byte[IV_SIZE];

  public CriptografiaSimetrica(SecretKey chave) throws Exception {
    this.cifra = Cipher.getInstance("AES/CBC/PKCS5Padding");
    this.chave = chave;
  }

  // Implemente os métodos a seguir aqui.

No método main vamos criar uma chave privada e guardar ela dentro de um arquivo chamado MinhaChave. Depois vamos utilizar a criptografia simetrica AES para ler o conteúdo do arquivo TextoOriginal.txt e gravar seu conteúdo criptografado no arquivo Criptografado.txt.

  public static void main(String[] args) throws Exception {
    // Nome do arquivo com que será salvo a chave gerada.
    String arquivoChave = "MinhaChave";
    // Cria e salva a chave no arquivo.
    criarChave(arquivoChave);
    //Carrega a chave que foi gerada.
    SecretKeySpec keySpec = lerChave(arquivoChave);

    // Inicializa a classe de criptografia com a chave simétrica.
    CriptografiaSimetrica aes = new CriptografiaSimetrica(keySpec);
    // Criptografa o conteúdo do arquivo.
    aes.criptografar(new FileInputStream("TextoOriginal.txt"), new
      FileOutputStream("Criptografado.txt"));
    // Descriptografa o conteúdo do arquivo.
    aes.descriptografar(new FileInputStream("Criptografado.txt"), new 
      FileOutputStream("Saida.txt"));
  }

No construtor foi definido this.cifra = Cipher.getInstance("AES/CBC/PKCS5Padding"); que informa o algoritmo de criptografia AES que será utilizado e também recebe a chave que será utilizada pela criptografia.

Essa chave recebida no construtor deve ser criada previamente, o método public static void criarChave(String nomeArquivo) throws Exception implementa uma forma de criar a chave privada usando a criptografia AES. Esse método recebe como parâmetro um caminho para salvar o arquivo contendo a chave privada.

  public static void criarChave(String nomeArquivo) throws Exception {
    // Define o gerador de chaves AES.
    KeyGenerator kg = KeyGenerator.getInstance("AES");
    // Tamanho da chave. Nesse exemplo KEY_SIZE é igual 16, portanto a chave é de 128 bits.
    kg.init(KEY_SIZE * 8);
    // Gera uma nova chave.
    SecretKey chave = kg.generateKey();

    // Salva a chave em um arquivo.
    FileOutputStream fos = new FileOutputStream(nomeArquivo);
    fos.write(chave.getEncoded());
    fos.close();
  }

O método public static SecretKeySpec lerChave(String nomeArquivo) throws Exception recebe como parâmetro o caminho do arquivo contendo a chave privada e carrega um objeto SecretKeySpec que representa essa chave.

public static SecretKeySpec lerChave(String nomeArquivo) throws Exception {
  // Lê o conteúdo do arquivo e guarda no vetor de bytes.
  byte bytesChave[] = new byte[KEY_SIZE];
  FileInputStream fis = new FileInputStream(nomeArquivo);
  fis.read(bytesChave);

  // Cria uma chave AES com os bytes lidos.
  return new SecretKeySpec(bytesChave, "AES");
}

O método public void criptografar(InputStream in, OutputStream out) throws Exception recebe um arquivo de entrada com o conteúdo original e um arquivo de saída no qual será gravado o conteúdo criptografado do arquivo de entrada usando o AES.

public void criptografar(InputStream in, OutputStream out) throws Exception {
  // Gera um conjunto de bytes aleatórios.
  ivBytes = createRandBytes(IV_SIZE);
  // Guarda os bytes gerados aleatoriamente no arquivo com o conteúdo criptografado.
  out.write(ivBytes);
  // Cria um vetor de inicialização para a criptografia.
  ivSpec = new IvParameterSpec(ivBytes);
  // Inicializa o algoritmo de criptografia definindo: modo de criptografia, chave e o vetor de inicialização.
  cifra.init(Cipher.ENCRYPT_MODE, chave, ivSpec);
  // Cria um stream que recebe uma entrada descriptografada para criptografar.
  CipherOutputStream cipherOut = new CipherOutputStream(out, cifra);
  // Lê uma parte da entrada, se essa parte lida tiver um tamanho maior que zero, então criptografa e guarda no arquivo de saída.
  int numLido = 0;
  while ((numLido = in.read(buf)) >= 0)
    cipherOut.write(buf, 0, numLido);
  cipherOut.close();
}

O método public static byte[] createRandBytes(int numBytes) throws NoSuchAlgorithmException cria um array de bytes contendo uma sequência aleatória.

public static byte[] createRandBytes(int numBytes) throws NoSuchAlgorithmException {
  byte[] bytesBuffer = new byte[numBytes];

  /* Utiliza um sistema mais seguro de geração de números aleatórios, que 
     dificulta adivinhar qual será o próximo número aleatório gerado. */
  SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
  // Guarda os bytes gerados nesse array.
  sr.nextBytes(bytesBuffer);

  return bytesBuffer;
}

O método public void descriptografar(InputStream in, OutputStream out) throws Exception recebe como entrada no parâmetro in o arquivo que está criptografado e no parâmetro out o caminho do arquivo onde será gravado o arquivo descriptografado.

public void descriptografar(InputStream in, OutputStream out) throws Exception {
  // Lê os bytes aleatórios e cria o vetor de inicialização para a criptografia.
  in.read(ivBytes);
  ivSpec = new IvParameterSpec(ivBytes);
  // Inicializa o algoritmo de criptografia definindo: modo de descriptografia, chave e o vetor de inicialização.
  cifra.init(Cipher.DECRYPT_MODE, chave, ivSpec);
  // Cria um stream que recebe uma entrada criptografada para descriptografar.
  CipherInputStream cipherIn = new CipherInputStream(in, cifra);
  /* Lê uma parte da entrada, se essa parte lida tiver um tamanho maior que zero, 
     então descriptografa e guarda no arquivo de saída. */
  int numLido = 0;
  while ((numLido = cipherIn.read(buf)) >= 0) {
    out.write(buf, 0, numLido);
  }
  out.close();
}
Criptografar e descriptografar usando AES.

Referência

[DASWANI, N.; KERN, C.; KESAVAN, A.] Foundations of Security. United States of America: Apress, 2007.

Conteúdos relacionados