3

I found a link in stackoverflow here use-3des-encryption-decryption-in-java,but in fact the method uses only two parameter:HG58YZ3CR9" and the "IvParameterSpec iv = new IvParameterSpec(new byte[8]);"
But the most strong option of triple des could use three different key to encrypt the message.So how to do that? I find a mehond in Cipher, which use "SecureRandom" as another parameter.So is this the right way?
The first method code is below:

import java.security.MessageDigest;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class TripleDESTest {

    public static void main(String[] args) throws Exception {

        String text = "kyle boon";

        byte[] codedtext = new TripleDESTest().encrypt(text);
        String decodedtext = new TripleDESTest().decrypt(codedtext);

        System.out.println(codedtext); // this is a byte array, you'll just see a reference to an array
        System.out.println(decodedtext); // This correctly shows "kyle boon"
    }

    public byte[] encrypt(String message) throws Exception {
        final MessageDigest md = MessageDigest.getInstance("SHA-1");
        final byte[] digestOfPassword = md.digest("HG58YZ3CR9"
                .getBytes("utf-8"));
        final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
        for (int j = 0, k = 16; j < 8;) {
            keyBytes[k++] = keyBytes[j++];
        }

        final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
        final IvParameterSpec iv = new IvParameterSpec(new byte[8]);
        final Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key, iv);

        final byte[] plainTextBytes = message.getBytes("utf-8");
        final byte[] cipherText = cipher.doFinal(plainTextBytes);
        // final String encodedCipherText = new sun.misc.BASE64Encoder()
        // .encode(cipherText);

        return cipherText;
    }

    public String decrypt(byte[] message) throws Exception {
        final MessageDigest md = MessageDigest.getInstance("SHA-1");
        final byte[] digestOfPassword = md.digest("HG58YZ3CR9"
                .getBytes("utf-8"));
        final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
        for (int j = 0, k = 16; j < 8;) {
            keyBytes[k++] = keyBytes[j++];
        }

        final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
        final IvParameterSpec iv = new IvParameterSpec(new byte[8]);
        final Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
        decipher.init(Cipher.DECRYPT_MODE, key, iv);

        // final byte[] encData = new
        // sun.misc.BASE64Decoder().decodeBuffer(message);
        final byte[] plainText = decipher.doFinal(message);

        return new String(plainText, "UTF-8");
    }
}
Community
  • 1
  • 1
Marshal Chen
  • 1,985
  • 4
  • 24
  • 35

2 Answers2

2

As per this document, simply pass the cipher a key that is 168 bits long.

Keysize must be equal to 112 or 168.

A keysize of 112 will generate a Triple DES key with 2 intermediate keys, and a keysize of 168 will generate a Triple DES key with 3 intermediate keys.

Your code seems to do something questionable to make up for the fact that the output of MD5 is only 128 bits long.

Copy-pasting cryptographic code off the internet will not produce secure applications. Using a static IV compromises several reasons why CBC mode is better than ECB. If you are using a static key, you should probably consider generating random bytes using a secure random number generator instead of deriving the key from a short ASCII string. Also, there is absolutely no reason to use Triple DES instead of AES in new applications.

ntoskrnl
  • 5,714
  • 2
  • 27
  • 31
  • Thank you very much.And will it be better if I use "SHA-1" instead of MD5 ? In fact, I don't think I have used the code which encrypt by MD5 directly .And I also confuse that what can I do for 3 intermediate keys.Must I use a secure random number generator? And if I do so,how can I decrypt the code?Thank you very much! – Marshal Chen Jul 04 '13 at 13:00
  • Instead of storing an ASCII string and then hashing that every time, you should generate the key bytes once and then store those bytes. – ntoskrnl Jul 04 '13 at 13:07
  • Cool!But I had to let the server decrypt the code too,so I think it is hard to synchronise the random number – Marshal Chen Jul 05 '13 at 00:56
  • I can't see how storing bytes and storing a string are different in this case. – ntoskrnl Jul 05 '13 at 09:30
0

In principle, the for-next loop to generate the DES ABA key does seem correct. Note that you can provide DESede with a 16 byte key from Java 7 onwards, which amounts to the same thing.

That said, the code you've shown leaves a lot to be desired:

I is not secure:

  • the key is not generated by a Password Based Key Derivation Function (PBKDF) using the (password?) string
  • the key is composed of two keys instead of three (using a triple DES or TDEA with an ABA key)
  • the IV is set to all zero's instead of being randomized
  • the "password" string is too short

Furthermore the following code mistakes can be seen:

  • using new sun.misc.BASE64Encoder() which is in the Sun proprietary packages (which can be removed or changed during any upgrade of the runtime)
  • throwing Exception for platform exceptions and runtime exceptions (not being able to decrypt is handled the same way as not being able to instantiate the Cipher)
  • requesting 24 bytes instead of 16 within the Arrays.copyOf() call (which seems to return 24 SHA-1 output while there are only 20 bytes)

To generate a 3DES 24 byte (168 bits used) DES ABC key from a password (like) String you should use PBKDF-2. Adding an authentication tag is also very important if man-in-the-middle attacks or padding oracle apply. It would be much secure and much more practical to upgrade to AES if you can control the algorithms being used as well.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263