2017-03-31 108 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