Мне нужно расшифровать строки, созданные на Java, с помощью org.jasypt.util.text.StrongTextEncryptor, использующего алгоритм PBEWithMD5AndTripleDES. Я думаю, что нашел здесь исходный код: ...

1
user568327 15 Дек 2020 в 18:06

1 ответ

Лучший ответ

Опубликованный зашифрованный текст имеет длину 32 байта с длиной открытого текста 5 байтов (или 8 байтов, включая заполнение). Согласно исходному коду Jasypt, конкатенация происходит в порядке salt | IV | зашифрованный текст , где длина соли составляет 8 байтов, а IV - 16 байтов.
IV длиной 16 байт не имеет смысла в контексте TripleDES с размером блока 8 байт и вообще не используется во время дешифрования. Другими словами, IV может быть заменен в зашифрованном тексте любой последовательностью из 16 байтов, и расшифрованный открытый текст останется таким же.


Таким образом, для дешифрования соль IV и зашифрованный текст должны быть разделены, IV можно отбросить.

Описание функции деривации ключа / IV уже размещено в вопросе. Пример реализации выглядит так:

private static byte[] GetKeyIV(String password, byte[] salt, int count)
{
    // Decode passwort
    byte[] pwd = Encoding.UTF8.GetBytes(password);

    // Split salt in 2 parts
    byte[] salt1 = new byte[4];
    byte[] salt2 = new byte[4];
    Array.Copy(salt, 0, salt1, 0, salt1.Length);
    Array.Copy(salt, 4, salt2, 0, salt2.Length);

    // Reverse 1st part if both parts are equal
    if (salt1.SequenceEqual(salt2))
    {
        Array.Reverse(salt1, 0, salt1.Length);
    }

    // Calculate 1st hash
    byte[] hash1 = salt1;
    for (int i = 0; i < count; i++)
    {
        MD5 md = MD5.Create();
        hash1 = md.ComputeHash(Concatenate(hash1, pwd));
    }

    // Calculate 2nd hash
    byte[] hash2 = salt2;
    for (int i = 0; i < count; i++)
    {
        MD5 md = MD5.Create();
        hash2 = md.ComputeHash(Concatenate(hash2, pwd));
    }

    // Join both hashes
    return Concatenate(hash1, hash2);
}

private static byte[] Concatenate(byte[] arr1, byte[] arr2)
{
    byte[] bytes = new byte[arr1.Length + arr2.Length];
    Buffer.BlockCopy(arr1, 0, bytes, 0, arr1.Length);
    Buffer.BlockCopy(arr2, 0, bytes, arr1.Length, arr2.Length);
    return bytes;
}

В качестве ключа для TripleDES используются первые 24 байта, в качестве IV - последние 8 байтов.

Это позволяет расшифровывать с помощью обычного шаблона MS:

// Separate data
byte[] data = Convert.FromBase64String("7bALjokBDuxopB+Z37DwiTX/jg3/pjUoKW4q25uzd34=");
byte[] salt = new byte[8];
byte[] ciphertext = new byte[data.Length - salt.Length - 16];
Array.Copy(data, 0, salt, 0, salt.Length);
Array.Copy(data, salt.Length + 16, ciphertext, 0, ciphertext.Length);

// Derive key and IV
byte[] keyIV = GetKeyIV("17EXGCnC", salt, 1000); // count = 1000 according to Jasypt sources
byte[] key = new byte[24];
byte[] iv = new byte[8];
Array.Copy(keyIV, 0, key, 0, key.Length);
Array.Copy(keyIV, key.Length, iv, 0, iv.Length);

// Decrypt
string plaintext = "";
using (TripleDESCryptoServiceProvider aesAlg = new TripleDESCryptoServiceProvider())
{
    aesAlg.Key = key;
    aesAlg.IV = iv;
    ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
    using (MemoryStream msDecrypt = new MemoryStream(ciphertext))
    {
        using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
        {
            using (StreamReader srDecrypt = new StreamReader(csDecrypt))
            {
                plaintext = srDecrypt.ReadToEnd();
            }
        }
    }
}
Console.WriteLine(plaintext);

Что дает результат кода Java: -1, -1


Обратите внимание, что PBEWithMD5AndTripleDES - устаревший алгоритм, который следует использовать только в целях совместимости.
Получение ключа при использовании MD5 не очень безопасно, а количество итераций 1000 слишком мало. Вместо этого следует использовать более надежную функцию получения ключа, такую ​​как PBKDF2.
TripleDES также устарел и неэффективен, и его следует заменить более современным алгоритмом, таким как AES.

2
Topaco 16 Дек 2020 в 07:37