2

我正在尝试加密客户端的名称(字符串格式),将其存储在数据库中,然后检索它并解密它。由于我需要避免使用任何第三方库,因此我使用了 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

请告知如何在不替换特殊字符的情况下进行解密。

4

2 回答 2

2

我认为每次从字符串到字节数组并返回时都应该指定编码。特别是,这一行:

decryptedText = new String(plainText);

应该读:

decryptedText = new String(plainText, FORMAT);

否则,您将依赖环境的编码,这很可能与 FORMAT 不同,并导致特殊字符被打印为“?”。

于 2013-01-07T12:00:24.823 回答
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);

但是当您将其转回字符串时,您将使用系统默认值。

decryptedText = new String(plainText);

我怀疑这应该是

decryptedText = new String(plainText, FORMAT); // use the same Charset
于 2013-01-07T11:57:53.293 回答