2

i found a question where the answer from Elephantik basically answerd my question: DES Initialization Vector in C#

I have a file which was encrypted with the DES.EXE command line tool. And i can decrypt it with following command: "des -D -k YSTxyHBH file.cr file.txt"

With this command i get an decrypted file.txt, but i need do decrypt this file in Java.

So i tried to transfer the solution from Elephantik to Java, but there has to be something wrong with my solution, because as result i only get some encrypted text when i call the decryptData(...) method.

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
};
Cœur
  • 37,241
  • 25
  • 195
  • 267
Michael P.
  • 31
  • 1
  • 4
  • Can you describe more clearly what you get and what expect to get? Can you give an example output? – Artjom B. Jan 21 '16 at 13:27
  • I got a test.txt file with the text "Hello" in it. If i call the command "des -E -k testkeyy test.txt test.cr" i get a file test.cr with the text "i¹^,ua-" in it. When i call the command "des -D -k testkeyy test.cr test.txt" i get a file test.txt with the text "Hello" again. If i call the decryptData(...) method with the byte-array if got from the file and the key "testkeyy" i get the output "^!Èe¹õ2ª". – Michael P. Jan 25 '16 at 05:46
  • Hi @MichaelP. I've the same problem, did you find a solution? – Michele Nov 15 '16 at 15:00
  • I have the solution in Java and C#. If someone need it send a message here and I will post an answer. – Dmitry Kazakov Nov 28 '16 at 12:30
  • @DmitryKazakov I need the solution in C#, any chance you could post it as an answer to: https://stackoverflow.com/questions/59770092/how-can-i-decrypt-a-file-in-c-sharp-which-has-been-encrypted-by-des-exe – MaYaN Jan 16 '20 at 13:01

1 Answers1

2

Michael, There are few mistakes I found in your code. Check the line cipher.init(Cipher.ENCRYPT_MODE, generateSecretKey(key), ivspec); You need to pass the same key as initialization vector,but not IV you have. The des.exe program is based on source code of LibDes library. You can find all the details in the documentation and source code. You have mention des -D parameter. It means you need to decrypt DES with CBC/NoPadding mode. Check also the _oddParityTable method you have.

If your file is not UUdecoded omit the related part in my code.

Here is ready Java example:

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};    
}
Dmitry Kazakov
  • 1,639
  • 3
  • 27
  • 47