Encriptar palavra-passe em ficheiros de configuração em Java
 
Criptografia é o processo de transformar informações de texto simples em uma forma ilegível usando um algoritmo de criptografia combinado com um parâmetro denominado chave de criptografia. O formato ilegível é geralmente conhecido como formato de ciphertext. Somente aqueles que possuem a chave de descriptografia podem descriptografar os dados e recuperar o texto original.
Podemos dividir o problema de criptografar senhas em arquivos de configuração em duas subtarefas a seguir.
- Criptografe a senha em texto simples que está no arquivo.
- Descriptografe a senha criptografada lida do arquivo.
Vamos primeiro criar um arquivo de configuração denominado arquivo config.properties no caminho src/conf/.
password = TestPassword123
Agora, para ler o arquivo de configuração, instancie a classe Properties. Podemos criar uma instância da classe FileInputStream usando seu construtor. Ele pega o caminho do arquivo de configuração como sua entrada. Agora, uma instância da classe de propriedades é usada para carregar as propriedades. Use o método load para carregar o arquivo de propriedades na classe, e isso leva a instância InputStreamReader como um parâmetro. Ele lança IllegalArgumentException se este fluxo de entrada contém uma sequência de escape Unicode malformada e IOException se um erro ocorreu durante a leitura do fluxo de entrada.
Depois que as propriedades forem carregadas com êxito, use o método getProperty() para pesquisar a propriedade com a chave especificada na lista de propriedades. O método retorna null se não for capaz de encontrar as propriedades. Faça uma verificação externa para lidar com essa situação e lance IllegalArgumentException se uma senha for considerada nula no arquivo.
salt é criado com qualquer string aleatória para adicionar à string da senha.
createSecretKey é um método definido pelo usuário que retorna a chave SecretKeySpec, e o uso da chave é para criptografar e descriptografar a senha. Os métodos encrypt e decrypt são métodos estáticos definidos pelo uso que foram fornecidos, na classe Encryption.
Abaixo está o código de exemplo que demonstra o mesmo.
package fileDataEncryption;
import static fileDataEncryption.Encryption.*;
import java.io.FileInputStream;
import java.util.Properties;
import javax.crypto.spec.SecretKeySpec;
public class ConfigFileEncryption {
  public static void main(String[] args) throws Exception {
    Properties properties = new Properties();
    FileInputStream inputStream = new FileInputStream("src/conf/config.properties");
    properties.load(inputStream);
    String password = properties.getProperty("password");
    if (password == null) {
      throw new IllegalArgumentException("No such parameter present in config file");
    }
    byte[] salt = new String("12345678").getBytes();
    int iterationCount = 40000;
    int keyLength = 128;
    SecretKeySpec key = createSecretKey(password.toCharArray(), salt, iterationCount, keyLength);
    String originalPassword = password;
    System.out.println("Original password: " + originalPassword);
    String encryptedPassword = encrypt(originalPassword, key);
    System.out.println("Encrypted password: " + encryptedPassword);
    String decryptedPassword = decrypt(encryptedPassword, key);
    System.out.println("Decrypted password: " + decryptedPassword);
  }
}
Uma descrição detalhada dos métodos definidos pelo usuário na classe Encryption é apresentada a seguir.
- O createSecretKeyé uma função que recebe parâmetros comopassword,salt,iterationCountekeyLength.passwordé a senha real no arquivo de configuração. Na criptografia, umsaltsão dados aleatórios que usamos como uma entrada adicional que faz o hash dos dados, uma senha ou uma frase secreta. O uso desaltsé para proteger as senhas no armazenamento. Usamos a variáveliterationCountcomo o número de iterações que um algoritmo deve realizar. Diminuir o valor das velocidades variáveis diminui o tempo de inicialização e, portanto, são úteis durante o teste, mas também torna mais fácil para atacantes de força bruta. A variávelkeyLengthé o comprimento da chave que precisamos derivar. Lança a exceção lançada a partir dos métodos usados.
- O método getInstancepercorre a lista de Provedores de segurança registrados, começando pelo Provedor preferido. Ele pega o nome padrão do algoritmo de chave secreta solicitado e retorna o novo objetoSecretKeyFactory. Ele lançaNullPointerExceptionse o algoritmo especificado for nulo eNoSuchAlgorithmExceptionse nenhum Provedor suportar uma implementaçãoSecretKeyFactorySpipara o algoritmo especificado.
- PBEKeySpecé um construtor de classe que pega uma senha, salt, contagem de iteração e comprimento de chave derivada para gerar- PBEKeyde cifras PBE de tamanho de chave variável. Ele lança- NullPointerExceptionse- saltfor- nulle- IllegalArgumentExceptionse sal estiver vazio.
- generateSecretgera um objeto- SecretKeya partir da especificação-chave fornecida ou do material-chave. Leva a especificação da chave secreta. Ele lança- InvalidKeySpecExceptionse a especificação fornecida for inadequada para esta fábrica de chave secreta para produzir um valor de chave classificado.
Detalhes do método encrypt na classe Encryption.
- O método encryptleva dois parâmetros, dados a serem criptografados e a chave. Este método lança exceções lançadas de métodos filhos nele.
- O método getInstancepercorre a lista de Provedores de segurança registrados, começando pelo Provedor preferido. Leva o nome da transformação, que é AES / CBC / PKCS5Padding. Ele lançaNoSuchAlgorithmExceptionse uma alteração for nula, vazia, em um formato inválido eNoSuchPaddingExceptionse a alteração contiver um esquema de preenchimento não disponível.
- O método initinicializa oCipherpara uma das seguintes quatro operações: criptografia, descriptografia, quebra de chave ou desempacotamento de chave, dependendo do valor do modo de operação.ENCRYPT_MODEno nosso caso. O método lançaUnsupportedOperationExceptionse o modo de operação for inválido eInvalidKeyExceptionse a chave fornecida for inadequada.
- O getParametersretorna os parâmetros usados com esta cifra.
- O getParameterSpecretorna uma especificação do objeto de parâmetro. O parâmetroparamSpecidentifica a classe de especificação na qual os parâmetros devem retornar. Por exemplo, poderia serDSAParameterSpec.classpara indicar que os parâmetros devem retornar em uma instância da classeDSAParameterSpec.
- O método doFinalcriptografa ou descriptografa dados em um trabalho de parte única ou conclui uma operação de várias partes. Os dados são criptografados ou descriptografados, dependendo de como inicializamos a cifra.
- base64Encodeé um método privado que codifica a matriz de bytes especificada em uma string usando o esquema de codificação- Base64. As funções usadas no método- descriptografarsão semelhantes ao método mencionado acima. A única diferença é que eles se comportam de maneira diferente com base no- modeespecificado na função,- DECRYPT_MODEcomo um modo de operação.
package fileDataEncryption;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class Encryption {
  public static SecretKeySpec createSecretKey(char[] password, byte[] salt, int iterationCount,
      int keyLength) throws NoSuchAlgorithmException, InvalidKeySpecException {
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
    PBEKeySpec keySpec = new PBEKeySpec(password, salt, iterationCount, keyLength);
    SecretKey keyTmp = keyFactory.generateSecret(keySpec);
    return new SecretKeySpec(keyTmp.getEncoded(), "AES");
  }
  public static String encrypt(String dataToEncrypt, SecretKeySpec key)
      throws GeneralSecurityException, UnsupportedEncodingException {
    Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    pbeCipher.init(Cipher.ENCRYPT_MODE, key);
    AlgorithmParameters parameters = pbeCipher.getParameters();
    IvParameterSpec ivParameterSpec = parameters.getParameterSpec(IvParameterSpec.class);
    byte[] cryptoText = pbeCipher.doFinal(dataToEncrypt.getBytes("UTF-8"));
    byte[] iv = ivParameterSpec.getIV();
    return base64Encode(iv) + ":" + base64Encode(cryptoText);
  }
  private static String base64Encode(byte[] bytes) {
    return Base64.getEncoder().encodeToString(bytes);
  }
  public static String decrypt(String string, SecretKeySpec key)
      throws GeneralSecurityException, IOException {
    String iv = string.split(":")[0];
    String property = string.split(":")[1];
    Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    pbeCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(base64Decode(iv)));
    return new String(pbeCipher.doFinal(base64Decode(property)), "UTF-8");
  }
  private static byte[] base64Decode(String property) throws IOException {
    return Base64.getDecoder().decode(property);
  }
}
Abaixo está a saída do código escrito para criptografar e descriptografar a senha no arquivo de configuração.
Original password: TestPassword123
Encrypted password: Hy7fbIwpyKgp0oileu+oLg==:WNRknMJz/8u8GmWlCZFPFA==
Decrypted password: TestPassword123
Rashmi is a professional Software Developer with hands on over varied tech stack. She has been working on Java, Springboot, Microservices, Typescript, MySQL, Graphql and more. She loves to spread knowledge via her writings. She is keen taking up new things and adopt in her career.
LinkedIn