Question

I'm having trouble decrypting a value from a third party that uses 3Des. They've given me a key, an encrypted value, the mode used, and what the decrypted value should be, but so far I've been unable to work out how to get from point a to b. I believe the problem has to do with the key they've given me - they say that it is the clear text key, but I think it still needs to be further transformed somehow.

The code below is is an example of my initial attempt to understand how to decrypt the value (AC9C5A46A63FC9EA in this case)

Any insights would be appreciated.

import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;

public class TripleDes2 {

private static final String UNICODE_FORMAT = "UTF8";
private static final String DESEDE_ENCRYPTION_SCHEME = "DESede";
private static final String CIPHER_ALG = "DESede/ECB/Nopadding"; //assuming no padding
private KeySpec ks;
private SecretKeyFactory skf;
private Cipher cipher;
private byte[] arrayBytes;
private String myEncryptionKey;
private SecretKey key;

public static void main(String args []) throws Exception {
    TripleDes2 td= new TripleDes2();

    String decrypted = td.decrypt("AC9C5A46A63FC9EA");
    System.out.println("expecting: 04286EDDFDEA6BD7");
    System.out.println("found: " + decrypted);
}

public TripleDes2() throws Exception {
    myEncryptionKey = "1032FD2CD64A9D7FA4D061F76B04BFEA";
    arrayBytes = myEncryptionKey.getBytes(UNICODE_FORMAT);
    ks = new DESedeKeySpec(arrayBytes);
    skf = SecretKeyFactory.getInstance(DESEDE_ENCRYPTION_SCHEME);

    cipher = Cipher.getInstance(CIPHER_ALG);
    key = skf.generateSecret(ks);
}

public String decrypt(String encryptedString) {
    String decryptedText=null;
    try {
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] encryptedText = encryptedString.getBytes();
        byte[] plainText = cipher.doFinal(encryptedText);
        decryptedText= new String(plainText);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return decryptedText;
}
}
Was it helpful?

Solution

You are making it more complex than you need to with the SecretKeyFactory, etc. But the main problem is that you aren't converting hexadecimal numbers correctly.

class TripleDES
{

  private final String key;

  public static void main(String... args)
    throws Exception
  {
    TripleDES td = new TripleDES("1032FD2CD64A9D7FA4D061F76B04BFEA");
    String decrypted = td.decrypt("AC9C5A46A63FC9EA");
    System.out.println("expecting: 04286EDDFDEA6BD7");
    System.out.println("found: " + decrypted);
  }

  TripleDES(String key)
  {
    this.key = key;
  }

  public String decrypt(String input)
    throws Exception
  {
    byte[] tmp = h2b(this.key);
    byte[] key = new byte[24];
    System.arraycopy(tmp, 0, key, 0, 16);
    System.arraycopy(tmp, 0, key, 16, 8);
    Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
    cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "DESede"));
    byte[] plaintext = cipher.doFinal(h2b(input));
    return b2h(plaintext);
  }

  private static byte[] h2b(String hex)
  {
    if ((hex.length() & 0x01) == 0x01)
      throw new IllegalArgumentException();
    byte[] bytes = new byte[hex.length() / 2];
    for (int idx = 0; idx < bytes.length; ++idx) {
      int hi = Character.digit((int) hex.charAt(idx * 2), 16);
      int lo = Character.digit((int) hex.charAt(idx * 2 + 1), 16);
      if ((hi < 0) || (lo < 0))
        throw new IllegalArgumentException();
      bytes[idx] = (byte) ((hi << 4) | lo);
    }
    return bytes;
  }

  private static String b2h(byte[] bytes)
  {
    char[] hex = new char[bytes.length * 2];
    for (int idx = 0; idx < bytes.length; ++idx) {
      int hi = (bytes[idx] & 0xF0) >>> 4;
      int lo = (bytes[idx] & 0x0F);
      hex[idx * 2] = (char) (hi < 10 ? '0' + hi : 'A' - 10 + hi);
      hex[idx * 2 + 1] = (char) (lo < 10 ? '0' + lo : 'A' - 10 + lo);
    }
    return new String(hex);
  }

}

OTHER TIPS

The main problem seems the usage of Strings containing hexadecimal data that are converted via getBytes() to a byte array.

For converting a hex string to it's byte array representation you need an external library, such as apache.commons.codec.binary:

 myEncryptionKey = "1032FD2CD64A9D7FA4D061F76B04BFEA";
 arrayBytes = Hex.decodeHex(myEncryptionKey.toCharArray());
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top