Como cifrar o texto em Java
o que eu preciso é de encriptar a cadeia de caracteres que irá aparecer no código de barras 2D(PDF-417) para que quando alguém tiver uma ideia para digitalizá-la não fique nada legível.
outros requisitos:
- não deve ser complicado
- não deve consistir em RSA, infra-estrutura PKI, pares de chaves, etc.
provavelmente essas empresas poderiam usar tecnologias diferentes, por isso seria bom manter algum padrão que não esteja ligado a alguma plataforma ou tecnologia especial.
O que sugeres? Existe alguma classe Java a fazer o encrypt() decrypt () sem muita complicação em alcançar elevados padrões de segurança?15 answers
Eu recomendaria usar um cypher simétrico padrão que está amplamente disponível como DES, 3DES ou AES . Embora esse não seja o algoritmo mais seguro, existem muitas implementações e você só precisa dar a chave para qualquer um que é suposto descriptografar a informação no código de barras. Javax.criptografia.Cipher é com o que queres trabalhar aqui.
Vamos assumir que os bytes para cifrar estão em
byte[] input;
Seguinte, vais precisar da chave e do vector de inicialização {[[22]}bytes
byte[] keyBytes;
byte[] ivBytes;
Agora você pode inicializar a cifra para o algoritmo que você selecionar:
// wrap key data in Key/IV specs to pass to cipher
SecretKeySpec key = new SecretKeySpec(keyBytes, "DES");
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
// create the cipher with the algorithm you choose
// see javadoc for Cipher class for more info, e.g.
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
A encriptação iria assim:
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
byte[] encrypted= new byte[cipher.getOutputSize(input.length)];
int enc_len = cipher.update(input, 0, input.length, encrypted, 0);
enc_len += cipher.doFinal(encrypted, enc_len);
E decriptação como esta:
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
byte[] decrypted = new byte[cipher.getOutputSize(enc_len)];
int dec_len = cipher.update(encrypted, 0, enc_len, decrypted, 0);
dec_len += cipher.doFinal(decrypted, dec_len);
Esta é a primeira página que aparece através do Google e da segurança. as vulnerabilidades em todas as implementações fazem-me encolher, por isso ... publicar isto para adicionar informações sobre a encriptação para outros como ele foi 7 anos desde a publicação original. Eu tenho um Mestrado em Engenharia Informática e passou muito tempo estudando e aprendendo Criptografia por isso estou a dar a minha opinião para fazer da internet um seguro.Também, note que muita implementação pode ser segura para um dado situação, mas porquê usá-los e potencialmente fazer acidentalmente um erro? Use as ferramentas mais fortes que você tem disponíveis a menos que você tenha um razão específica para não o fazer. No geral, aconselho vivamente a utilização de uma biblioteca e ficar longe dos pormenores, se puder.
UPDATE 4/5/18: I rewrote some parts to make them simpler to understand and changed the recommended library from Jasypt to Google ' s new library Tink , eu recomendaria remover completamente Jasypt de uma configuração existente.
Prefácio
Vou delinear os princípios básicos da criptografia simétrica segura abaixo e apontar os erros comuns que vejo online quando as pessoas implementam criptografia por conta própria com a biblioteca Java padrão. Se quiser simplesmente saltar todos os detalhes corridos para a nova Biblioteca do Google Tink importá-los para o seu projecto e usar o modo AES-GCM para todos os seus encriptações e você estará seguro.Agora se quiser aprender os detalhes mais importantes sobre como encriptar em java leia em:)
Cifras De Bloco
Primeiro, tens de escolher uma cifra de bloco simétrico. Uma cifra de bloco é uma função de computador / programa usado para criar Pseudo-aleatoriedade. Pseudo-aleatoriedade é falsa aleatoriedade que nenhum computador além de um computador quântico seria capaz de dizer a diferença entre ele e aleatoriedade real. bloco A cifra é como o bloco de construção da criptografia, e quando usada com diferentes modos ou esquemas podemos criar criptografias.Agora em relação aos algoritmos de cifra de bloco disponíveis hoje, certifique-se de nunca, eu repito nunca use DES, eu diria mesmo que nunca use 3DES. A única cifra de bloco que até a NSA de Snowden conseguiu verificar ser o mais próximo possível Do Pseudo-aleatório é AES 256 . Existe também AES 128, a a diferença é que AES 256 funciona em blocos de 256 bits, enquanto AES 128 funciona em 128 blocos. No total, o AES 128 é considerado seguro, embora algumas fraquezas tenham sido descobertas, mas 256 é o mais sólido possível.
O fato divertido do DES foi quebrado pela NSA quando foi inicialmente fundada e manteve um segredo por alguns anos e embora algumas pessoas ainda afirmem que 3DES } é seguro, existem alguns trabalhos de pesquisa que encontraram e analisaram fraquezas em 3DES .Modos De Cifra
A encriptação é criada quando se pega numa cifra em bloco e se usa um esquema específico para que a aleatoriedade seja combinada com uma chave para criar algo que seja reversível, desde que se conheça a chave. Isto é referido como um modo de encriptação.
Aqui está um exemplo de um modo de encriptação e o modo mais simples conhecido como BCE, só para que possa compreender visualmente o que está a acontecer:
A os modos de encriptação que irá ver mais frequentemente 'online' são os seguintes:
BCE CTR, CBC, GCM
Existem outros modos fora dos listados e os pesquisadores estão sempre trabalhando em direção a novos modos para melhorar os problemas existentes. Passemos agora às implementações e ao que é seguro. nuncause o BCE isto é mau a esconder dados repetitivos como mostrado pelo famoso Linux penguin.Ao implementar em Java, note que, se utilizar o seguinte código, o modo BCE é definido por omissão:
Cipher cipher = Cipher.getInstance("AES");
... PERIGO ISTO É UMA VULNERABILIDADE!E infelizmente, isso é visto em todo o StackOverflow e online em tutoriais e exemplos.
Nonces e IVs
Em resposta à questão encontrada com os nomes do modo BCE também conhecidos como IVs foram criados. A idéia é que nós geramos uma nova variável aleatória e anexá-la a cada criptografia de modo que quando você criptografar duas mensagens que são as mesmas eles saem diferentes. A beleza por trás disso é que um IV ou nonce é conhecimento público. Isso significa que um atacante pode ter acesso a isto, mas desde que não tenham a sua chave, não podem fazer nada com esse conhecimento.
Questões comuns eu vou ver é que as pessoas vão definir o IV como um valor estático como no mesmo valor fixo em seu código. e aqui está a armadilha para IVs no momento em que você repetir Uma você realmente comprometer toda a segurança de seu criptografia.
Gerar um IV Aleatório
SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG");
byte[] iv = new byte[cipher.getBlockSize()];
randomSecureRandom.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);
Nota: O SHA1 está avariado, mas não consegui encontrar como implementar o SHA256 neste caso de uso correctamente, por isso, se alguém quiser tentar resolver isto e actualizá-lo, seria fantástico! Também ataques SHA1 ainda são pouco convencionais, pois pode levar alguns anos em um enorme aglomerado para quebrar. Vê os detalhes aqui.
Implementação CTR
Não é necessário enchimento para o CTR modo.
Cipher cipher = Cipher.getInstance("AES/NoPadding");
Implementação do CBC
Se optar por implementar o modo CBC, faça-o com o PKCS7Padding do seguinte modo:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
Vulnerabilidade CBC e CTR e por que você deve usar GCM
Embora alguns outros modos como o CBC e o CTR sejam seguros, eles correm para o problema onde um atacante pode rodar os dados encriptados, alterando o seu valor quando descodificado. Digamos que encripta uma mensagem de banco imaginária "vender 100", a sua mensagem encriptada parece-se com isto. "eu23ng "o atacante muda um pouco para" eu53ng "e, de repente, quando descriptografado sua mensagem, lê-se como"Sell 900".
Para evitar isso, a maioria da internet usa GCM, e cada vez que você vê HTTPS eles provavelmente estão usando GCM. O GCM assina a mensagem cifrada com um hash e verifica se a mensagem não foi alterada com esta assinatura.
Eu evitaria a implementação do MGC devido à sua complexidade. É melhor usar a biblioteca nova do Google Sininho porque aqui novamente se você acidentalmente repetir uma IV você está comprometendo a chave no caso com GCM, que é a falha de segurança final. Os novos investigadores estão a trabalhar no sentido de modos de encriptação resistentes à repetição IV, onde, mesmo que repita a IV, a chave não está em perigo, mas isto ainda não chegou à corrente principal. Agora, se você quer implementar o GCM, aqui está um link para uma boa implementação do GCM . No entanto, não posso garantir a segurança ou se a sua correcta implementação mas diminui a base. Também nota com GCM não há enchimento.Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
Chaves vs Senhas
Outra nota muito importante, é que quando se trata de criptografia uma chave e uma senha não são as mesmas coisas. Uma chave na criptografia precisa ter uma certa quantidade de entropia e aleatoriedade para ser considerada segura. É por isso que você precisa se certificar de usar as bibliotecas criptográficas adequadas para gerar a chave para você. Então tens mesmo dois. implementações que você pode fazer aqui, a primeira é usar o código encontrado em este tópico StackOverflow para geração de chave aleatória . Esta solução usa um gerador de números aleatórios seguros para criar uma chave a partir do zero que você pode usar.A outra opção menos segura é usar, a entrada do utilizador, como uma senha. A questão como discutimos é que a senha não tem entropia suficiente, então teríamos que usar PBKDF2 , um algoritmo que pega a senha e fortalece ele. Aqui está uma implementação StackOverflow que eu gostei . No entanto Google Sink library tem tudo isso incorporado e você deve tirar proveito dele.
Programadores Android
Um ponto importante a salientar aqui é saber que o seu código android é reverso motorerable e a maioria dos casos código java também é. Isso significa que se você armazenar a senha em texto simples em seu código. Um hacker pode facilmente recuperá-lo. Normalmente, para este tipo de criptografia, você quer usar Criptografia assimétrica e assim por diante. Este é fora do escopo deste post assim que eu evitarei mergulhar nele.
Uma leitura interessante de 2013 aponta que 88% das implementações criptográficas no Android foram feitas de forma inadequada.Pensamentos Finais
Mais uma vez, sugiro que evite a implementação da biblioteca java para crypto diretamente e que utilize o Google Sink , irá poupar-lhe a dor de cabeça, uma vez que eles realmente fizeram um bom trabalho de implementação de todas as algoritmos correctamente. E, mesmo assim, certifique-se de verificar os problemas levantados no sininho, as vulnerabilidades aparecem aqui e ali.Se você tem alguma dúvida ou feedback sinta-se livre para comentar! A segurança está sempre mudando e você precisa fazer o seu melhor para acompanhá-la:)
Aviso
Não uses isto como uma medida de segurança.
O mecanismo de criptografia neste post é um pad único, o que significa que a chave secreta pode ser facilmente recuperada por um atacante usando 2 mensagens criptografadas. XOR 2 mensagens criptografadas e você recebe a chave. É simples!
Apontado por Moussa
Estou a usar o Base64Encoder / descodificador da Sun, que se encontra no JRE da Sun, para evitar ainda outro frasco em lib. Isso é perigoso do ponto de usar o OpenJDK ou o JRE de outro. Além disso, há outra razão que eu deva considerar usar o Apache commons lib com codificador/decodificador?
public class EncryptUtils {
public static final String DEFAULT_ENCODING = "UTF-8";
static BASE64Encoder enc = new BASE64Encoder();
static BASE64Decoder dec = new BASE64Decoder();
public static String base64encode(String text) {
try {
return enc.encode(text.getBytes(DEFAULT_ENCODING));
} catch (UnsupportedEncodingException e) {
return null;
}
}//base64encode
public static String base64decode(String text) {
try {
return new String(dec.decodeBuffer(text), DEFAULT_ENCODING);
} catch (IOException e) {
return null;
}
}//base64decode
public static void main(String[] args) {
String txt = "some text to be encrypted";
String key = "key phrase used for XOR-ing";
System.out.println(txt + " XOR-ed to: " + (txt = xorMessage(txt, key)));
String encoded = base64encode(txt);
System.out.println(" is encoded to: " + encoded + " and that is decoding to: " + (txt = base64decode(encoded)));
System.out.print("XOR-ing back to original: " + xorMessage(txt, key));
}
public static String xorMessage(String message, String key) {
try {
if (message == null || key == null) return null;
char[] keys = key.toCharArray();
char[] mesg = message.toCharArray();
int ml = mesg.length;
int kl = keys.length;
char[] newmsg = new char[ml];
for (int i = 0; i < ml; i++) {
newmsg[i] = (char)(mesg[i] ^ keys[i % kl]);
}//for i
return new String(newmsg);
} catch (Exception e) {
return null;
}
}//xorMessage
}//class
Cifra de objectos
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class ObjectCrypter {
private Cipher deCipher;
private Cipher enCipher;
private SecretKeySpec key;
private IvParameterSpec ivSpec;
public ObjectCrypter(byte[] keyBytes, byte[] ivBytes) {
// wrap key data in Key/IV specs to pass to cipher
ivSpec = new IvParameterSpec(ivBytes);
// create the cipher with the algorithm you choose
// see javadoc for Cipher class for more info, e.g.
try {
DESKeySpec dkey = new DESKeySpec(keyBytes);
key = new SecretKeySpec(dkey.getKey(), "DES");
deCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
enCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public byte[] encrypt(Object obj) throws InvalidKeyException, InvalidAlgorithmParameterException, IOException, IllegalBlockSizeException, ShortBufferException, BadPaddingException {
byte[] input = convertToByteArray(obj);
enCipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
return enCipher.doFinal(input);
// cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
// byte[] encypted = new byte[cipher.getOutputSize(input.length)];
// int enc_len = cipher.update(input, 0, input.length, encypted, 0);
// enc_len += cipher.doFinal(encypted, enc_len);
// return encypted;
}
public Object decrypt( byte[] encrypted) throws InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, IOException, ClassNotFoundException {
deCipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
return convertFromByteArray(deCipher.doFinal(encrypted));
}
private Object convertFromByteArray(byte[] byteObject) throws IOException,
ClassNotFoundException {
ByteArrayInputStream bais;
ObjectInputStream in;
bais = new ByteArrayInputStream(byteObject);
in = new ObjectInputStream(bais);
Object o = in.readObject();
in.close();
return o;
}
private byte[] convertToByteArray(Object complexObject) throws IOException {
ByteArrayOutputStream baos;
ObjectOutputStream out;
baos = new ByteArrayOutputStream();
out = new ObjectOutputStream(baos);
out.writeObject(complexObject);
out.close();
return baos.toByteArray();
}
}
private static byte[] xor(final byte[] input, final byte[] secret) {
final byte[] output = new byte[input.length];
if (secret.length == 0) {
throw new IllegalArgumentException("empty security key");
}
int spos = 0;
for (int pos = 0; pos < input.length; ++pos) {
output[pos] = (byte) (input[pos] ^ secret[spos]);
++spos;
if (spos >= secret.length) {
spos = 0;
}
}
return output;
}
Funciona bem para mim e é bastante compacto.
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("singleton")
public class Encryptor {
@Value("${aeskey}")
private String keyStr;
private Key aesKey = null;
private Cipher cipher = null;
synchronized private void init() throws Exception {
if (keyStr == null || keyStr.length() != 16) {
throw new Exception("bad aes key configured");
}
if (aesKey == null) {
aesKey = new SecretKeySpec(keyStr.getBytes(), "AES");
cipher = Cipher.getInstance("AES");
}
}
synchronized public String encrypt(String text) throws Exception {
init();
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
return toHexString(cipher.doFinal(text.getBytes()));
}
synchronized public String decrypt(String text) throws Exception {
init();
cipher.init(Cipher.DECRYPT_MODE, aesKey);
return new String(cipher.doFinal(toByteArray(text)));
}
public static String toHexString(byte[] array) {
return DatatypeConverter.printHexBinary(array);
}
public static byte[] toByteArray(String s) {
return DatatypeConverter.parseHexBinary(s);
}
/*
* DO NOT DELETE
*
* Use this commented code if you don't like using DatatypeConverter dependency
*/
// public static String toHexStringOld(byte[] bytes) {
// StringBuilder sb = new StringBuilder();
// for (byte b : bytes) {
// sb.append(String.format("%02X", b));
// }
// return sb.toString();
// }
//
// public static byte[] toByteArrayOld(String s) {
// int len = s.length();
// byte[] data = new byte[len / 2];
// for (int i = 0; i < len; i += 2) {
// data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i +
// 1), 16));
// }
// return data;
// }
}
Eu consideraria usar algo como https://www.bouncycastle.org/ é uma biblioteca pré-construída que lhe permite cifrar o que quiser com várias Cifras diferentes Compreendo que só queiras proteger-te de bisbilhotar, mas se queres mesmo proteger a informação, usar o Base64 não te vai proteger.
Aqui estão algumas ligações que você pode ler o que o Java Suporta
Cifrar / descodificar uma transmissão de dados.
Este exemplo demonstra como cifrar (usando uma cifra simétrica algoritmo como AES, Blowfish, RC2, 3DES, etc) uma grande quantidade de dados. O os dados são passados em pedaços a um dos métodos de cifragem: cifrar Porytes, EncryptString, EncryptBytesENC, ou EncryptStringENC. (O nome do método indica o tipo de entrada (texto ou lista de 'bytes') e o tipo de retorno (texto codificado ou lista de 'bytes'). O Propriedades FirstChunk e LastChunk são usados para indicar se um bloco é o primeiro, médio, ou último em um transmissão a codificar. Por omissão, ambos os primeiros e últimos iguais verdadeiro -- significando que os dados passaram é o montante total.
Pode usar Jasypt
Com o Jasypt, encriptar e verificar uma senha pode ser tão simples quanto isso...
StrongTextEncryptor textEncryptor = new StrongTextEncryptor();
textEncryptor.setPassword(myEncryptionPassword);
Encriptação:
String myEncryptedText = textEncryptor.encrypt(myText);
Descodificação:
String plainText = textEncryptor.decrypt(myEncryptedText);
Enxada:
compile group: 'org.jasypt', name: 'jasypt', version: '1.9.2'
Características:
O Jasypt fornece-lhe técnicas de encriptação simples e unidireccionais (digest) e bidireccionais.
Abra a API para ser usada com qualquer provedor JCE, e não apenas o padrão Java VM one. Jasypt pode ser facilmente usado com provedores bem conhecidos como Bouncy Castle. Aprender.
Maior segurança para as senhas dos seus utilizadores. Aprender.
Suporte de encriptação binária. Jasypt permite a digestão e criptografia de binários (matrizes de bytes). Encriptar os seus objectos ou ficheiros quando necessário (por ser enviado pela rede, por exemplo).
Suporte de encriptação de Números. Além de textos e binários, permite a digestão e criptografia de valores numéricos (BigInteger e binários). BigDecimal, outros tipos numéricos são suportados ao cifrar para a persistência do hibernado). Aprender.
Completamente seguro.Suporte para o Encryptor/digester pooling, a fim de obter um elevado desempenho em sistemas multi-processadores / multi-núcleos.
Inclui uma versão leve ("lite") da biblioteca para uma melhor gestão em ambientes restritivos de tamanho, como plataformas móveis.
Oferece ambas as ferramentas de encriptação simples e sem configuração para usuários novos em criptografia, e também ferramentas de criptografia padrão altamente configuráveis, para usuários de energia.
Hibernar 3 e 4 integração opcional para campos persistentes das suas entidades mapeadas de uma forma encriptada. Criptografia de Campos é definida nos arquivos de mapeamento hibernado, e permanece transparente para o resto da aplicação (útil para dados pessoais sensíveis, bases de dados com muitos usuários habilitados a leitura...). Encriptar textos, binários, números, booleanos, datas... Aprender.
Perfeitamente integráveis numa aplicação de primavera, com características específicas de integração para a Primavera 2, Primavera 3.0 e primavera 3.1. Todos os digestores e criptógrafos em jasypt são projetados para serem facilmente usados (instanciados, dependentes-injetados...) from Spring. E, por serem seguros por fio, podem ser usados sem preocupações de sincronização num ambiente orientado para singleton como a Primavera. Saiba mais: Primavera 2, Primavera 3.0, Primavera 3.1.
Segurança Da Primavera (anteriormente Acegi) Segurança) integração opcional para a realização de criptografia de senha e tarefas de correspondência para a estrutura de segurança, melhorando a segurança das senhas de seus usuários, usando mecanismos de criptografia de senha mais seguros e proporcionando-lhe um maior grau de configuração e controle. Aprender.Oferece uma funcionalidade avançada para cifrar todos ou parte dos ficheiros de configuração de uma aplicação, incluindo informações sensíveis como senhas de bases de dados. Integração perfeita cifrada configuração em aplicações simples, baseadas em molas e/ou hibernadas. Aprender.
Oferece ferramentas fáceis de usar CLI (interface da linha de comandos) para permitir aos programadores inicializarem os seus dados encriptados e incluírem as operações de encriptação/descodificação/digestão em tarefas ou programas de manutenção. Aprender.
Integra-se no Apache Wicket, para uma encriptação mais robusta de URLs nas suas aplicações seguras.
Guias completos e documentação javadoc, para permitir desenvolvedores para entender melhor o que eles estão realmente fazendo com seus dados.
Suporte robusto de codificação, concebido para cifrar e digerir adequadamente os textos, independentemente da codificação original. Suporte completo para idiomas como japonês, coreano, árabe... sem codificação ou problemas de plataforma.
Um nível muito elevado de capacidades de configuração: o programador pode implementar truques como instruir um "encriptor" para pedir, por exemplo, a um servidor de HTTPS remoto a senha a usar para encriptação. Permite-lhe satisfazer as suas necessidades de segurança.
Aqui uma solução simples, com apenas java.*
e javax.crypto.*
dependências para a criptografia de bytes fornecendo confidencialidade e integridade. Será indistinguível sob um ataque de texto simples escolhido.
Ele usa AES
no modo GCM
Sem Enchimento, uma chave 128bit é derivada por PBKDF2
com muitas iterações e um sal estático da senha fornecida. Isso faz com que brute forçando senhas é difícil e distribui a Entropia sobre o todo chave.
Um vetor de inicialização aleatória (IV) é gerado e será pré-adicionado ao cifrotexto. Além disso, o byte estático 0x01
é preparado como o primeiro byte como uma 'versão'.
A mensagem inteira vai para o código de autenticação da mensagem (MAC) gerado por AES/GCM
.
package cryptor;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
/**
* This class implements AES-GCM symmetric key encryption with a PBKDF2 derived password.
* It provides confidentiality and integrity of the plaintext.
*
* @created 2018-02-25
*/
public class AesGcmCryptor {
// https://crypto.stackexchange.com/questions/26783/ciphertext-and-tag-size-and-iv-transmission-with-aes-in-gcm-mode
private static final byte VERSION_BYTE = 0x01;
private static final int VERSION_BYTE_LENGTH = 1;
private static final int AES_KEY_BITS_LENGTH = 128;
private static final int GCM_IV_BYTES_LENGTH = 12;
private static final int GCM_TAG_BYTES_LENGTH = 16;
private static final int PBKDF2_ITERATIONS = 16384;
private static final byte[] PBKDF2_SALT = hexStringToByteArray("4d3fe0d71d2abd2828e7a3196ea450d4");
/**
* Decrypts an AES-GCM encrypted ciphertext and is
* the reverse operation of {@link AesGcmCryptor#encrypt(char[], byte[])}
*
* @param password passphrase for decryption
* @param ciphertext encrypted bytes
*
* @return plaintext bytes
*
* @throws NoSuchPaddingException
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
* @throws InvalidKeySpecException
* @throws InvalidAlgorithmParameterException
* @throws InvalidKeyException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
* @throws IllegalArgumentException if the length or format of the ciphertext is bad
*/
public byte[] decrypt(char[] password, byte[] ciphertext)
throws NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException,
InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException,
BadVersionException {
// input validation
if (ciphertext == null) {
throw new IllegalArgumentException("Ciphertext cannot be null.");
}
if (ciphertext.length <= VERSION_BYTE_LENGTH + GCM_IV_BYTES_LENGTH + GCM_TAG_BYTES_LENGTH) {
throw new IllegalArgumentException("Ciphertext too short.");
}
// the version must match, we don't decrypt other versions
if (ciphertext[0] != VERSION_BYTE) {
throw new BadVersionException();
}
// input seems legit, lets decrypt and check integrity
// derive key from password
SecretKey key = deriveAesKey(password, PBKDF2_SALT, AES_KEY_BITS_LENGTH);
// init cipher
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE");
GCMParameterSpec params = new GCMParameterSpec(GCM_TAG_BYTES_LENGTH * 8,
ciphertext,
VERSION_BYTE_LENGTH,
GCM_IV_BYTES_LENGTH
);
cipher.init(Cipher.DECRYPT_MODE, key, params);
final int ciphertextOffset = VERSION_BYTE_LENGTH + GCM_IV_BYTES_LENGTH;
// add version and IV to MAC
cipher.updateAAD(ciphertext, 0, ciphertextOffset);
// decipher and check MAC
return cipher.doFinal(ciphertext, ciphertextOffset, ciphertext.length - ciphertextOffset);
}
/**
* Encrypts a plaintext with a password.
*
* The encryption provides the following security properties:
* Confidentiality + Integrity
*
* This is achieved my using the AES-GCM AEAD blockmode with a randomized IV.
*
* The tag is calculated over the version byte, the IV as well as the ciphertext.
*
* Finally the encrypted bytes have the following structure:
* <pre>
* +-------------------------------------------------------------------+
* | | | | |
* | version | IV bytes | ciphertext bytes | tag |
* | | | | |
* +-------------------------------------------------------------------+
* Length: 1B 12B len(plaintext) bytes 16B
* </pre>
* Note: There is no padding required for AES-GCM, but this also implies that
* the exact plaintext length is revealed.
*
* @param password password to use for encryption
* @param plaintext plaintext to encrypt
*
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
* @throws NoSuchPaddingException
* @throws InvalidAlgorithmParameterException
* @throws InvalidKeyException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
* @throws InvalidKeySpecException
*/
public byte[] encrypt(char[] password, byte[] plaintext)
throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException,
InvalidKeySpecException {
// initialise random and generate IV (initialisation vector)
SecretKey key = deriveAesKey(password, PBKDF2_SALT, AES_KEY_BITS_LENGTH);
final byte[] iv = new byte[GCM_IV_BYTES_LENGTH];
SecureRandom random = SecureRandom.getInstanceStrong();
random.nextBytes(iv);
// encrypt
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE");
GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_BYTES_LENGTH * 8, iv);
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
// add IV to MAC
final byte[] versionBytes = new byte[] { VERSION_BYTE };
cipher.updateAAD(versionBytes);
cipher.updateAAD(iv);
// encrypt and MAC plaintext
byte[] ciphertext = cipher.doFinal(plaintext);
// prepend VERSION and IV to ciphertext
byte[] encrypted = new byte[1 + GCM_IV_BYTES_LENGTH + ciphertext.length];
int pos = 0;
System.arraycopy(versionBytes, 0, encrypted, 0, VERSION_BYTE_LENGTH);
pos += VERSION_BYTE_LENGTH;
System.arraycopy(iv, 0, encrypted, pos, iv.length);
pos += iv.length;
System.arraycopy(ciphertext, 0, encrypted, pos, ciphertext.length);
return encrypted;
}
/**
* We derive a fixed length AES key with uniform entropy from a provided
* passphrase. This is done with PBKDF2/HMAC256 with a fixed count
* of iterations and a provided salt.
*
* @param password passphrase to derive key from
* @param salt salt for PBKDF2 if possible use a per-key salt, alternatively
* a random constant salt is better than no salt.
* @param keyLen number of key bits to output
*
* @return a SecretKey for AES derived from a passphrase
*
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
private SecretKey deriveAesKey(char[] password, byte[] salt, int keyLen)
throws NoSuchAlgorithmException, InvalidKeySpecException {
if (password == null || salt == null || keyLen <= 0) {
throw new IllegalArgumentException();
}
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(password, salt, PBKDF2_ITERATIONS, keyLen);
SecretKey pbeKey = factory.generateSecret(spec);
return new SecretKeySpec(pbeKey.getEncoded(), "AES");
}
/**
* Helper to convert hex strings to bytes.
*
* May be used to read bytes from constants.
*/
private static byte[] hexStringToByteArray(String s) {
if (s == null) {
throw new IllegalArgumentException("Provided `null` string.");
}
int len = s.length();
if (len % 2 != 0) {
throw new IllegalArgumentException("Invalid length: " + len);
}
byte[] data = new byte[len / 2];
for (int i = 0; i < len - 1; i += 2) {
byte b = (byte) toHexDigit(s, i);
b <<= 4;
b |= toHexDigit(s, i + 1);
data[i / 2] = b;
}
return data;
}
private static int toHexDigit(String s, int pos) {
int d = Character.digit(s.charAt(pos), 16);
if (d < 0) {
throw new IllegalArgumentException("Cannot parse hex digit: " + s + " at " + pos);
}
return d;
}
}
Aqui todo o projecto com um bom CLI: https://github.com/trichner/tcrypt
Este é o método que eu usei.isto é simples, mas tem melhor protecção. https://github.com/chamikaras/simpleEncryptor
Leia readme sobre este projecto.Isto é simples de usar.
public SimpleEncryptor(int MaximumLength) {
//initialize encryption Key pattern variable
pattern = new Integer[MaximumLength];
//Generate pattern
pattern =GenarateEncryptionPattern(MaximumLength);
}
private Integer[] GenarateEncryptionPattern(int Length) {
Integer[] randomPattern = new Integer[Length];
//generate encryption pattern
for (int i = 0; i < Length; i++) {
//make random encrypt key
Random random = new Random();
randomPattern[i] = random.nextInt(9);
}
return randomPattern;
}
public void simpleEncryptData(String data) {
for (int i=0; i<data.length();i++){
//get character from data
char character = data.charAt(i);
//convert character to ascii
int ascii = (int) character;
//decrypt data with random generated text
int encryptedascii = ascii + pattern[i];
//convert ascii to char
char encryptedchar = (char)encryptedascii;
//append string with char
encryptedData += encryptedchar;
}
}
private String convertKey(){
//convert key to String
String key = "";
for (int i = 0;i<pattern.length;i++){
key += String.valueOf(pattern[i]);
}
return key;
}
public String getDecryptData(String data, String key){
String decryptedData = "";
for (int i=0;i<data.length();i++){
//get current key from decryptkey
String number = key.substring(i,i+1);
//get char from encrypeddata
char encryptedchar = data.charAt(i);
//convert char to ascii
int encryptedascii = (char)encryptedchar;
//decrypt encrypted char
int decryptedascii = encryptedascii - Integer.valueOf(number);
//convert ascii to char
char decryptedchar = (char)decryptedascii;
//append decrypted string
decryptedData += decryptedchar;
}
return decryptedData;
}
public String getDecryptData(String data, Integer[] key){
String decryptedData = "";
for (int i=0;i<data.length();i++){
//get char from encrypeddata
char encryptedchar = data.charAt(i);
//convert char to ascii
int encryptedascii = (char)encryptedchar;
//decrypt encrypted char
int decryptedascii = encryptedascii - key[i];
//convert ascii to char
char decryptedchar = (char)decryptedascii;
//append decrypted string
decryptedData += decryptedchar;
}
return decryptedData;
}
public String getEncryptedData(){
//return encryptedData
return encryptedData;
}
public Integer[] getRawDecryptKey(){
//return rawkey
return pattern;
}
public String getStringDecryptKey(){
//return string key
return convertKey();
}
}
Um exemplo simples de como pode cifrar e descodificar um texto em java usando AES.
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class EncryptorDemo {
public static String encrypt(String key, String randomVector, String value) {
try {
IvParameterSpec iv = new IvParameterSpec(randomVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
System.out.println("encrypted text: " + Base64.encodeBase64String(encrypted));
return Base64.encodeBase64String(encrypted);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String decrypt(String key, String randomVector, String encrypted) {
try {
IvParameterSpec iv = new IvParameterSpec(randomVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] originalText = cipher.doFinal(Base64.decodeBase64(encrypted));
System.out.println("decrypted text: " + new String(originalText));
return new String(originalText);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
String key = "JavasEncryptDemo"; // 128 bit key
String randomVector = "RandomJavaVector"; // 16 bytes IV
decrypt(key, randomVector, encrypt(key, randomVector, "Anything you want to encrypt!"));
}
}
String s1="arshad";
char[] s2=s1.toCharArray();
int s3= s2.length;
System.out.println(s3);
int i=0;
// for(int j=0;j<s3;j++)
// System.out.println(s2[j]);
for(i=0;i<((s3)/2);i++) {
char z,f=10;
z=(char) (s2[i] * f);
s2[i]=s2[(s3-1)-i];
s2[(s3-1)-i]=z;
String b=new String(s2);
print(b); }
Você pode querer considerar alguma ferramenta automatizada para fazer a geração de código de encriptação / descodificação eg. https://www.stringencrypt.com/java-encryption/
Ele pode gerar diferentes códigos de encriptação e descodificação de cada vez para o texto ou ficheiro de encriptação.
É muito útil quando se trata de encriptação rápida de string sem usar RSA, AES, etc.
Resultados da amostra:
// encrypted with https://www.stringencrypt.com (v1.1.0) [Java]
// szTest = "Encryption in Java!"
String szTest = "\u9E3F\uA60F\uAE07\uB61B\uBE1F\uC62B\uCE2D\uD611" +
"\uDE03\uE5FF\uEEED\uF699\uFE3D\u071C\u0ED2\u1692" +
"\u1E06\u26AE\u2EDC";
for (int iatwS = 0, qUJQG = 0; iatwS < 19; iatwS++)
{
qUJQG = szTest.charAt(iatwS);
qUJQG ++;
qUJQG = ((qUJQG << 5) | ( (qUJQG & 0xFFFF) >> 11)) & 0xFFFF;
qUJQG -= iatwS;
qUJQG = (((qUJQG & 0xFFFF) >> 6) | (qUJQG << 10)) & 0xFFFF;
qUJQG ^= iatwS;
qUJQG -= iatwS;
qUJQG = (((qUJQG & 0xFFFF) >> 3) | (qUJQG << 13)) & 0xFFFF;
qUJQG ^= 0xFFFF;
qUJQG ^= 0xB6EC;
qUJQG = ((qUJQG << 8) | ( (qUJQG & 0xFFFF) >> 8)) & 0xFFFF;
qUJQG --;
qUJQG = (((qUJQG & 0xFFFF) >> 5) | (qUJQG << 11)) & 0xFFFF;
qUJQG ++;
qUJQG ^= 0xFFFF;
qUJQG += iatwS;
szTest = szTest.substring(0, iatwS) + (char)(qUJQG & 0xFFFF) + szTest.substring(iatwS + 1);
}
System.out.println(szTest);
Estamos sempre a usá-lo na nossa empresa.
public static String encryptParams(String myTextInput) {
String myKey = "40674244454045cb9a70040a30e1c007";
String myVector = "@1B2c3D4e5F6g7H8";
String encData = "";
try{
JavaEncryprtionUtil encUtil = new JavaEncryprtionUtil();
encData = Base64.encodeToString(encUtil.encrypt(myTextInput.getBytes("UTF-8"), myKey.getBytes("UTF-8"), myVector.getBytes("UTF-8")),Base64.DEFAULT);
System.out.println(encData);
}catch(NoSuchAlgorithmException ex){
ex.printStackTrace();
}catch(NoSuchPaddingException ex){
ex.printStackTrace();
}catch(InvalidKeyException ex){
ex.printStackTrace();
}catch(InvalidAlgorithmParameterException ex){
ex.printStackTrace();
}catch(IllegalBlockSizeException ex){
ex.printStackTrace();
}catch(BadPaddingException ex){
ex.printStackTrace();
}catch(UnsupportedEncodingException ex){
ex.printStackTrace();
}
return encData;
}