我正在使用以下代码进行我正在使用的采样3DES加密:
package Algorithms;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
public class MyDES {
public static String encrypt(String pass,String plainText) throws NoSuchAlgorithmException, UnsupportedEncodingException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
byte[] key = pass.getBytes("UTF-8"); //get byte arrays of the given password
MessageDigest sha = MessageDigest.getInstance("SHA-1"); //get SHA-1 hashing instance
key=sha.digest(key); //has the given password
key=Arrays.copyOf(key,24);//take the first 16 bytes as the key for DES encryption
SecretKeySpec sks = new SecretKeySpec(key, "DESede");//key spec for 3-DES
Cipher c = Cipher.getInstance("DESede");//get an instance of 3DES
c.init(Cipher.ENCRYPT_MODE,sks); //initialize 3DES to encrypt mode with given parameters
byte[] cipherTextBytes = c.doFinal(plainText.getBytes()); //encrypt
System.out.println("key used: "+new String(key)+" cipher generated "+new String(cipherTextBytes));
StringBuffer cipherText= new StringBuffer();
for(int i=0;i<cipherTextBytes.length;i++)
{
cipherText.append(Integer.toHexString(cipherTextBytes[i]));
}
System.out.println("Final Cipher returned: "+cipherText.toString());
return cipherText.toString();
}
public static String decrypt(String pass,String cipherText) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
System.out.println("Initially in decryption-> pass:"+pass+" cipher: "+cipherText);
byte[] byteArray = new byte[cipherText.length() / 2];
int j=0;
for(int k=0;k<cipherText.length()-1;k+=2)
{
String o= cipherText.substring(k,k+2);
int dec = Integer.parseInt(o,16);
byteArray[j++] = (byte)dec;
}
String plainText="";
byte[] key = pass.getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key=sha.digest(key);
key=Arrays.copyOf(key,24);
System.out.println("\nkey obtained: "+new String(key)+"\n Later cipher text:-> "+new String(byteArray));
SecretKeySpec sks = new SecretKeySpec(key, "DESede");
Cipher c = Cipher.getInstance("DESede");
c.init(Cipher.DECRYPT_MODE,sks);
plainText = new String(c.doFinal(byteArray));
return plainText;
}
}
这里我试图获取密码,使用SHA-1哈希,然后使用生成的has作为我的3DES的关键。生成的密码正在转换为十六进制表示,因为我在保存和检索密码中的奇怪字符时遇到问题。
在解密中,我将密码从十六进制再次转换为普通字符串然后解密。但我得到javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
例外。知道我哪里错了吗?
答案 0 :(得分:3)
问题隐藏在多个层次下。
StringBuilder sb = new StringBuilder();
...
sb.append((char)dec);
因此,您尝试通过调用StringBuilder.Append(char)来组装原始二进制数据。嗯,那是做什么的?
StringBuilder.Append(char)的文档说“整体效果就像是通过方法String.valueOf(char)将参数转换为字符串,然后将该字符串中的字符附加到此字符序列。 “
好的,那么String.valueOf(char)的文档是什么意思呢?我很高兴你问。它说它“返回:一个长度为1的字符串,其中包含参数c的单个字符。” (你可以看到,返回类型是'String'。)
啊,但是String值是如何工作的?好吧,我们来看看documentation on that。它表示,“字符串表示UTF-16格式的字符串,其中补充字符由代理项对表示(有关详细信息,请参阅字符类中的Unicode字符表示形式一节)。索引值是指char代码单元,因此a补充字符在字符串中使用两个位置。“
这就是问题所在。您正在将原始二进制密文转换为UTF-16字符和代理对,这肯定不是您想要的。
答案 1 :(得分:2)
啊我觉得我明白了。 尝试简化您的代码,难以阅读。 避免使用字符串并尽可能多地使用数组,当你必须使用二进制数据时最好使用字节数组。
隔离问题!将程序拆分为较小的函数,以完成更简单的任务。
您可以使用标准Base64编码器来执行此操作。见http://www.docjar.com/docs/api/sun/misc/BASE64Encoder.html Base64当然比十六进制编码短。
如果您想继续使用HEX转换,请尝试使用我在google上找到的这些功能:http://www.developerfeed.com/javacore/blog/how-convert-hex-string-bytes-and-viceversa-java
我试着稍微简化代码。 您可以使用要编写的新编码函数来代替新的sun.misc.BASE64Encoder()。encode()或decode()。
private static byte[] getPassKey(String pass)
{
byte[] passKey = pass.getBytes("UTF-8"); //get byte arrays of the given password
byte[] shaKey = MessageDigest.getInstance("SHA-1").digest(passKey);
return Arrays.copyOf(shaKey,24);
}
public static String encrypt(String pass, String plainText) throws NoSuchAlgorithmException, UnsupportedEncodingException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
Cipher desCipher = Cipher.getInstance("DESede");
desCipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(getPassKey(pass), "DESede"));
byte[] cipherTextBytes = desCipher.doFinal(plainText.getBytes());
String encoded = new sun.misc.BASE64Encoder().encode(cipherTextBytes);
return encoded;
}
public static String decrypt(String pass,String cipherText) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
byte[] decoded = new sun.misc.BASE64Encoder().decode(cipherText);
Cipher desCipher = Cipher.getInstance("DESede");
desCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(getPassKey(pass), "DESede"));
plainText = new String(desCipher.doFinal(decoded));
return plainText;
}
未经测试,只是在记事本中用刮笔写的。