java - 在 Java 中对 DES.EXE 中的文件进行 DES 解密

标签 java encryption des

我发现了一个问题,Elephantik 的答案基本上回答了我的问题: DES Initialization Vector in C#

我有一个使用 DES.EXE 命令行工具加密的文件。我可以使用以下命令解密它:“des -D -k YSTxyHBH file.cr file.txt”

通过这个命令,我得到了一个解密的 file.txt,但我需要在 Java 中解密这个文件。

所以我尝试将解决方案从 Elephantik 转移到 Java,但我的解决方案一定有问题,因为结果当我调用 cryptoData(...) 方法时我只得到一些加密文本。

public byte[] decryptData(byte input[], String password) throws Exception {
    byte[] result = null;
    //Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
    Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
    //byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0 };
    byte[] iv = { -128, -128, -128, -128, -128, -128, -128, -128 };
    IvParameterSpec ivspec = new IvParameterSpec(iv);
    cipher.init(Cipher.DECRYPT_MODE, generateSecretKey(passwordToKey(password)), ivspec);
    result = cipher.doFinal(input);
    return result;
}

protected SecretKey generateSecretKey(byte[] key) throws Exception {
    SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
    KeySpec keySpec = new DESKeySpec(key);
    SecretKey secretKey = factory.generateSecret(keySpec);
    return secretKey;
}

public byte[] passwordToKey(String password) throws Exception
{
    if (password == null)
        throw new IllegalArgumentException("password");
    if (password == "")
        throw new IllegalArgumentException("password");

    byte[] key = new byte[8];

    for (int i = 0; i < password.length(); i++)
    {
        int c = (int)password.charAt(i);
        if ((i % 16) < 8)
        {
            key[i % 8] ^= (byte)(c << 1);
        }
        else
        {
            // reverse bits e.g. 11010010 -> 01001011
            c = (((c << 4) & 0xf0) | ((c >> 4) & 0x0f));
            c = (((c << 2) & 0xcc) | ((c >> 2) & 0x33));
            c = (((c << 1) & 0xaa) | ((c >> 1) & 0x55));
            key[7 - (i % 8)] ^= (byte)c;
        }
    }

    addOddParity(key);

    byte[] target = new byte[8];
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream( );
    outputStream.write(password.getBytes("US-ASCII"));
    outputStream.write(new byte[8]);
    byte[] temp = outputStream.toByteArray();
    outputStream = new ByteArrayOutputStream( );
    for (int i = 0; i < (password.length() + (8 - (password.length() % 8)) % 8); ++i) {
        outputStream.write(temp[i]);
    }
    byte[] passwordBuffer = outputStream.toByteArray(); 

    Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
    //byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0 };
    byte[] iv = { -128, -128, -128, -128, -128, -128, -128, -128 };
    IvParameterSpec ivspec = new IvParameterSpec(iv);
    cipher.init(Cipher.ENCRYPT_MODE, generateSecretKey(key), ivspec);
    for (int x = 0; x < passwordBuffer.length / 8; ++x)
    {
        cipher.update(passwordBuffer, 8 * x, 8, target, 0);
    }

    addOddParity(target);

    return target;
}

private void addOddParity(byte[] buffer)
{
    for (int i = 0; i < buffer.length; ++i)
    {
        buffer[i] = _oddParityTable[buffer[i] & 0xFF];
    }
}

private static byte[] _oddParityTable = {
   -127,-127,-126,-126,-124,-124,-121,-121,-120,-120,-117,-117,-115,-115,-114,-114,
   -112,-112,-109,-109,-107,-107,-106,-106,-103,-103,-102,-102,-100,-100, -97, -97,
    -96, -96, -93, -93, -91, -91, -90, -90, -87, -87, -86, -86, -84, -84, -81, -81,
    -79, -79, -78, -78, -76, -76, -73, -73, -72, -72, -69, -69, -67, -67, -66, -66,
    -64, -64, -61, -61, -59, -59, -58, -58, -55, -55, -54, -54, -52, -52, -49, -49,
    -47, -47, -46, -46, -44, -44, -41, -41, -40, -40, -37, -37, -35, -35, -34, -34,
    -31, -31, -30, -30, -28, -28, -25, -25, -24, -24, -21, -21, -19, -19, -18, -18,
    -16, -16, -13, -13, -11, -11, -10, -10,  -7,  -7,  -6,  -6,  -4,  -4,  -1,  -1,
      0,   0,   3,   3,   5,   5,   6,   6,   9,   9,  10,  10,  12,  12,  15,  15,
     17,  17,  18,  18,  20,  20,  23,  23,  24,  24,  27,  27,  29,  29,  30,  30,
     33,  33,  34,  34,  36,  36,  39,  39,  40,  40,  43,  43,  45,  45,  46,  46,
     48,  48,  51,  51,  53,  53,  54,  54,  57,  57,  58,  58,  60,  60,  63,  63,
     65,  65,  66,  66,  68,  68,  71,  71,  72,  72,  75,  75,  77,  77,  78,  78,
     80,  80,  83,  83,  85,  85,  86,  86,  89,  89,  90,  90,  92,  92,  95,  95,
     96,  96,  99,  99, 101, 101, 102, 102, 105, 105, 106, 106, 108, 108, 111, 111,
    113, 113, 114, 114, 116, 116, 119, 119, 120, 120, 123, 123, 125, 125, 126, 126
};

