Uma maneira simples de fazer isso é usar a criptografia baseada em senha em Java. Isso permite criptografar e descriptografar um texto usando uma senha.
Isso basicamente significa inicializar um javax.crypto.Cipher
com o algoritmo "AES/CBC/PKCS5Padding"
e obter uma chave javax.crypto.SecretKeyFactory
com o "PBKDF2WithHmacSHA512"
algoritmo.
Aqui está um exemplo de código (atualizado para substituir a variante menos segura baseada em MD5):
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 ProtectedConfigFile {
public static void main(String[] args) throws Exception {
String password = System.getProperty("password");
if (password == null) {
throw new IllegalArgumentException("Run with -Dpassword=<password>");
}
// The salt (probably) can be stored along with the encrypted data
byte[] salt = new String("12345678").getBytes();
// Decreasing this speeds down startup time and can be useful during testing, but it also makes it easier for brute force attackers
int iterationCount = 40000;
// Other values give me java.security.InvalidKeyException: Illegal key size or default parameters
int keyLength = 128;
SecretKeySpec key = createSecretKey(password.toCharArray(),
salt, iterationCount, keyLength);
String originalPassword = "secret";
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);
}
private 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");
}
private static String encrypt(String property, 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(property.getBytes("UTF-8"));
byte[] iv = ivParameterSpec.getIV();
return base64Encode(iv) + ":" + base64Encode(cryptoText);
}
private static String base64Encode(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}
private 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);
}
}
Um problema permanece: onde você deve armazenar a senha usada para criptografar as senhas? Você pode armazená-lo no arquivo de origem e ofuscá-lo, mas não é muito difícil encontrá-lo novamente. Como alternativa, você pode atribuí-lo como uma propriedade do sistema ao iniciar o processo Java ( -DpropertyProtectionPassword=...
).
O mesmo problema permanece se você usar o KeyStore, que também é protegido por uma senha. Basicamente, você precisará ter uma senha mestra em algum lugar e é muito difícil de proteger.
Sim, definitivamente não escreva seu próprio algoritmo. Java possui muitas APIs de criptografia.
Se o sistema operacional em que você está instalando tiver um armazenamento de chaves, você poderá usá-lo para armazenar suas chaves criptográficas que serão necessárias para criptografar e descriptografar os dados confidenciais em sua configuração ou em outros arquivos.
fonte
Confira jasypt , que é uma biblioteca que oferece recursos básicos de criptografia com o mínimo de esforço.
fonte
Eu acho que a melhor abordagem é garantir que seu arquivo de configuração (contendo sua senha) seja acessível apenas a uma conta de usuário específica . Por exemplo, você pode ter um usuário específico do aplicativo
appuser
para o qual apenas pessoas confiáveis tenham a senha (e para a qual elessu
).Dessa forma, não há sobrecarga de criptografia irritante e você ainda tem uma senha segura.
EDIT: Estou assumindo que você não está exportando a configuração do aplicativo para fora de um ambiente confiável (o que não tenho certeza se faria sentido, dada a pergunta)
fonte
Bem, para resolver os problemas da senha mestra - a melhor abordagem é não armazenar a senha em nenhum lugar, o aplicativo deve criptografar senhas para si mesmo - para que somente ele possa descriptografá-las. Portanto, se eu estivesse usando um arquivo .config, faria o seguinte, mySettings.config :
para ler as chaves mencionadas nas encryptTheseKeys, aplique o exemplo Brodwalls acima e escreva-as de volta no arquivo com um marcador de algum tipo (digamos crypt :) para que o aplicativo saiba que não deve fazê-lo novamente, a saída ficaria assim:
Certifique-se de manter os originais em seu próprio local seguro ...
fonte
O grande ponto, e o elefante na sala e tudo isso, é que, se seu aplicativo pode se apossar da senha, um hacker com acesso à caixa também pode se apossar dela!
A única maneira de contornar isso é que o aplicativo solicita a "senha mestra" no console usando a Entrada padrão e, em seguida, usa isso para descriptografar as senhas armazenadas no arquivo. Obviamente, isso impossibilita a inicialização automática do aplicativo junto com o sistema operacional quando ele é inicializado.
No entanto, mesmo com esse nível de aborrecimento, se um hacker conseguir obter acesso root (ou apenas acessar como o usuário executando seu aplicativo), ele poderá despejar a memória e encontrar a senha lá.
O que deve ser garantido é não permitir que toda a empresa tenha acesso ao servidor de produção (e, portanto, às senhas) e verifique se é impossível quebrar essa caixa!
fonte
Tente usar os métodos de criptografia ESAPIs. É fácil de configurar e você também pode alterar facilmente suas chaves.
http://owasp-esapi-java.googlecode.com/svn/trunk_doc/latest/org/owasp/esapi/Encryptor.html
Vocês
1) criptografar 2) descriptografar 3) assinar 4) cancelar assinatura 5) hash 6) assinaturas baseadas em tempo e muito mais com apenas uma biblioteca.
fonte
Veja o que está disponível no Jetty para armazenar senhas (ou hashes) nos arquivos de configuração e considere se a codificação OBF pode ser útil para você. Então veja na fonte como isso é feito.
http://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html
fonte
Dependendo de quão seguro você precise dos arquivos de configuração ou de quão confiável é seu aplicativo, http://activemq.apache.org/encrypted-passwords.html pode ser uma boa solução para você.
Se você não tem muito medo da senha ser descriptografada e pode ser realmente simples de configurar usando um bean para armazenar a chave da senha. No entanto, se você precisar de mais segurança, poderá definir uma variável de ambiente com o segredo e removê-la após o lançamento. Com isso, você precisa se preocupar com a queda do aplicativo / servidor e não com o reinício automático do aplicativo.
fonte
Se você estiver usando o java 8, o uso do codificador e decodificador interno Base64 pode ser evitado substituindo-o
return new BASE64Encoder().encode(bytes);
com
return Base64.getEncoder().encodeToString(bytes);
e
return new BASE64Decoder().decodeBuffer(property);
com
return Base64.getDecoder().decode(property);
Observe que esta solução não protege seus dados, pois os métodos para descriptografar são armazenados no mesmo local. Isso apenas torna mais difícil quebrar. Evita principalmente imprimi-lo e mostrá-lo a todos por engano.
fonte