Compartilhe os password
(a char[]
) e salt
(a - byte[]
8 bytes selecionados por um SecureRandom
faz um bom sal - que não precisa ser mantido em segredo) com o destinatário fora da banda. Em seguida, para obter uma boa chave dessas informações:
/* Derive the key, given password and salt. */
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Os números mágicos (que podem ser definidos como constantes em algum lugar) 65536 e 256 são a contagem de iterações de derivação de chave e o tamanho da chave, respectivamente.
A função de derivação de chave é iterada para exigir um esforço computacional significativo e impede que os invasores tentem rapidamente muitas senhas diferentes. A contagem de iterações pode ser alterada dependendo dos recursos de computação disponíveis.
O tamanho da chave pode ser reduzido para 128 bits, o que ainda é considerado criptografia "forte", mas não oferece grande margem de segurança se forem descobertos ataques que enfraquecem o AES.
Usado com um modo de encadeamento de blocos adequado, a mesma chave derivada pode ser usada para criptografar muitas mensagens. No Cipher Block Chaining (CBC) , um vetor de inicialização aleatória (IV) é gerado para cada mensagem, produzindo texto cifrado diferente, mesmo que o texto sem formatação seja idêntico. O CBC pode não ser o modo mais seguro disponível para você (consulte AEAD abaixo); existem muitos outros modos com diferentes propriedades de segurança, mas todos eles usam uma entrada aleatória semelhante. De qualquer forma, as saídas de cada operação de criptografia são o texto cifrado e o vetor de inicialização:
/* Encrypt the message. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal("Hello, World!".getBytes("UTF-8"));
Armazene o ciphertext
e o iv
. Na descriptografia, o SecretKey
é regenerado exatamente da mesma maneira, usando a senha com os mesmos parâmetros de sal e iteração. Inicialize a cifra com essa chave e o vetor de inicialização armazenado com a mensagem:
/* Decrypt the message, given derived key and initialization vector. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
String plaintext = new String(cipher.doFinal(ciphertext), "UTF-8");
System.out.println(plaintext);
O Java 7 incluiu suporte à API para modos de cifra AEAD , e o provedor "SunJCE" incluído nas distribuições OpenJDK e Oracle implementa estes a partir do Java 8. Um desses modos é altamente recomendado no lugar do CBC; protegerá a integridade dos dados, bem como a sua privacidade.
A java.security.InvalidKeyException
com a mensagem "Tamanho da chave ilegal ou parâmetros padrão" significa que a força da criptografia é limitada; os arquivos de política de jurisdição de força ilimitada não estão no local correto. Em um JDK, eles devem ser colocados em${jdk}/jre/lib/security
Com base na descrição do problema, parece que os arquivos de políticas não foram instalados corretamente. Os sistemas podem facilmente ter vários tempos de execução Java; verifique duas vezes para garantir que o local correto esteja sendo usado.