openssl des3 расшифровывает в java - PullRequest
2 голосов
/ 17 апреля 2009

есть ли способ расшифровать файлы, которые были зашифрованы с использованием Команда openssl -des3 enc. Как именно openssl использует пароль и соль для создания ключа?

Ответы [ 2 ]

5 голосов
/ 17 апреля 2009

Утилита OpenSSL enc использует нестандартный (и некачественный) алгоритм получения ключей для паролей. Следующий код показывает, как утилита enc генерирует ключ и вектор инициализации, учитывая соль и пароль. Обратите внимание, что enc хранит значение «соли» в зашифрованном файле, когда указан параметр -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's 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 (что является плохой идеей и отмечено как ошибка на странице руководства для моей версии enc) и MD5 в качестве алгоритма дайджеста - "сломанный" алгоритм.

Непонятно, как OpenSSL преобразует текстовый пароль в байты. Я предполагаю, что он использует кодировку символов платформы по умолчанию. Так что, если вы застряли с паролем String (не очень хорошо, поскольку его нельзя «обнулить»), вы можете просто позвонить password.getBytes(), чтобы преобразовать его в byte[] ,

Если вы можете, используйте что-нибудь вроде Java 6 Console или Swing's JPasswordField, чтобы получить пароль. Они возвращают массив, поэтому вы можете «удалить» пароль из памяти, когда закончите с ним: Arrays.fill(password, '\0');

1 голос
/ 17 марта 2011

Спасибо, Эриксон, за ваш пост. Это очень помогло мне в попытке воссоздать пароль openssl для ключа и процедуры IV.

Я закончил с чем-то немного другим, вероятно, потому, что мне нужно расшифровать данные, зашифрованные blowfish, а не DES. Смотри ниже.

Также я обнаружил, что openssl прекратит чтение паролей, когда встретит байты 00, 0a или 0d. Обычно я думаю, что openssl читает только символы пароля между байтами 11 и 127. Так что для приведенного ниже примера у меня есть код, который предшествует этому, который усекает пароль, если он содержит 00, 0a или 0d.

     /* Compute the key and IV with OpenSSL's 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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...