我在C#中有一个应用程序,它使用RijndaelManaged 加密 部分文件 (因为它们是大文件)。因此,我将文件转换为字节数组并仅对其一部分进行加密。
然后,我想使用Java解密文件。因此,我只需要解密用C#加密 的文件的一部分 (意味着那些字节)。
问题来了。因为在C#中,我们 有无符号字节 ,在Java中,我们有 符号字节 。因此,我的加密和解密无法按照我想要的方式工作。
在C#中,我将加密字节和普通字节结合在一起,并用保存File.WriteAllBytes。所以我不能在这里使用 sbyte ,或者我不知道该怎么做:
File.WriteAllBytes
byte[] myEncryptedFile = new byte[myFile.Length]; for (long i = 0; i < encryptedBlockBytes.Length; i++) { myEncryptedFile[i] = encryptedBlockBytes[i]; } for (long i = encryptedBlockBytes.Length; i < myFile.Length; i++) { myEncryptedFile[i] = myFileBytes[i]; } File.WriteAllBytes(@"C:\enc_file.big", myEncryptedFile);
(Java中有完全相同的解密代码)
所以我的问题是:
尽管您不能在Java中使用无符号字节,但是您可以简单地忽略该问题。
AES和所有现代对称密码都以字节为单位,并且输入和输出已定义为字节(或八位位组)。输入和输出已通过NIST进行了标准化,并且可以使用测试向量。
如果查看字节的单独位内容,则{200,201,202}C#和{(byte)200, (byte)201, (byte)202}Java中的相同。这是因为Java使用字节的二补码表示。
{200,201,202}
{(byte)200, (byte)201, (byte)202}
将数字200作为整数:将以11010000二进制形式表示,-56如果用两个补数的(带符号)字节使用,则表示Java中的数字。现在,对称密码将简单地将这些位转换为另一个(通常使用完整的位 块 )。
200
11010000
-56
找到答案后, 当您查看单独的位时 ,您会发现它们在C#和Java中都是相同的。但是,C#将把它们解释为无符号值,将Java解释为有符号值。
如果要打印或将这些值用作Java中的带符号数字,则必须将它们转换为带正符号的整数。做到这一点的方法是使用int p = b & 0xFF。
int p = b & 0xFF
这将执行以下操作(我将再次使用数字200):
11010000 变成 11111111 11111111 11111111 11010000
11111111 11111111 11111111 11010000
0xFF
00000000 00000000 00000000 11111111
11111111 11111111 11111111 11010000 & 00000000 00000000 00000000 11111111 = 00000000 00000000 00000000 11010000
该值与200带符号整数的值相同。