2013-01-05 29 views
0

昨天我問了下面的問題,但沒有得到太多的關注,因爲我沒有真正包含任何關於我的實際問題的細節。爲什麼我的簡體DES在Cp1252編碼下工作正常,但不在UTF-8下工作?

Eclipse:Using UTF-8 encoding in the text editor make the Strings not work properly, how can I fix that?

我會嘗試儘可能多的分析,以給你這是怎麼回事豁然開朗我的問題。

我有一個大學項目,我應該爲教育目的實施簡化的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 

爲了看到實際的位表示每個I加密時間和解密我爲了顯示每個字符串的所有數據創建了以下函數的數據:

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

每次你做String.getBytes(),你都會默認使用你的平臺默認編碼來將字符轉換爲字節。如果字符串包含無法使用平臺默認編碼表示的字符,則會丟失信息。因此,請使用支持地球上每個字符的顯式編碼,如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"); 
+0

的確,如果他用像FindBugs這樣的靜態代碼分析工具這一缺陷(使用'的getBytes( )而不是'getBytes(String)')會立即被報告。 –

+2

不是說它有什麼不同,但[StandardCharsets](http://docs.oracle.com/javase/7/docs/api/java/nio/charset/StandardCharsets.html)類型現在提供了預定義的變量以供在類型安全的方法/構造函數。 – McDowell

+0

非常感謝您的明確解釋,我的問題終於解決了! – ksm001

相關問題