解密pbewithmd5并将.net中的加密字符串增加三倍

cidc1ykv  于 2021-07-03  发布在  Java
关注(0)|答案(1)|浏览(387)

我需要用org.jasypt.util.text.strongtextencryptor解密java中生成的字符串,该加密程序使用pbewithmd5andtripledes算法。我想我在这里找到了源代码:http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/com/sun/crypto/provider/pbewithmd5andtripledescipher.java
它有一些关于算法的信息:
创建随机盐和分裂成两半。如果两半相同,则将其中一个倒置。
将密码与每一半连接起来。
用c迭代来消化每个串联,其中c是迭代计数。将每个摘要轮的输出与密码连接起来,并将结果用作下一个摘要操作的输入。摘要算法是md5。
在c迭代之后,使用2个结果摘要,如下所示:第一个摘要的16字节和第二个摘要的前8字节
形成三重des密钥,第二个摘要的最后8个字节形成iv。
java中的代码似乎很简单。密钥就是这样解密的。

StrongTextEncryptor textEncryptor = new StrongTextEncryptor();
    textEncryptor.setPassword(key1);
    String result = textEncryptor.decrypt(key2);

这是我生成的一个示例:

key1=17EXGCnC
key2=7bALjokBDuxopB+Z37DwiTX/jg3/pjUoKW4q25uzd34=
result=-1,-1

有人能指导我如何实现解密代码吗?
这是java中使用的包:https://mvnrepository.com/artifact/com.melloware/jasypt/1.9.4

yvfmudvl

yvfmudvl1#

发布的密文长度为32字节,明文长度为5字节(或8字节,包括填充)。根据jasypt源代码,串联按照salt | iv |密文的顺序进行,其中salt长8字节,iv长16字节。
16字节长的iv在块大小为8字节的tripledes上下文中没有意义,在解密期间根本不使用。换句话说,在密文中,iv可以被任何16字节的序列所取代,而解密的明文仍然是相同的。
所以对于解密盐,iv和密文必须分开,iv可以丢弃。
key/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;
}

作为三元组的键,使用前24个字节,最后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。

相关问题