最佳答案

Michael,我在你的代码中发现了一些错误。检查行 cipher.init(Cipher.ENCRYPT_MODE,generateSecretKey(key), ivspec); 您需要传递与 key 相同的key>初始化 vector ,但不是你拥有的 IV。 des.exe程序基于LibDes的源代码图书馆。您可以在文档和源代码中找到所有详细信息。您提到了 des -D 参数。这意味着您需要使用CBC/NoPadding模式解密DES。另请检查您拥有的 _oddParityTable 方法。

如果您的文件未经过 UUdecoded,请忽略我的代码中的相关部分。

这里是准备好的 Java 示例:

public class UUDES {

    public static void main (String[] args) throws Exception
    {                                   
        String password = "xxxxxx";
        String pathToUUEencodedEncryptedFile = "C:\DES\path-to-decoded-and-encrypted-file";

        byte[] secretKey = passwordToKey(password);
        byte[] iv = new byte[8];        
        byte[] uuEncodedFile = Files.readAllBytes(Paths.get(pathToUUEencodedEncryptedFile));

        SecretKey key = new SecretKeySpec(secretKey, "DES");

        Cipher decryptor = Cipher.getInstance("DES/CBC/NoPadding");
        decryptor.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));          

        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        InputStream in = null;      
        try {
            in = MimeUtility.decode(new ByteArrayInputStream(uuEncodedFile), "uuencode");
            byte[] buf = new byte[1024];
            int length;
            while (true) {
                length = in.read(buf);
                if (length == -1) {
                    break;
                }
                bout.write(buf, 0, length);
            }

            byte[] bytesDecrypted = decryptor.doFinal(bout.toByteArray());

            ByteArrayInputStream bais = new ByteArrayInputStream(bytesDecrypted);
            GZIPInputStream gzis = new GZIPInputStream(bais);
            InputStreamReader reader = new InputStreamReader(gzis);
            BufferedReader buffer = new BufferedReader(reader);

            String readed;
            while ((readed = buffer.readLine()) != null) {
                System.out.println(readed);
            }                              
        }
        finally {
            if (in != null) {
                try {
                    in.close();
                }
                catch (IOException e) {
                    System.out.println(e.getMessage());
                }
            }
        }                                   
    }

    static SecretKey generateSecretKey(byte[] key) throws Exception {
        SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
        KeySpec keySpec = new DESKeySpec(key);
        SecretKey secretKey = factory.generateSecret(keySpec);
        return secretKey;
    }

    static byte[] passwordToKey(String password) throws Exception
    {
        if (password == null)
            throw new IllegalArgumentException("password");
        if (password == "")
            throw new IllegalArgumentException("password");

        byte[] key = new byte[8];

        for (int i = 0; i < password.length(); i++)
        {
            int c = (int)password.charAt(i);
            if ((i % 16) < 8)
            {
                key[i % 8] ^= (byte)(c << 1);
            }
            else
            {
                // reverse bits e.g. 11010010 -> 01001011
                c = (((c << 4) & 0xf0) | ((c >> 4) & 0x0f));
                c = (((c << 2) & 0xcc) | ((c >> 2) & 0x33));
                c = (((c << 1) & 0xaa) | ((c >> 1) & 0x55));
                key[7 - (i % 8)] ^= (byte)c;
            }
        }

        addOddParity(key);

        byte[] target = new byte[8];
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream( );
        outputStream.write(password.getBytes("US-ASCII"));
        outputStream.write(new byte[8]);
        byte[] temp = outputStream.toByteArray();
        outputStream = new ByteArrayOutputStream( );
        for (int i = 0; i < (password.length() + (8 - (password.length() % 8)) % 8); ++i) {
            outputStream.write(temp[i]);
        }
        byte[] passwordBuffer = outputStream.toByteArray(); 

        Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
        byte[] iv = key;

        IvParameterSpec ivspec = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, generateSecretKey(key), ivspec);
        for (int x = 0; x < passwordBuffer.length / 8; ++x)
        {
            cipher.update(passwordBuffer, 8 * x, 8, target, 0);
        }

        addOddParity(target);

        return target;
    }

    static void addOddParity(byte[] buffer)
    {
        for (int i = 0; i < buffer.length; ++i)
        {
            buffer[i] = _oddParityTable[buffer[i] & 0xFF];
        }
    }

    static byte[] _oddParityTable = {
            (byte)1,(byte)1,(byte)2,(byte)2,(byte)4,(byte)4,(byte)7,(byte)7,(byte)8,(byte)8,(byte)11,(byte)11,(byte)13,(byte)13,(byte)14,(byte)14,
            (byte)16,(byte)16,(byte)19,(byte)19,(byte)21,(byte)21,(byte)22,(byte)22,(byte)25,(byte)25,(byte)26,(byte)26,(byte)28,(byte)28,(byte)31,(byte)31,
           (byte)32,(byte)32,(byte)35,(byte)35,(byte)37,(byte)37,(byte)38,(byte)38,(byte)41,(byte)41,(byte)42,(byte)42,(byte)44,(byte)44,(byte)47,(byte)47,
           (byte)49,(byte)49,(byte)50,(byte)50,(byte)52,(byte)52,(byte)55,(byte)55,(byte)56,(byte)56,(byte)59,(byte)59,(byte)61,(byte)61,(byte)62,(byte)62,
           (byte)64,(byte)64,(byte)67,(byte)67,(byte)69,(byte)69,(byte)70,(byte)70,(byte)73,(byte)73,(byte)74,(byte)74,(byte)76,(byte)76,(byte)79,(byte)79,
           (byte)81,(byte)81,(byte)82,(byte)82,(byte)84,(byte)84,(byte)87,(byte)87,(byte)88,(byte)88,(byte)91,(byte)91,(byte)93,(byte)93,(byte)94,(byte)94,
           (byte)97,(byte)(byte)97,(byte)(byte)98,(byte)(byte)98,(byte)100,(byte)100,(byte)103,(byte)103,(byte)104,(byte)104,(byte)107,(byte)107,(byte)109,(byte)109,(byte)110,(byte)110,
           (byte)112,(byte)112,(byte)115,(byte)115,(byte)117,(byte)117,(byte)118,(byte)118,(byte)121,(byte)121,(byte)122,(byte)122,(byte)124,(byte)124,(byte)127,(byte)127,
           (byte)128,(byte)128,(byte)131,(byte)131,(byte)133,(byte)133,(byte)134,(byte)134,(byte)137,(byte)137,(byte)138,(byte)138,(byte)140,(byte)140,(byte)143,(byte)143,
           (byte)145,(byte)145,(byte)146,(byte)146,(byte)148,(byte)148,(byte)151,(byte)151,(byte)152,(byte)152,(byte)155,(byte)155,(byte)157,(byte)157,(byte)158,(byte)158,
           (byte)161,(byte)161,(byte)162,(byte)162,(byte)164,(byte)164,(byte)167,(byte)167,(byte)168,(byte)168,(byte)171,(byte)171,(byte)173,(byte)173,(byte)174,(byte)174,
           (byte)176,(byte)176,(byte)179,(byte)179,(byte)181,(byte)181,(byte)182,(byte)182,(byte)185,(byte)185,(byte)186,(byte)186,(byte)188,(byte)188,(byte)191,(byte)191,
           (byte)193,(byte)193,(byte)194,(byte)194,(byte)196,(byte)196,(byte)199,(byte)199,(byte)200,(byte)200,(byte)203,(byte)203,(byte)205,(byte)205,(byte)206,(byte)206,
           (byte)208,(byte)208,(byte)211,(byte)211,(byte)213,(byte)213,(byte)214,(byte)214,(byte)217,(byte)217,(byte)218,(byte)218,(byte)220,(byte)220,(byte)223,(byte)223,
           (byte)224,(byte)224,(byte)227,(byte)227,(byte)229,(byte)229,(byte)230,(byte)230,(byte)233,(byte)233,(byte)234,(byte)234,(byte)236,(byte)236,(byte)239,(byte)239,
           (byte)241,(byte)241,(byte)242,(byte)242,(byte)244,(byte)244,(byte)247,(byte)247,(byte)248,(byte)248,(byte)251,(byte)251,(byte)253,(byte)253,(byte)254,(byte)254};    
}

关于java - 在 Java 中对 DES.EXE 中的文件进行 DES 解密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34923553/

相关文章:

java - 使用java创建解释器的工具

java - 解密的字符串与预加密的字符串不同

android - 如何在 Android 应用程序中保护密码

ios - Objective-C DESede/CBC/PKCS5Padding

java - 将 SecretKey 转换为字节,如何将其转换回 SecretKey?

java - 使用 Jsoup.parse 时如何保持换行?

java - 返回按钮无意中退出应用程序

java - 如何在 IIS 中托管 Java Web 服务

encryption - 同态加密中的截断