为什么我的简化DES的实现在Cp1252编码下工作良好,而不是在UTF-8下



我昨天问了以下问题,但由于我没有真正包括我的实际问题的任何细节,所以它没有得到太多关注。

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

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

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向字符串添加了更多的字节。然而,我不知道为什么。我的意思是初始文本似乎有相同的字节数那么为什么这些字节在加密后会增加解密后会增加更多呢?我很感激你提供的任何帮助。提前感谢!

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

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

加密是一个二进制操作。它接受字节并返回其他字节。无论采用何种编码方式,都不能盲目地将字节转换为字符,因为并非所有字节都表示有效字符。如果要将二进制信息(如加密文本)转换为字符串,请使用十六进制或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");

相关内容

最新更新