我在C#中有一个应用程序使用RijndaelManaged加密部分文件(因为它们是大文件)。所以我将我的文件转换为字节数组并仅加密其中的一部分。
然后我想用Java解密文件。因此,我必须解密仅在C#中加密的部分(意味着那些字节)。
问题来了。因为在C#中我们有无符号字节,而在Java中我们有有符号字节。所以我的加密和解密不能按我想要的方式工作。
在C#中,我将加密的字节和普通字节加在一起,并用File.WriteAllBytes
保存。所以我不能在这里使用 sbyte 或者我不知道该怎么做:
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中解密的代码完全相同)
所以我的问题是:
答案 0 :(得分:3)
虽然你不能在Java中使用无符号字节,但你可以忽略这个问题。
AES - 以及所有现代对称密码 - 按字节操作,输入和输出已定义为字节(或八位字节)。输入和输出已由NIST标准化,并且可以使用测试向量。
如果查看字节的单独位内容,那么C#中的{200,201,202}
和Java中的{(byte)200, (byte)201, (byte)202}
是相同的。这是因为Java使用字节的双补码表示。
将数字200
作为整数:这将是二进制的11010000
,如果在两个补码中的(带符号)字节中使用,则表示Java中的数字-56
。现在,对称密码将简单地将这些位转换为另一个位(通常使用完整的块位)。
一旦检索到答案,当您查看单独的位时,您将看到它们在C#和Java 中是相同的。但是,C#会将这些解释为无符号值,将Java解释为有符号值。
如果要在Java中打印或使用这些值作为带符号的数字,则必须将它们转换为正有符号整数。这样做的方法是使用int p = b & 0xFF
。
以下(我将再次使用数字200):
(负)字节值扩展为有符号整数,记住符号位:
11010000
变为11111111 11111111 11111111 11010000
通过执行二元AND运算符,0xFF
或00000000 00000000 00000000 11111111
对此值进行“屏蔽”:
11111111 11111111 11111111 11010000 & 00000000 00000000 00000000 11111111 = 00000000 00000000 00000000 11010000
此值与作为有符号整数的值200
相同。