0

我昨天问了以下问题,但由于我没有真正包含有关我的实际问题的任何细节,因此没有引起太多关注。

Eclipse:在文本编辑器中使用 UTF-8 编码会使字符串无法正常工作,我该如何解决?

我将尝试尽可能多地分析我的问题,以便让您清楚地了解正在发生的事情。

我有一个大学项目,我应该为教育目的实现简化的 DES 算法。该算法是一种加密算法,它使用 10 位密钥来加密 8 位数据。

在实现中,我想包括加密任何字符串。

所以我编写了 8 位加密的代码,它对各种输入都非常有效。为了包含字符串加密支持,我使用了该函数String.getBytes(),将字符串的所有字节保存在一个变量中byte[] data

然后我遵循了这个逻辑:

int i;
for(i=0; i< data.length; i++)
    data[i] = encrypt(data[i]);

对于解密,我遵循以下逻辑:

int i;
for(i=0; i< data.length; i++)
    data[i] = encrypt(data[i]);

这是main函数中的实际代码

public static void main(String[] args){

    short K = (short) Integer.parseInt("1010010001",2);
    SDEncryption sdes = new SDEncryption(K); //K is the 10 bit key

    String test = "INFO BOB 57674";

    //let's encrypt the String test
    String enc = sdes.encrypt(test.getBytes());

    //let's decrypt the encrypted String of the initial String
    String dec = sdes.decrypt(enc.getBytes());
}

通过使用默认编码 Cp1252。我尝试加密字符串并得到以下结果:

Initial Text: INFO BOB 57674
Encrypted Text: ÅO [áa[aá»j×jt
Decrypted Text: INFO BOB 57674

为了在每次加密和解密数据时查看实际位表示,我创建了以下函数以显示每个字符串的所有数据:

public void show(byte[] data){
    //εμφάνιση των 
    //note how the Greek letters aren't displayed at all under Cp1252

    int i;
    for(i=0;i<data.length;i++){

        short mask = (short) (1<<7); //10000000
        while(mask>0){
            if((data[i]&mask) == 0)
                System.out.print("0");
            else
                System.out.print("1");

            mask = (short) (mask >> 1);
        }
        if(i < data.length - 1){

            System.out.print(" ");
        }
    }
    System.out.println();
}

所以我得到了以下结果:

Initial Text(binary): 01001001 01001110 01000110 01001111 00100000 01000010 01001111 01000010 00100000 00110101 00110111 00110110 00110111 00110100
Encrypted Text(binary): 11000101 01001111 00100000 01011011 11100001 01100001 01011011 01100001 11100001 10111011 01101010 11010111 01101010 01110100
Decrypted Text(binary): 01001001 01001110 01000110 01001111 00100000 01000010 01001111 01000010 00100000 00110101 00110111 00110110 00110111 00110100

似乎一切都按预期工作。不过,为了在代码编辑器中支持希腊字母,我不得不将编码更改为 UTF-8。

再次运行所有内容后,我得到以下结果:

Initial Text: INFO BOB 57674
Encrypted Text: �O [�a[a�j�jt
Decrypted Text: ���NFO���BOB���7���74

请注意解密文本的某些单词是如何正确显示的,例如NFOBOB。在我看来,位操作似乎存在某种问题,好像 Eclipse 无法识别遵循 UTF-8 规则的位序列。

以下是二进制形式的结果:

Initial Text(binary): 01001001 01001110 01000110 01001111 00100000 01000010 01001111 01000010 00100000 00110101 00110111 00110110 00110111 00110100
Encrypted Text(binary): 11101111 10111111 10111101 01001111 00100000 01011011 11101111 10111111 10111101 01100001 01011011 01100001 11101111 10111111 10111101 01101010 11101111 10111111 10111101 01101010 01110100
Decrypted Text(binary): 11101111 10111111 10111101 11101111 10111111 10111101 11101111 10111111 10111101 01001110 01000110 01001111 11101111 10111111 10111101 11101111 10111111 10111101 11101111 10111111 10111101 01000010 01001111 01000010 11101111 10111111 10111101 11101111 10111111 10111101 11101111 10111111 10111101 00110111 11101111 10111111 10111101 11101111 10111111 10111101 11101111 10111111 10111101 00110111 00110100

现在我可以清楚地看到问题所在了。似乎 UTF-8 向字符串添加了更多字节。但是我不确定为什么。我的意思是初始文本似乎具有相同数量的字节,那么为什么在加密后添加这些字节,而在解密后添加更多字节呢?

我将不胜感激提供的任何帮助。先感谢您!

4

1 回答 1

4

每次您这样做时String.getBytes(),您都会隐式使用您的平台默认编码将字符转换为字节。如果字符串包含无法使用您平台的默认编码表示的字符,则会丢失信息。因此,请使用支持地球上每个字符的显式编码,例如 UTF8: string.getBytes("UTF8")

同样,当您这样做时new String(bytes),您使用平台的默认编码将字节转换为字符。如果字节实际上是使用另一种编码的文本编码,或者根本不是字符,而是纯粹的二进制信息,那么您也会丢失信息。

加密是二进制操作。它接受字节并返回其他字节。无论编码是什么,您都不能盲目地将字节转换为字符,因为并非所有字节都表示有效字符。如果要将二进制信息(如加密文本)转换为字符串,请使用 Hex 或 Base64 编码。

所以加密过程应该是:

String clearText = ...:
byte[] clearTextAsBytes = clearText.getBytes("UTF8");
byte[] encryptedBinary = encrypt(clearTextAsBytes);
String encryptedBinaryAsPrintableChars = toBase64(encryptedBinary);

并且解密过程应该是对称的:

String encryptedBinaryAsPrintableChars = ...;
byte[] encryptedBinary  = fromBase64(encryptedBinaryAsPrintableChars);
byte[] decryptedTextAsBytes = decrypt(encryptedBinary);
String decryptedText = new String(decryptedTextAsBytes, "UTF8");
于 2013-01-05T15:56:49.313 回答