Java AES и использование моего собственного ключа
Я хочу зашифровать строку с помощью AES с помощью собственного ключа. Но у меня проблемы с длиной бита ключа. Можете ли вы просмотреть мой код и посмотреть, что мне нужно исправить/изменить.
public static void main(String[] args) throws Exception {
String username = "[email protected]";
String password = "Password1";
String secretID = "BlahBlahBlah";
String SALT2 = "deliciously salty";
// Get the Key
byte[] key = (SALT2 + username + password).getBytes();
System.out.println((SALT2 + username + password).getBytes().length);
// Need to pad key for AES
// TODO: Best way?
// Generate the secret key specs.
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
// Instantiate the cipher
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] encrypted = cipher.doFinal((secrectID).getBytes());
System.out.println("encrypted string: " + asHex(encrypted));
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] original = cipher.doFinal(encrypted);
String originalString = new String(original);
System.out.println("Original string: " + originalString + "\nOriginal string (Hex): " + asHex(original));
}
Сейчас я получаю исключение " Недопустимая длина ключа AES: 86 байтов". Нужно ли мне заполнять свой ключ? Как мне это сделать?
Также мне нужно установить что-либо для ECB или CBC?
Спасибо
Ответы
Ответ 1
Редактировать:
Как написано в комментариях, старый код не является "лучшей практикой". Вы должны использовать алгоритм генерации ключей, такой как PBKDF2, с большим количеством итераций. Вы также должны использовать хотя бы частично нестатическую (то есть для каждой исключительной "идентичности") соль. По возможности генерируется случайным образом и сохраняется вместе с зашифрованным текстом.
SecureRandom sr = SecureRandom.getInstanceStrong();
byte[] salt = new byte[16];
sr.nextBytes(salt);
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 1000, 128 * 8);
SecretKey key = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(spec);
Cipher aes = Cipher.getInstance("AES");
aes.init(Cipher.ENCRYPT_MODE, key);
===========
Старый ответ
Вы должны использовать SHA-1, чтобы сгенерировать хеш из вашего ключа и обрезать результат до 128 бит (16 байт).
Кроме того, не генерируйте байтовые массивы из Strings через getBytes(), он использует платформу Charset по умолчанию. Таким образом, пароль "blaöä" приводит к разным байтовым массивам на разных платформах.
byte[] key = (SALT2 + username + password).getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16); // use only first 128 bit
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
Изменение: Если вам нужны ключи размером 256 бит, вам нужно загрузить ссылку на скачивание Oracle "Файлы политики неограниченного расширения Java Cryptography (JCE)", используйте SHA-256 в качестве хэша и удалите строку Arrays.copyOf. "ECB" - это режим шифрования по умолчанию, а "PKCS5Padding" - заполнение по умолчанию. Вы можете использовать разные режимы шифрования и режимы заполнения через строку Cipher.getInstance, используя следующий формат: "Cipher/Mode/Padding"
Для AES с использованием CTS и PKCS5Padding строка выглядит так: "AES/CTS/PKCS5Padding"
Ответ 2
Вы должны использовать KeyGenerator для генерации ключа,
Длина ключей AES составляет 128, 192 и 256 бит в зависимости от используемого шифрования.
Взгляните на учебник здесь
Вот код для шифрования на основе пароля, у этого есть пароль, вводимый через System.in, вы можете изменить это, чтобы использовать сохраненный пароль, если хотите.
PBEKeySpec pbeKeySpec;
PBEParameterSpec pbeParamSpec;
SecretKeyFactory keyFac;
// Salt
byte[] salt = {
(byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
(byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99
};
// Iteration count
int count = 20;
// Create PBE parameter set
pbeParamSpec = new PBEParameterSpec(salt, count);
// Prompt user for encryption password.
// Collect user password as char array (using the
// "readPassword" method from above), and convert
// it into a SecretKey object, using a PBE key
// factory.
System.out.print("Enter encryption password: ");
System.out.flush();
pbeKeySpec = new PBEKeySpec(readPassword(System.in));
keyFac = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);
// Create PBE Cipher
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
// Initialize PBE Cipher with key and parameters
pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);
// Our cleartext
byte[] cleartext = "This is another example".getBytes();
// Encrypt the cleartext
byte[] ciphertext = pbeCipher.doFinal(cleartext);
Ответ 3
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.*;
import java.io.BufferedReader;
import java.io.FileReader;
public class AESFile
{
private static String algorithm = "AES";
private static byte[] keyValue=new byte[] {'0','2','3','4','5','6','7','8','9','1','2','3','4','5','6','7'};// your key
// Performs Encryption
public static String encrypt(String plainText) throws Exception
{
Key key = generateKey();
Cipher chiper = Cipher.getInstance(algorithm);
chiper.init(Cipher.ENCRYPT_MODE, key);
byte[] encVal = chiper.doFinal(plainText.getBytes());
String encryptedValue = new BASE64Encoder().encode(encVal);
return encryptedValue;
}
// Performs decryption
public static String decrypt(String encryptedText) throws Exception
{
// generate key
Key key = generateKey();
Cipher chiper = Cipher.getInstance(algorithm);
chiper.init(Cipher.DECRYPT_MODE, key);
byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedText);
byte[] decValue = chiper.doFinal(decordedValue);
String decryptedValue = new String(decValue);
return decryptedValue;
}
//generateKey() is used to generate a secret key for AES algorithm
private static Key generateKey() throws Exception
{
Key key = new SecretKeySpec(keyValue, algorithm);
return key;
}
// performs encryption & decryption
public static void main(String[] args) throws Exception
{
FileReader file = new FileReader("C://myprograms//plaintext.txt");
BufferedReader reader = new BufferedReader(file);
String text = "";
String line = reader.readLine();
while(line!= null)
{
text += line;
line = reader.readLine();
}
reader.close();
System.out.println(text);
String plainText = text;
String encryptedText = AESFile.encrypt(plainText);
String decryptedText = AESFile.decrypt(encryptedText);
System.out.println("Plain Text : " + plainText);
System.out.println("Encrypted Text : " + encryptedText);
System.out.println("Decrypted Text : " + decryptedText);
}
}
Ответ 4
MD5, AES, без подкладки
import static javax.crypto.Cipher.DECRYPT_MODE;
import static javax.crypto.Cipher.ENCRYPT_MODE;
import static org.apache.commons.io.Charsets.UTF_8;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
public class PasswordUtils {
private PasswordUtils() {}
public static String encrypt(String text, String pass) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
Key key = new SecretKeySpec(messageDigest.digest(pass.getBytes(UTF_8)), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(ENCRYPT_MODE, key);
byte[] encrypted = cipher.doFinal(text.getBytes(UTF_8));
byte[] encoded = Base64.getEncoder().encode(encrypted);
return new String(encoded, UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
throw new RuntimeException("Cannot encrypt", e);
}
}
public static String decrypt(String text, String pass) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
Key key = new SecretKeySpec(messageDigest.digest(pass.getBytes(UTF_8)), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(DECRYPT_MODE, key);
byte[] decoded = Base64.getDecoder().decode(text.getBytes(UTF_8));
byte[] decrypted = cipher.doFinal(decoded);
return new String(decrypted, UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
throw new RuntimeException("Cannot decrypt", e);
}
}
}
Ответ 5
Эта работа будет работать.
public class CryptoUtils {
private final String TRANSFORMATION = "AES";
private final String encodekey = "1234543444555666";
public String encrypt(String inputFile)
throws CryptoException {
return doEncrypt(encodekey, inputFile);
}
public String decrypt(String input)
throws CryptoException {
// return doCrypto(Cipher.DECRYPT_MODE, key, inputFile);
return doDecrypt(encodekey,input);
}
private String doEncrypt(String encodekey, String inputStr) throws CryptoException {
try {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
byte[] key = encodekey.getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16); // use only first 128 bit
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] inputBytes = inputStr.getBytes();
byte[] outputBytes = cipher.doFinal(inputBytes);
return Base64Utils.encodeToString(outputBytes);
} catch (NoSuchPaddingException | NoSuchAlgorithmException
| InvalidKeyException | BadPaddingException
| IllegalBlockSizeException | IOException ex) {
throw new CryptoException("Error encrypting/decrypting file", ex);
}
}
public String doDecrypt(String encodekey,String encrptedStr) {
try {
Cipher dcipher = Cipher.getInstance(TRANSFORMATION);
dcipher = Cipher.getInstance("AES");
byte[] key = encodekey.getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16); // use only first 128 bit
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
dcipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
// decode with base64 to get bytes
byte[] dec = Base64Utils.decode(encrptedStr.getBytes());
byte[] utf8 = dcipher.doFinal(dec);
// create new string based on the specified charset
return new String(utf8, "UTF8");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
Ответ 6
byte[] seed = (SALT2 + username + password).getBytes();
SecureRandom random = new SecureRandom(seed);
KeyGenerator generator;
generator = KeyGenerator.getInstance("AES");
generator.init(random);
generator.init(256);
Key keyObj = generator.generateKey();