Вы уже получили ссылку от @Saptarshi Basu, которая в общих чертах показывает, как шифровать данные с помощью AES GCM. Как вы видите в моем коде, в этом нет ничего мистического, но есть некоторые ловушки, на которые можно наткнуться.
Начнем с самой важной информации - что такое ключ шифрования? От Hashicorp вы получили строку длиной 44 байта, которая представляет собой чистый 32-байтовый ключ AES GCM, но в кодировке Base64. Чтобы получить ключ, пригодный для использования с шифрованием Java, вам необходимо декодировать ключ в массив байтов следующим образом:
String keyBase64 = "VxJWkOYm2F5z1nF1th9zreS6ZAZMFkCq0c/Ik460ayw=";
byte[] key = Base64.getDecoder().decode(keyBase64);
Вторая информация, которая нам нужна, - это режим AES - вы правильно назвали его режимом AES GCM, а поскольку вы предоставляете Java ключ длиной 32 байта = 256 бит, это запрашиваемый алгоритм / режим AES GCM 256.
Для шифрования AES GCM необходим третий параметр - nonce (иногда называемый вектором инициализации). Hashicorp говорит вам использовать одноразовый номер длиной 96 бит = 12 байт. По соображениям безопасности важно использовать другой одноразовый номер каждый раз при шифровании, поэтому рекомендуется использовать (безопасный) случайно сгенерированный одноразовый номер:
byte[] nonceRandom = new byte[12];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(nonceRandom);
Теперь мы готовы к шифрованию и объединению всех данных, выполняем шаг .doFinal и получаем массив байтов с зашифрованным текстом. Но остановитесь - нам нужно объединить использованный одноразовый номер и зашифрованный текст в более крупный ciphertextWithNonce следующим образом:
nonce | ciphertext
просто скопировав одноразовый номер и зашифрованный текст в новый массив байтов. Затем этот ciphertextWithNonce кодируется в Base64 в окончательный ciphertextBase64 и для целей загрузки записывается в файл.
Если вы вставите свой собственный ключ в начало программы и запустите его, вы получите файл с именем hashicorp_test.enc, готовый к загрузке по вашей вине.
Это пример вывода (ваш будет отличаться из-за случайного элемента):
Hashicorp Vault AES GCM encryption
ciphertext: /YB+kfVlIhMowLrsnndD737o2CcyWMfr4xnAADnCBSNCSvMG25aR8UzU2ta8wLwdnHfcago/25KFJ2ky95wpFtsCNE63xRs=
ciphertext written to file: hashicorp_test.enc
used key: VxJWkOYm2F5z1nF1th9zreS6ZAZMFkCq0c/Ik460ayw=
Если вы хотите увидеть, как этот код работает в онлайн-компиляторе, вот ссылка: https://repl.it/@javacrypto/SoHashicorpVaultAesGcmEncryption
Это доказательство концепции, чтобы показать в общих чертах, как выполнять шифрование, но в нем отсутствуют некоторые важные моменты, из-за которых мне было бы лень выполнять вашу работу :-).
- В этом примере строка шифруется в зашифрованный файл - вам нужно будет получить исходные данные из файла.
- Имея большой файл, вы можете столкнуться с ошибкой нехватки памяти, поскольку все операции с вашими данными выполняются в вашей куче - для простых вычислений вам понадобится свободная память размером 4,5 * исходных данных, потому что вы берете исходные данные в память во второй раз у вас есть зашифрованные данные в памяти, третий раз вы копируете зашифрованные данные в ciphertextWithNonce и в конце (номер 4) кодируете все данные в base64-String. Для больших программ вам нужно будет переключиться на шифрование по частям, выполненное с помощью CiphertextOutputStream.
- Чтобы сделать запись полных данных с помощью Base64 немного более удобной, я рекомендую дополнительно использовать Apache Base64OutputStream (доступный через Maven https://mvnrepository.com/artifact/commons-codec/commons-codec).
Предупреждение безопасности: этот код не обрабатывает исключения и предназначен только для образовательных целей.
код:
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
public class Hashicorp_Aes_Gcm_encryption {
public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, IOException {
System.out.println("Hashicorp Vault AES GCM encryption");
// https://stackoverflow.com/questions/64714527/how-can-i-encrypt-data-with-an-already-generated-aes-256-gcm-96-key-coming-from
// paste your key here:
String keyBase64 = "VxJWkOYm2F5z1nF1th9zreS6ZAZMFkCq0c/Ik460ayw=";
// filename with ciphertext for upload
String filename = "hashicorp_test.enc";
// my sample plaintext
String plaintext = "The quick brown fox jumps over the lazy dog";
// aes gcm encryption
// decode key
byte[] key = Base64.getDecoder().decode(keyBase64);
// generate random nonce
byte[] nonceRandom = new byte[12];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(nonceRandom);
// calculate specs
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(16 * 8, nonceRandom);
// initialize cipher
Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5Padding");//NOPadding
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, gcmParameterSpec);
// encrypt
byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
// concentenate iv + ciphertext
int ciphertextWithNonceLength = nonceRandom.length + ciphertext.length;
byte[] ciphertextWithNonce = new byte[ciphertextWithNonceLength];
System.arraycopy(nonceRandom, 0, ciphertextWithNonce, 0, nonceRandom.length);
System.arraycopy(ciphertext, 0, ciphertextWithNonce, nonceRandom.length, ciphertext.length);
String ciphertextBase64 = Base64.getEncoder().encodeToString(ciphertextWithNonce);
System.out.println("ciphertext: " + ciphertextBase64);
// save encrypted data to a file
Files.write(Paths.get(filename), ciphertextBase64.getBytes(StandardCharsets.UTF_8));
System.out.println("ciphertext written to file: " + filename);
System.out.println("used key: " + keyBase64);
}
}
person
Michael Fehr
schedule
06.11.2020