我有一个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
答案 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");