三重DES解密无效密钥,16字节

时间:2015-04-16 10:03:22

标签: java android encryption tripledes

我有一个Android项目,其中从我的Web服务获取三重DES加密文本。我需要三重DES解密。

但是,我收到了无效的密钥异常。我的密钥转换为HEX格式,我收到错误:W/System.err﹕ java.security.InvalidKeyException: DES key too long - should be 8 bytes我发现here一个论坛,解释说明十六进制可能会导致问题

“DES密钥通常以8个字节打包56位,因此他们给你的16个字节/字符很可能是密钥的十六进制编码字节。你可以得到一个十六进制解码器”

所以我使用

将十六进制字符串转换为字节数组
 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;
    }

并将其传递给密码,我收到错误:

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

这是我的解密方法。如果有人可以发现我可能出错的地方,我将不胜感激。

 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;
}

我的密钥是C9AF269DF8A78A06D1216BFFF8F0536A。

我已经检查过客户端并且密钥是正确的,因此使用相同的密钥进行加密。

加密代码

 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;
    }

以下是包含14个字符的解密文本示例:12345678901234

3 个答案:

答案 0 :(得分:2)

DES会期望一个8字节密钥(带奇偶校验)。所以Triple DES需要24字节密钥(带奇偶校验)。由于您只有一个16字节的密钥,因此必须复制其中一些密钥才能获得最终密钥。通常,第一个和最后8个字节是相同的。您可以尝试两种变体:

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

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

hexConvert := K1 || K2

答案 1 :(得分:1)

也许你必须使用这个密码:

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"));

}

对于解密:

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);

}

看一下我在密码的实例中使用“PKCS5Padding”。

请注意,填充用于在所有块中给出相同的大小(例如,如果最后一个块是788而不是1024)。

为了创建密钥,在我的解决方案中(它不是唯一的),我计算一个sha-256哈希,然后我得到Des键的必要字节:

计算哈希:

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;
}

最后只得到Des键所需的128个字节:

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

这是我的解决方案,但不是唯一的解决方案!

答案 2 :(得分:1)

您将Cipher实例化为(singel)DES密码:

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

但你的密钥是 16字节 3Des密钥,并且你得到错误

DES key too long - should be 8 bytes

尝试将您的密码实例化为3DES密码:

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