Triple DES decryption invalid key with 16 bytes

会有一股神秘感。 提交于 2019-12-30 03:39:32

问题


I have an android project in which am getting an Triple DES encrypted piece of text from my web services. I need to Triple DES decrypt.

However, I am getting invalid key exceptions. My key is converted to HEX format and I got an error: W/System.err﹕ java.security.InvalidKeyException: DES key too long - should be 8 bytes I found here a forum explaining that hex may cause issue

"DES keys are 56 bits normally packaged in 8 bytes so the chances are that the 16 bytes/characters they have given you are the hex encoded bytes of the key. You can get a hex decoder"

So I converted my hex string to a byte array using

 private static byte[] hexStringtoByteArray(String hex){
        int len = hex.length();

        byte [] data = new byte[len/2];
        for(int i=0; i<len;i+=2){
            data[i/2] = (byte)((Character.digit(hex.charAt(i), 16)<<4) + Character.digit(hex.charAt(i+1),16));
        }
        return data;
    }

and passed that in to the cipher and I get an error:

W/System.err﹕ java.security.InvalidKeyException
W/System.err﹕ at javax.crypto.spec.DESedeKeySpec.

here is my decrypt method. I would appreciate if someone could shine some light on where I might be going wrong.

 public String DesDecryptPin(String pin, String encryptKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {

    String UNICODE_FORMAT = "UTF8";
    String decryptedPinText = null;

    byte[] hexConvert = hexStringtoByteArray(encryptKey);

    SecretKey desKey = null;
    KeySpec desKeySpec = new DESedeKeySpec(hexConvert); // Exception HERE
    Cipher desCipher;
    SecretKeyFactory skf = SecretKeyFactory.getInstance("DESede");
    desCipher = Cipher.getInstance("DES/ECB/NoPadding");
    try {
        desKey = skf.generateSecret(desKeySpec);
    } catch (InvalidKeySpecException e) {
        e.printStackTrace();
    }

    desCipher.init(Cipher.DECRYPT_MODE, desKey);
    byte[] decryptPin = desCipher.doFinal(pin.getBytes());
    decryptedPinText = new String(decryptPin, "UTF-8");

    return decryptedPinText;
}

My key is C9AF269DF8A78A06D1216BFFF8F0536A.

I have checked with the client and the key is correct, so the same key is being used for encryption.

Encryption Code

 public string TripleDESEncrypt(string strClearText, string strKey)
    {
        byte[] bytClearText;
        byte[] bytClearTextChunk = new byte[8];
        byte[] bytEncryptedChunk = new byte[8];
        int BytesCount = 0;
        int nArrayPosition = 0;
        string strEncryptedChar;
        string strEncryptedText = "";

        ArrayList Input = new ArrayList();
        ArrayList Output = new ArrayList();

        TripleDESCryptoServiceProvider tdes = (TripleDESCryptoServiceProvider)TripleDESCryptoServiceProvider.Create();

        tdes.Key = HexToByteArray(strKey);
        tdes.Mode = CipherMode.ECB;

        ICryptoTransform tdesEncrypt = tdes.CreateEncryptor();

        bytClearText = ASCIIEncoding.ASCII.GetBytes(strClearText);
        BytesCount = bytClearText.Length;

        for (int i = 0; i < BytesCount; i++)
        {
            if (nArrayPosition == 8)
            {
                Input.Add(bytClearTextChunk);
                bytClearTextChunk = new byte[8];
                nArrayPosition = 0;
            }
            bytClearTextChunk[nArrayPosition] = bytClearText[i];
            nArrayPosition++;
        }

        if (nArrayPosition != 0)
            Input.Add(bytClearTextChunk);


        foreach (byte[] Cbyte in Input)
        {
            tdesEncrypt.TransformBlock(Cbyte, 0, 8, bytEncryptedChunk, 0);
            Output.Add(bytEncryptedChunk);
            bytEncryptedChunk = null;
            bytEncryptedChunk = new byte[8];
        }


        foreach (byte[] Cbyte in Output)
        {
            foreach (byte BByte in Cbyte)
            {
                strEncryptedChar = BByte.ToString("X");
                strEncryptedChar = strEncryptedChar.PadLeft(2, Convert.ToChar("0"));
                strEncryptedText += strEncryptedChar;
            }
        }

        return strEncryptedText;
    }

Here is an example of the decrypted text with 14 chars: 12345678901234


回答1:


DES would expect an 8 byte key (with parity). So Triple DES expects a 24 byte key (with parity). Since you only have a 16 byte key, you have to replicate some of it, to get the final key. Oftentimes the first and last 8 bytes are the same. You can try two variants:

byte[] tdesKey = new byte[24];
System.arraycopy(hexConvert, 0, tdesKey, 0, 16);
System.arraycopy(hexConvert, 0, tdesKey, 16, 8);
// tdesKey := K1 || K2 || K1

or

byte[] tdesKey = new byte[24];
System.arraycopy(hexConvert, 8, tdesKey, 0, 8);
System.arraycopy(hexConvert, 0, tdesKey, 8, 16);
// tdesKey := K2 || K1 || K2

when

hexConvert := K1 || K2



回答2:


Maybe you must to use this cipher:

public byte[] encTripleDes (String txt, byte [] key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidKeySpecException{
    DESedeKeySpec keySpec = new DESedeKeySpec(key);
    SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("DESede");
    SecretKey ky = keyfactory.generateSecret(keySpec);

    Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, ky);
    return cipher.doFinal(txt.getBytes("UTF-8"));

}

And for decrypting:

public byte[] uncTripleDes (byte [] encryptedTextBytes, byte [] key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidKeySpecException{
    DESedeKeySpec keySpec = new DESedeKeySpec(key);
    SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("DESede");
    SecretKey ky = keyfactory.generateSecret(keySpec);

    Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, ky);
    return cipher.doFinal(encryptedTextBytes);

}

Look that I use a "PKCS5Padding" in the instance of the cipher.

Notice that the padding is used for give the same size at all the blocks (for example if the last block is 788 instead of 1024).

For create the key, in my solution (it's not the only one), I calculate a sha-256 hash and then I get the necessary bytes for the Des key:

Calculating the hash:

public byte[] sumCalc (){ 
    String key = "anyKey";
    byte[] hashedKey = null;
    try {
        byte [] byteKey = key.getBytes("UTF-8");
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        hashedKey = md.digest(byteKey);
    }catch (Exception ex){
        System.err.println("Error generant clau" + ex);  
    }
    return hashedKey;
}

Finally get only the 128 bytes that we need for the Des key:

bytedKey = Arrays.copyOf(bytedKey, 16 ); // 16 use only first 128 bit. if 32 use only 256

It's my solution but not the only one!




回答3:


You instantiate your Cipher as a (singel) DES Cipher with:

desCipher = Cipher.getInstance("DES/ECB/NoPadding");

But your key is a 16 byte 3Des key, and thuse you get the error

DES key too long - should be 8 bytes

Try instantiating your cipher as a 3DES cipher with:

desCipher = Cipher.getInstance("DESede/ECB/NoPadding");


来源:https://stackoverflow.com/questions/29671427/triple-des-decryption-invalid-key-with-16-bytes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!