есть способ расшифровать файлы, которые были зашифрованы с помощью Команда openssl -des3 enc. Каким образом openssl использует пароль и соль, чтобы сделать ключ?
Openssl des3 расшифровка в java
Ответ 1
Утилита OpenSSL enc
использует нестандартный (и низкокачественный) алгоритм деривации ключей для паролей. Следующий код показывает, как утилита enc
генерирует ключ и вектор инициализации, заданную соль и пароль. Обратите внимание, что enc
хранит значение "salt" в зашифрованном файле, если указан параметр -salt
(и это важно для безопасности).
public InputStream decrypt(InputStream is, byte[] password)
throws GeneralSecurityException, IOException
{
/* Parse the "salt" value from the stream. */
byte[] header = new byte[16];
for (int idx = 0; idx < header.length;) {
int n = is.read(header, idx, header.length - idx);
if (n < 0)
throw new EOFException("File header truncated.");
idx += n;
}
String magic = new String(header, 0, 8, "US-ASCII");
if (!"Salted__".equals(magic))
throw new IOException("Expected salt in header.");
/* Compute the key and IV with OpenSSL non-standard method. */
SecretKey secret;
IvParameterSpec iv;
byte[] digest = new byte[32];
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(password);
md5.update(header, 8, 8);
md5.digest(digest, 0, 16);
md5.update(digest, 0, 16);
md5.update(password);
md5.update(header, 8, 8);
md5.digest(digest, 16, 16);
iv = new IvParameterSpec(digest, 24, 8);
DESedeKeySpec keySpec = new DESedeKeySpec(digest);
SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
secret = factory.generateSecret(keySpec);
}
finally {
Arrays.fill(digest, (byte) 0);
}
/* Initialize the cipher. */
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, iv);
return new CipherInputStream(is, cipher);
}
Этот ключ и генерация IV описаны в EVP_BytesToKey(3)
документации. Команда enc
использует 1
как итерацию count
(это плохая идея и отмечена как ошибка на странице man для моей версии enc
), а MD5 - алгоритм дайджест-алгоритма. "/msgstr.
Неясно, как OpenSSL преобразует текстовый пароль в байты. Я предполагаю, что он использует кодировку символов платформы по умолчанию. Итак, если вы застряли с паролем String
(не хорошо, поскольку он не может быть "нулевым" ), вы можете просто вызвать password.getBytes()
, чтобы преобразовать его в byte[]
.
Если вы можете, используйте что-то вроде Java 6 Console
или Swing JPasswordField
, чтобы получить пароль. Они возвращают массив, поэтому вы можете "удалить" пароль из памяти, когда закончите с ним: Arrays.fill(password, '\0');
Ответ 2
Спасибо, Эриксон, за ваш пост. Это очень помогло мне воссоздать пароль openssl для ключевых и IV рутинных.
Я закончил с чем-то немного другим, вероятно, потому что мне нужно расшифровать данные, зашифрованные задуманными, а не DES. См. Ниже.
Также я обнаружил, что openssl перестанет читать пароли, когда он встречает байты 00, 0a или 0d. Как правило, я думаю, что openssl только считывает символы пароля между байтами 11 и 127. Итак, для примера ниже, у меня есть код, который предшествует этому, который усекает пароль, если он содержит 00, 0a или 0d.
/* Compute the key and IV with OpenSSL non-standard method. */
final byte[] digest = new byte[32];
final MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(password, 0);
// append the salt
md5.update(salt);
// run the digest and output 16 bytes to the first 16 bytes to the digest array. Digest is reset
md5.digest(digest, 0, 16);
// write the first 16 bytes from the digest array back to the buffer
md5.update(digest, 0, 16);
// append the password
md5.update(password, 0);
// append the salt
md5.update(salt);
// run the digest and output 16 bytes to the last 16 bytes of the digest array
md5.digest(digest, 16, 16);
key = Arrays.copyOfRange(digest, 0, 16);
iv = Arrays.copyOfRange(digest, 16, 24);
Этот код выше можно заменить на 3 строки, используя org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator. Он становится
final OpenSSLPBEParametersGenerator generator = new OpenSSLPBEParametersGenerator();
generator.init(password, salt);
final ParametersWithIV ivParam = (ParametersWithIV)generator.generateDerivedParameters(16, 8);
final KeyParameter keyParameter = (KeyParameter)ivParam.getParameters();