Java 和 c++ 加密的结果不匹配

2022-09-02 04:47:13

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

我无法弄清楚为什么会发生这种情况。我在调试模式下运行了这两个代码,直到它们调用它们的库都具有相同的密钥,salt,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加密是罪魁祸首。我在两个地方都使用拉丁-1字符集。我可以检查的任何其他内容


答案 1

叹息!!

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

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

U2FsdGVkX18xMj

U2FsdGXt91mJpz

在上面的示例中,每种情况下只有两个隔离的 Base-64 字符(一个字节)被搞砸,这一事实几乎证明了损坏发生在加密之后。

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

你说你正在使用“拉丁语-1字符集在两个地方”,这清楚地表明你正在做一些你不应该做的转换 - 不应该用字符集来捣乱。


答案 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在拉丁语-1中,正式名称为控制字符。Windows Latin-1 正式版 将这些代码用于其他字符。ISO-8859-1Windows-1252

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


布伦德利

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