我将数千行加密C#函数移植到Java项目中。 C#代码广泛使用无符号值和按位运算。
我知道必要的Java解决方案来支持无符号值。但是,如果有无符号32位和64位整数的实现,我可以放入我的代码中会更方便。请链接到这样的图书馆。
快速谷歌查询揭示了商业应用程序中的几个:
答案 0 :(得分:2)
这是一种语言功能,而不是库功能,因此除非您更改语言本身,否则无法扩展Java以支持此功能,在这种情况下,您需要创建自己的编译器。
但是,如果您需要无符号右移,Java支持>>>
运算符,该运算符类似于>>
运算符,用于无符号类型。
但是,您可以使用签名类型制作自己的方法来执行算术,就像它们无符号一样;这应该有用,例如:
static int multiplyUnsigned(int a, int b)
{
final bool highBitA = a < 0, highBitB = b < 0;
final long a2 = a & ~(1 << 31), b2 = b & ~(1 << 31);
final long result = (highBitA ? a2 | (1 << 31) : a2)
* (highBitB ? b2 | (1 << 31) : b2);
return (int)result;
}
编辑:
感谢@ Ben的评论,我们可以简化这一点:
static int multiplyUnsigned(int a, int b)
{
final long mask = (1L << 32) - 1;
return (int)((a & mask) * (b & mask));
}
但这两种方法都不适用于long
类型。在这种情况下,您必须转换为double
,否定,乘以及再次将其强制转换,这可能会导致任何和所有优化。
答案 1 :(得分:2)
当使用两个补码表示法时,有符号和无符号整数的运算大多相同,这就是Java所做的。这意味着,如果您有两个32位字a
和b
并且想要计算它们的总和a+b
,那么无论您是否考虑,相同的内部操作都将产生正确的答案单词为签名或未签名。这适用于加法,减法和乘法。
必须符号标识的操作包括:
>>>
”运算符。long
类型(“x & 0xFFFFFFFFL
”执行“无符号转换”技巧)。比较:如果您想将a
与b
比较为两个32位无符号字词,那么您有两个标准习语:
if ((a + Integer.MIN_VALUE) < (b + Integer.MIN_VALUE)) { ... }
if ((a & 0xFFFFFFFFL) < (b & 0xFFFFFFFFL)) { ... }
知道,签名的Java类型对加密代码来说并不是一件容易的事。我已经在Java中实现了许多加密原语,只要您了解自己正在编写的内容,签名类型就不是问题。例如,看看sphlib:这是一个开源库,它在C和Java中实现了许多加密哈希函数。 Java代码非常无缝地使用Java的签名类型(int
,long
...),它只是有效。
Java没有运算符重载,因此获取无符号类型的Java“解决方案”将涉及自定义类(例如您链接到的UInt64
类),这将意味着大量的性能损失。你真的不想这样做。
理论上,可以使用无符号类型定义类似Java的语言,并实现一个为JVM生成字节码的编译器(内部使用我在上面详细说明的移位,分割和比较的技巧)。我不知道有任何可用的工具吗?并且,正如我上面所说,Java的签名类型适用于加密代码(换句话说,如果你遇到这种签名类型的问题,那么我敢说你不太了解安全地实现加密代码,你应该避免这样做;相反,使用现有的开源库。)