2017-03-31 107 views
1

我有一個MS-Access數據庫,裏面有加密的字符串。這些看起來是這樣的: encrypted stringsJackcess:MSAccess數據庫的錯誤字符集

但是,我很快注意到,這些字符串的長度恰好匹配明文的長度(我知道明文)。因此,通過對Excel的一些嘗試,我發現如果您使用=CODE(<char>)-函數(因此您可以在默認字符集中獲得字符代碼,並且反之亦然),並且將該數字與該字母的字符代碼進行異或運算應代表你總是得到相同的結果。這意味着我只需要用java和瞧這些值創建一個數組。的Excel示例(在右側所提到的 「陣列」): excel example decoding 實施例: 「>>」 具有(DEC)187的索引,所以187xor253產生70 => 「F」

現在,我使用jackcess到訪問這些值和「解密」大多是好的,但我有時從字符串中得到錯誤的字符。在Excel中,一切正常。代碼與最好的結果:

public static final int[] DECRYPT_KEY = { 253, 203, 204, 217, 226, 205, 128, 201, 222, 183, 58, 217, 230, 201, 183, 211, 158, 203, 167, 213, 35, 33, 201, 123, 186, 247 }; 

public static void main(String[] args) throws IOException 
{ 
    System.out.println(System.getProperty("file.encoding")); 


    Database db = DatabaseBuilder.open(new File("/home/***/TM.db"));     
    Table table = db.getTable("personal"); 

    for (Row row : table) 
    { 
     String vorname = row.getString("vorname"); 
     byte[] vornameArr = vorname.getBytes("cp1252"); 
     for (int i1 = 0; i1 < vornameArr.length; i1++) 
     {    
      vornameArr[i1] = (byte) ((vornameArr[i1] & 0xff)^DECRYPT_KEY[i1]); 
     } 

     System.out.println(new String(vornameArr, "cp1252")); 
    } 
} 

但正如我所說,一些字符仍然是錯誤的,但在Excel中,但一切都很好。當我打印getBytes("cp1272")給出的數字時,它與Excel完全不同。

你有什麼想法,我可能做錯了什麼,爲什麼java有時會給出與Excel不同的值?什麼是更好的方法?我已經嘗試過所有的字符集組合,有些工作在其他人失敗的地方,但之後出現了其他錯誤的結果。

+1

嗯....奇怪。只是爲了它,試試「windows-1252」。 「cp1252」是用於java.io API和java.lang API的規範名稱,「windows-1253」是用於java.nio API的規範名稱。 – DevilsHnd

+0

不,可悲的是它沒有幫助。上面顯示的名稱「Fadima」導致「FadiÝa」。這是唯一的一個,所有其他都很好 – TheFreddy1404

回答

1

所以,感謝@Gord Thompson和他建議的網站(fileformat.info),我終於找到了答案:有時候角色看起來很相似,數據庫中的某些原因是「較高」的優先(如unicode字符402和131)。我的java代碼預計一切都有較低的價值,如Excel提供。所以,如果代碼高於255,則需要用較低的值代替。出於某種原因,getBytes("cp1252")將始終返回值較低,但toCharArray()getBytes("UTF-16LE")將返回較高,正確的值(比較:fileformat 192

所以我的代碼是現在這個樣子和完美的作品:

String vorname = row.getString("vorname"); 
char[] vornameArr = vorname.toCharArray();   
for (int i = 0; i < vornameArr.length; i++) 
{ 
    if (vornameArr[i] > 255) 
    { 
     vornameArr[i] = (char) (String.valueOf(vornameArr[i]).getBytes("cp1252")[0] & 0xff); 
    } 

    vornameArr[i] = (char) (vornameArr[i]^DECRYPT_KEY[i]); 
} 

System.out.println(String.valueOf(vornameArr)); 

非常感謝您的幫助!

+1

感謝您花時間發佈您的發現。澄清:並非getBytes(「cp1252」)對給定字符返回「較低值」,它只是返回該字符的單字節值 - 「帶小鉤的拉丁文小信號」 - * in Windows-1252字符集*。它說明了該字符(0x0192,十進制數402)的* Unicode代碼點*與Windows-1252(0x83,十進制數131)中相應的*字節值*之間的區別。 –

1

我能夠通過在您的問題中使用字節值篡改數據庫文件來重新創建您的問題。行

byte[] vornameArr = vorname.getBytes("cp1252"); 

嘗試將vorname字符轉換爲CP1252字節,但沒有對應於U + 008F(十進制143,SINGLE SHIFT THREE)沒有CP1252字符,所以Java轉換該字符到一個問號(0x3F的)。因此,你的解碼步驟是解碼0x3F而不是0x8F,這就是爲什麼你得到「FadiÝa」而不是「Fadima」。

我可以通過你的解碼循環替換單行以上

byte[] doubleBytes = vorname.getBytes("UTF-16LE"); // 187 0 170 0 168 0 ... 
byte[] vornameArr = new byte[doubleBytes.length/2]; 
for (int i = 0; i < vornameArr.length; i++) { 
    vornameArr[i] = doubleBytes[i * 2]; // remove nulls 
} 

,然後運行vornameArr字節來得到正確的結果。 (如果你喜歡的話,你也可以在上面的循環中應用解碼轉換。)

+0

非常感謝!這讓我更進了一步。不幸的是,現在所有其他名稱都有問題。例如,「Thomas」是 [[87,0,-93,0,-93,0,-76,0,-110,1,-66,0](之前的陣列) [84,104,111 ,109,112,115](陣列後) Thomps' – TheFreddy1404

+0

什麼是原始數字,就像您在問題中顯示的電子表格中顯示的那樣? –

+0

對於「托馬斯」來說,它應該是'169,163,163,180,131,190',它們應該變成'84,104,111,109,97,115',所以唯一的區別就是97. 112. 「托馬斯」是你在第一張照片中看到的第一個名字,從版權標誌 – TheFreddy1404