Mam aplikację, która musi przechowywać pewne tajne hasła w pliku konfiguracyjnym, takim jak bazy danych i hasła ftp/szczegóły. Rozejrzałem się i znalazłem wiele rozwiązań szyfrowania/odszyfrowywania za pomocą AES, ale nie mogę się domyślić, jak to zrobić bez zmiany klucza. Oznacza to, że mogę szyfrować i odszyfrowywać (używając tego samego klucza SecretKey), ale w celu zachowania trwałości podczas restartów itp. Nie mogę sprawić, że SecretKey pozostanie taki sam. Poniższy przykład pokazuje moje metody pracy:Szyfrowanie i deszyfrowanie AES Java z statycznym sekretem
String secret = Encryptor.encrpytString("This is secret");
String test = Encryptor.decrpytString(secret);
System.out.println(test); //This is secret is printed
Jak dotąd tak dobrze. Jednak jeśli uruchomię go raz, mogę uzyskać wartość "2Vhht/L80UlQ184S3rlAWw ==" jako mój sekret, następnym razem będzie to "MeC4zCf9S5wUUKAu8rvpCQ ==", więc prawdopodobnie klucz się zmienia. Zakładam, że stosuję jakąś logikę przeciw-intuicyjną do problemu i doceniłbym, gdyby ktoś mógł rzucić trochę światła na a) co robię źle, lub b) rozwiązanie, które pozwoliłoby mi przechowywać zaszyfrowane informacje o haśle i można je odzyskać za pomocą dostarczonych informacji.
Moje metody są następujące:
private static final String salt = "SaltySalt";
private static byte [] ivBytes = null;
private static byte[] getSaltBytes() throws Exception {
return salt.getBytes("UTF-8");
}
private static char[] getMasterPassword() {
return "SuperSecretPassword".toCharArray();
}
private static byte[] getIvBytes() throws Exception {
if (ivBytes == null) {
//I don't have the parameters, so I'll generate a dummy encryption to create them
encrpytString("test");
}
return ivBytes;
}
public static String encrpytString (String input) throws Exception {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(getMasterPassword(), getSaltBytes(), 65536,256);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
ivBytes = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
byte[] encryptedTextBytes = cipher.doFinal(input.getBytes("UTF-8"));
return DatatypeConverter.printBase64Binary(encryptedTextBytes);
}
public static String decrpytString (String input) throws Exception {
byte[] encryptedTextBytes = DatatypeConverter.parseBase64Binary(input);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(getMasterPassword(), getSaltBytes(), 65536, 256);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(getIvBytes()));
byte[] decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
return new String(decryptedTextBytes);
}
Dzięki za pomoc!
To jest dokładnie to, co mam w trzecim interfejsie integracyjnym. Pole danych wejściowych XML Base64toBytes, bajty 0..15 to wartość IV, odszyfruj bajty 16..n za pomocą tajnego klucza. – Whome
W przypadku AES/CBC/PKCS7Padding większość osób wybiera opcję IV do tekstu zaszyfrowanego. Odszyfrując pierwsze 16 bajtów z tekstu zaszyfrowanego, są to IV, zainicjuj szyfr, a następnie wykonaj z resztą. Ma kilka fajnych właściwości, w szczególności te implementacje, które nie są zgodne z tą konwencją, ale zaczynają się od 0 IV i odrzucają, że pierwszy blok nadal może odszyfrować tekst. – wallenborn
Dzięki za potwierdzenie! – Aaron