Шифрование с использованием OpenSSL таким же образом, как это делает Java
Я должен зашифровать строку с помощью скрипта bash таким же образом, как я шифрую с помощью javax.crypto.Cipher. На Java я использую AES-256 с ключом "0123456789". Но когда я использую openssl, мне пришлось преобразовать "0123456789" в шестнадцатеричное, но результат не совпадает с Java
echo "lun01" | openssl aes-256-cbc -e -a -K 7573746f726530313233343536373839 -iv 7573746f726530313233343536373839
dpMyN7L5HI8VZEs1biQJ7g ==
Джава:
public class CryptUtil {
public static final String DEFAULT_KEY = "0123456789";
private static CryptUtil instance;
private String chiperKey;
private CryptUtil(String chiperKey) {
this.chiperKey = chiperKey;
}
public static CryptUtil getInstance() {
if (null == instance) {
instance = new CryptUtil(DEFAULT_KEY);
}
return instance;
}
public static CryptUtil getInstance(String cipherkey) {
instance = new CryptUtil(cipherkey);
return instance;
}
public String aesEncrypt(String plainText) {
byte[] keyBytes = Arrays.copyOf(this.chiperKey.getBytes("ASCII"), 16);
SecretKey key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cleartext = plainText.getBytes("UTF-8");
byte[] ciphertextBytes = cipher.doFinal(cleartext);
final char[] encodeHex = Hex.encodeHex(ciphertextBytes);
return new String(encodeHex);
return null;
}
public static void main(String[] args) {
CryptUtil cryptUtil = CryptUtil.getInstance();
System.out.println(cryptUtil.aesEncrypt("lun01"));
}
}
d230b216e9d65964abd4092f5c455a21
1 ответ
Если бесчисленное количество шестнадцатеричных онлайн-конвертеров не работает, вы можете просто напечатать ключ, который вы используете в Java, как шестнадцатеричный. Вот популярный ТАК вопрос относительно этого подвига.
После того, как вы это сделаете, вы увидите, что это все еще не работает, потому что вы используете разные алгоритмы.
Когда вы используете Cipher.getInstance("AES");
скорее всего, по умолчанию будет использоваться "AES/ECB/PKCS5Padding", который отличается от "aes-256-cbc", поскольку ECB и CBC - это два совершенно разных режима работы. Чтобы предотвратить эту неоднозначность, всегда полностью квалифицируйте ваши шифры, например: Cipher.getInstance("AES/CBC/PKCS5Padding");
,
Тогда ключ, который вы генерируете в Java, имеет длину всего 16 байтов, поэтому соответствующий шифр в OpenSSL будет "aes-128-ecb".
Как сказал dave_thompson_085 в комментарии:
echo
добавляет символ новой строки, который ваш код Java не добавляет. Вам необходимо создать открытый текст следующим образом:echo -n "lun01"
, Или посмотрите, если вы на Windows.Ваш Java-код выводит результат в шестнадцатеричном виде, поэтому вам нужно сделать то же самое в OpenSSL. Вы должны удалить
-a
параметр в команде OpenSSL, чтобы предотвратить кодирование Base64, а затем вы можете использовать дополнительные инструменты командной строки, такие какod
на Linux, чтобы преобразовать двоичные выходные данные в шестнадцатеричный сod -tx1
,Полная команда:
echo -n lun01 |openssl aes-128-ecb -K 30313233343536373839000000000000 |od -tx1
Не используйте режим ECB! Это не семантически безопасно. Вам нужно использовать как минимум режим CBC со случайным IV (убедитесь, что он случайный, а не просто ноль байтов).
Еще лучше было бы добавить аутентификацию, например, добавив тег HMAC с подходом шифрования-затем-MAC или просто используя режим аутентификации, такой как GCM.
Если вы используете что-то кроме ECB, то вы не можете зашифровать одно и то же в обеих версиях и ожидать появления одного и того же зашифрованного текста. Поскольку он рандомизирован, вам нужно будет зашифровать в одной версии и расшифровать в другой, чтобы обеспечить совместимость.