21

我有一个现有的 c++ 代码,它将加密一个字符串。现在我在 . 一些加密字符串是匹配的。有些是一两个字符不匹配。

我无法弄清楚为什么会这样。我在调试模式下运行这两个代码,直到他们调用他们的库都具有相同的密钥、盐、iv 字符串进行加密。

我知道即使单个字节填充更改会大幅修改加密字符串。但在这里我只是看到一两个字符发生了变化。这是一个示例(星号之间的粗体字符是不匹配的部分)

爪哇:

U2FsdGVkX18xMjM0NTY3OGEL9nxFlHrWvodMqar82NT53krNkqat0rrgeV5FAJFs1vBsZIJPZ08DJVrQ* Pw *yV15HEoyECBeAZ6MTeN+ZYHRitKanY5jiRU2J0KP0Fzola

C++:

U2FsdGVkX18xMjM0NTY3OGEL9nxFlHrWvodMqar82NT53krNkqat0rrgeV5FAJFs1vBsZIJPZ08DJVrQ* jQ *yV15HEoyECBeAZ6MTeN+ZYHRitKanY5jiRU2J0KP0Fzola

我正在使用 AES 加密。提供者是 SunJCE 1.6 版。我尝试将提供者更改为 Bouncy Castle。即使那样结果也是一样的。

增加了一个样本:

C++:

U2FsdGVkX18xMjM0NTY3O* I* /BMu11HkHgnkx+dLPDU1lbfRwb+aCRrwkk7e9dy++MK+/94dKLPXaZDDlWlA3gdUNyh/Fxv* oF *STgl3QgpS0XU=

爪哇:

U2FsdGVkX18xMjM0NTY3O* D* /BMu11HkHgnkx+dLPDU1lbfRwb+aCRrwkk7e9dy++MK+/94dKLPXaZDDlWlA3gdUNyh/Fxv* j9 *STgl3QgpS0XU=

更新:

根据评论,我觉得 base 64 加密是罪魁祸首。我在两个地方都使用了 Latin-1 字符集。还有什么我可以检查的

4

2 回答 2

7

叹!!

几乎可以肯定的问题是,在您加密数据并将加密数据作为字节字符串接收后,您正在对数据进行某种字符转换,然后再通过 Base-64 转换发送数据。

请注意,如果您对字符串“ ABC_D_EFG 和“ABC_G_EFG ”进行加密,加密后的输出将完全不同,从第 4 个字符开始,一直持续到最后。换句话说,Base-64 输出将类似于(使用虚构值):

U2FsdGVkX18xMj

U2FsdGXt91mJpz

在上面的例子中,只有两个孤立的 Base-64 字符(一个字节)在每种情况下都被弄乱了,这一事实几乎证明了损坏发生在加密之后。

加密过程的输出是字节序列,而不是字符序列。观察到的损坏与错误地将字节解释为字符并在将它们输入 Base-64 转换器之前尝试对其执行代码页转换是一致的。加密器的输出应直接送入 Base-64 转换器,无需任何转换。

你说你在两个地方都使用了“Latin-1 char set”,这清楚地表明你正在做一些你不应该做的转换——应该没有必要使用 char 集。

于 2012-06-20T21:11:10.293 回答
2

先来一段代码:

import javax.xml.bind.DatatypeConverter;

...

public static void main(String[] args) {
    String s1j = "U2FsdGVkX18xMjM0NTY3OGEL9nxFlHrWvodMqar82NT53krNkqat0rrgeV5FAJFs1vBsZIJPZ08DJVrQPwyV15HEoyECBeAZ6MTeN+ZYHRitKanY5jiRU2J0KP0Fzola";
    String s1c = "U2FsdGVkX18xMjM0NTY3OGEL9nxFlHrWvodMqar82NT53krNkqat0rrgeV5FAJFs1vBsZIJPZ08DJVrQjQyV15HEoyECBeAZ6MTeN+ZYHRitKanY5jiRU2J0KP0Fzola";
    byte[] bytesj = DatatypeConverter.parseBase64Binary(s1j);
    byte[] bytesc = DatatypeConverter.parseBase64Binary(s1c);
    int nmax = Math.max(bytesj.length, bytesc.length);
    int nmin = Math.min(bytesj.length, bytesc.length);
    for (int i = 0; i < nmax; ++i) {
        if (i >= nmin) {
            boolean isj = i < bytesj.length;
            byte b = isj? bytesj[i] : bytesc[i];
            System.out.printf("%s [%d] %x%n", (isj? "J" : "C++"), i, (int)b & 0xFF);
        } else {
            byte bj = bytesj[i];
            byte bc = bytesc[i];
            if (bj != bc) {
                System.out.printf("[%d] J %x != C++ %x%n", i, (int)bj & 0xFF, (int)bc & 0xFF);
            }
        }
    }
}

这提供

[60] J 3f != C++ 8d

现在 0x3f 是问号的代码。

错误是,0x80 - 0xBF 是 Latin-1,正式的ISO-8859-1,控制字符。Windows Latin-1 正式Windows-1252将这些代码用于其他字符。

因此,您应该在 Java 中使用“Windows-1252”或“Cp1252”(代码页)。


直言不讳

在加密中,0x80 .. 0xBF 范围内的原始字节被替换为问号,因为某些转换为 ISO-8859-1 而不是 Windows-1252 到 byte[]。

于 2012-06-20T20:12:28.533 回答