我正在尝试加密客户端名称(字符串格式),将其存储在数据库中,然后检索并解密它。因为我需要避免使用任何第三方库,所以我使用了Java发行版中可用的类。
这个过程运行正常,直到我遇到一个带有特殊字符的名字(Ascii:48910)。这是一个问号(?)。加密和解密很顺利,但在解密后,特殊字符被替换为问号。
所以我将编码格式从'UTF-8'更改为'ISO-8859-1'。这解决了显示问题,但解密后仍然会替换特殊字符。
正在使用的代码和输出如下(我删除了不必要的代码):
package crypt;
import java.io.PrintStream;
import java.nio.charset.Charset;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.xml.bind.DatatypeConverter;
public class SecretKeyEncryptionExample {
private static final String FORMAT = "ISO-8859-1";
public static final String DESEDE_ENCRYPTION_SCHEME = "DESede";
private KeySpec ks;
private SecretKeyFactory skf;
private Cipher cipher;
SecretKey key;
public SecretKeyEncryptionExample() throws Exception {
String myEncryptionKey = "4A144BEBF7E5E7B7DCF26491AE79C54C768C514CF1547D23";
ks = new DESedeKeySpec(myEncryptionKey.getBytes(FORMAT));
skf = SecretKeyFactory.getInstance(DESEDE_ENCRYPTION_SCHEME);
cipher = Cipher.getInstance(DESEDE_ENCRYPTION_SCHEME);
key = skf.generateSecret(ks);
}
public String encrypt(String unencryptedString) throws Exception {
String encryptedString = null;
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plainText = unencryptedString.getBytes(FORMAT);
byte[] encryptedText = cipher.doFinal(plainText);
encryptedString = DatatypeConverter.printBase64Binary(encryptedText);
return encryptedString;
}
public String decrypt(String encryptedString) throws Exception {
String decryptedText = null;
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] encryptedText = DatatypeConverter.parseBase64Binary(encryptedString);
byte[] plainText = cipher.doFinal(encryptedText);
decryptedText = new String(plainText);
return decryptedText;
}
public static void main(String args[]) throws Exception {
SecretKeyEncryptionExample td = new SecretKeyEncryptionExample();
String target = "Expendable" + getSpecialCharacter(49810) + "s Pte Ltd";
String encrypted = td.encrypt(target);
String decrypted = td.decrypt(encrypted);
PrintStream out = new PrintStream(System.out, true, FORMAT);
out.println("String To Encrypt: " + target);
out.println("Encrypted String: " + encrypted);
out.println("Decrypted String: " + decrypted);
}
public static String getSpecialCharacter(int code) {
Charset charSet = Charset.forName(FORMAT);
String specialCharacter = new String(new byte[] { (byte) code }, charSet);
specialCharacter = String.format("%s", specialCharacter);
return specialCharacter;
}
}
输出:
String To Encrypt: Expendable’s Pte Ltd
Encrypted String: TAAJuF7KOmBZHBXFHsW0FB9YBwH7Tcif
Decrypted String: Expendable?s Pte Ltd
请告知如何解密,而无需更换特殊字符。
答案 0 :(得分:2)
我认为你应该在每次从字符串到字节数组并返回时指定编码。特别是,这一行:
decryptedText = new String(plainText);
应为:
decryptedText = new String(plainText, FORMAT);
否则,您依赖于环境的编码,这种编码很可能与FORMAT不同,导致特殊字符被打印为“?”。
答案 1 :(得分:1)
可能有用的一些事情。
System.out.println((int) getSpecialCharacter(49810).charAt(0));
打印
146
这是你在这里实际创建的角色。
System.out.println("The Falcon" + (char) 146 + "s Hangar Pte Ltd");
打印
The Falcon’s Hangar Pte Ltd
我认为问题在于您使用带有
的ISO-8859-1字符集获取字节byte[] plainText = unencryptedString.getBytes(FORMAT);
但是当你把它变回String时,你会使用系统默认值。
decryptedText = new String(plainText);
我怀疑这应该是
decryptedText = new String(plainText, FORMAT); // use the same Charset