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 に答える