为什么在散列之前删除 java 字节数组中的前导全零字节
Why dropping leading all zeros byte in a java byte array before hashing
这个问题是关于在 java 中对字节数组进行哈希处理之前对字节数组执行的操作。
我试图理解为什么在多个 srp 加密库中,前导零字节(如果有一个)在被散列之前被删除。
例如:这是来自 Bouncy Castle
/**
* Return the passed in value as an unsigned byte array.
*
* @param value value to be converted.
* @return a byte array without a leading zero byte if present in the signed encoding.
*/
public static byte[] asUnsignedByteArray(int length, BigInteger value)
{
byte[] bytes = value.toByteArray();
if (bytes.length == length)
{
return bytes;
}
int start = bytes[0] == 0 ? 1 : 0;
int count = bytes.length - start;
if (count > length)
{
throw new IllegalArgumentException("standard length exceeded for value");
}
byte[] tmp = new byte[length];
System.arraycopy(bytes, start, tmp, tmp.length - count, count);
return tmp;
}
或者这是来自 nimbus SRP:
public static byte[] toUnsignedByteArray(final BigInteger bigInteger) {
byte[] bytes = bigInteger.toByteArray();
byte[] result = toUnsignedByteArray(bytes);
// remove leading zero if any
if (bytes[0] == 0) {
byte[] tmp = new byte[bytes.length - 1];
System.arraycopy(bytes, 1, tmp, 0, tmp.length);
return tmp;
}
return bytes;
}
买的例子基本上去掉了前导零。这些库中的方法调用 "toUnsignedByteArray",尽管我不明白为什么删除前导零会使字节数组无符号。 IE。它只删除零字节,然后下一个字节可能为负,即下一个字节成为最左边的字节(在 Big Indian 中)并且字节中最左边的位是符号位,可以根据字节设置或取消设置,所以如果我正确理解字节数组的结构,那么首先不应将这些方法调用到 "toUnsignedByteArray" 。然而,最重要的问题是为什么我们需要删除那个零字节以防它全为零
这是来自 srp rfc 5054 附录 A 的测试向量示例。我们从 A 和 B 计算 U。其中 B 的零字节恰好是二进制全零,即如果我们将 B 打印为字节数组我们将得到以下值
public static final B = new BigInteger("BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC996C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAEEB4012B7D7665238A8E3FB004B117B58", 16);
[0, -67, 12, 97, 81, 44, 105, 44, 12, -74, -48, 65, -6, 1, -69, 21,
45, 73, 22, -95, -25, 122, -12, 106, -31, 5, 57, 48, 17, -70, -13,
-119, 100, -36, 70, -96, 103, 13, -47, 37, -71, 90, -104, 22, 82, 35, 111, -103, -39, -74, -127, -53, -8, 120, 55, -20, -103, 108, 109, -96,
68, 83, 114, -122, 16, -48, -58, -35, -75, -117, 49, -120, -123, -41,
-40, 44, 127, -115, -21, 117, -50, 123, -44, -5, -86, 55, 8, -98, 111, -100, 96, 89, -13, -120, -125, -114, 122, 0, 3, 11, 51, 30, -73, 104, 64, -111, 4, 64, -79, -78, 122, -82, -82, -21, 64, 18, -73, -41, 102,
82, 56, -88, -29, -5, 0, 75, 17, 123, 88]
Byte Zero printed in binary: 00000000
现在我知道出于某种原因删除该字节很重要(虽然我不确定)我的意思是因为这些测试向量使用这两个库正确计算,所以应该正确编程,对吗?但是我不明白为什么我们需要删除前导零字节。它有什么问题。如果我删除前导 zeor 字节并尝试从没有前导零字节的字节数组创建另一个 BigInteger,那么在这种情况下我将得到一个完全不同的数字,甚至是负数。所以删除那个零字节对我来说没有任何影响。欢迎任何解释。
名称中的"unsigned"可能有点误导;不是丢弃 0 字节使它无符号,它只是假设 BigInteger
包含一个无符号数。
在这些情况下丢弃的 0 字节不会更改值,就像 01
或 001
与 1
.
的值相同一样
由于各种原因,删除零很重要:
- 不浪费 space 不必要的 0 字节。
- 在比较字节数组时使表示一致。
- (并且在您所指的上下文中最相关)前面带有额外 0 的字节数组的散列与没有额外 0 的字节数组的散列不同。散列函数毕竟不知道这是一个数字,在这种情况下 0 是无意义的。想象一下,如果这是一个文件,字节数
0:1:2:3
与字节数 1:2:3
的文件。您不会期望不同长度的文件的哈希值相同。
另请注意,是从开头还是结尾删除 0 字节取决于整数表示的 endianness。
更新:关于删除 0 字节的说明:
虽然从任何旧字节数组的开头或结尾删除 0 字节 会 更改值,在您所指的情况下,我们谈论的是整数的表示。如果 0 字节很重要,例如你想往返一些二进制数据,将二进制数据加载到 BigInteger
class 中是不合适的。我指的是我原来的例子,你不会认为 1
和 01
是不同的数字吧(尽管你会认为它们是不同的字符串)?
更新:关于字节序的说明:
整数在内存中可能有不同的表示方式。如果您看到数字 20
(普通十进制),您就会知道 2
指的是十进制数,但这只是约定俗成。我们可以将二十向后写为 02
,并将最大的单位放在数字的末尾。同样在计算机中,数字的顺序可以是我们平时熟悉的方式,也可以是"backwards"。鉴于此,不影响数字值的 0 可能位于字节数组的开头或结尾,我们必须知道在处理字节数组时字节应该以哪种方式循环"read".
这个问题是关于在 java 中对字节数组进行哈希处理之前对字节数组执行的操作。
我试图理解为什么在多个 srp 加密库中,前导零字节(如果有一个)在被散列之前被删除。
例如:这是来自 Bouncy Castle
/**
* Return the passed in value as an unsigned byte array.
*
* @param value value to be converted.
* @return a byte array without a leading zero byte if present in the signed encoding.
*/
public static byte[] asUnsignedByteArray(int length, BigInteger value)
{
byte[] bytes = value.toByteArray();
if (bytes.length == length)
{
return bytes;
}
int start = bytes[0] == 0 ? 1 : 0;
int count = bytes.length - start;
if (count > length)
{
throw new IllegalArgumentException("standard length exceeded for value");
}
byte[] tmp = new byte[length];
System.arraycopy(bytes, start, tmp, tmp.length - count, count);
return tmp;
}
或者这是来自 nimbus SRP:
public static byte[] toUnsignedByteArray(final BigInteger bigInteger) {
byte[] bytes = bigInteger.toByteArray();
byte[] result = toUnsignedByteArray(bytes);
// remove leading zero if any
if (bytes[0] == 0) {
byte[] tmp = new byte[bytes.length - 1];
System.arraycopy(bytes, 1, tmp, 0, tmp.length);
return tmp;
}
return bytes;
}
买的例子基本上去掉了前导零。这些库中的方法调用 "toUnsignedByteArray",尽管我不明白为什么删除前导零会使字节数组无符号。 IE。它只删除零字节,然后下一个字节可能为负,即下一个字节成为最左边的字节(在 Big Indian 中)并且字节中最左边的位是符号位,可以根据字节设置或取消设置,所以如果我正确理解字节数组的结构,那么首先不应将这些方法调用到 "toUnsignedByteArray" 。然而,最重要的问题是为什么我们需要删除那个零字节以防它全为零
这是来自 srp rfc 5054 附录 A 的测试向量示例。我们从 A 和 B 计算 U。其中 B 的零字节恰好是二进制全零,即如果我们将 B 打印为字节数组我们将得到以下值
public static final B = new BigInteger("BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC996C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAEEB4012B7D7665238A8E3FB004B117B58", 16);
[0, -67, 12, 97, 81, 44, 105, 44, 12, -74, -48, 65, -6, 1, -69, 21, 45, 73, 22, -95, -25, 122, -12, 106, -31, 5, 57, 48, 17, -70, -13, -119, 100, -36, 70, -96, 103, 13, -47, 37, -71, 90, -104, 22, 82, 35, 111, -103, -39, -74, -127, -53, -8, 120, 55, -20, -103, 108, 109, -96, 68, 83, 114, -122, 16, -48, -58, -35, -75, -117, 49, -120, -123, -41, -40, 44, 127, -115, -21, 117, -50, 123, -44, -5, -86, 55, 8, -98, 111, -100, 96, 89, -13, -120, -125, -114, 122, 0, 3, 11, 51, 30, -73, 104, 64, -111, 4, 64, -79, -78, 122, -82, -82, -21, 64, 18, -73, -41, 102, 82, 56, -88, -29, -5, 0, 75, 17, 123, 88]
Byte Zero printed in binary: 00000000
现在我知道出于某种原因删除该字节很重要(虽然我不确定)我的意思是因为这些测试向量使用这两个库正确计算,所以应该正确编程,对吗?但是我不明白为什么我们需要删除前导零字节。它有什么问题。如果我删除前导 zeor 字节并尝试从没有前导零字节的字节数组创建另一个 BigInteger,那么在这种情况下我将得到一个完全不同的数字,甚至是负数。所以删除那个零字节对我来说没有任何影响。欢迎任何解释。
名称中的"unsigned"可能有点误导;不是丢弃 0 字节使它无符号,它只是假设 BigInteger
包含一个无符号数。
在这些情况下丢弃的 0 字节不会更改值,就像 01
或 001
与 1
.
由于各种原因,删除零很重要:
- 不浪费 space 不必要的 0 字节。
- 在比较字节数组时使表示一致。
- (并且在您所指的上下文中最相关)前面带有额外 0 的字节数组的散列与没有额外 0 的字节数组的散列不同。散列函数毕竟不知道这是一个数字,在这种情况下 0 是无意义的。想象一下,如果这是一个文件,字节数
0:1:2:3
与字节数1:2:3
的文件。您不会期望不同长度的文件的哈希值相同。
另请注意,是从开头还是结尾删除 0 字节取决于整数表示的 endianness。
更新:关于删除 0 字节的说明:
虽然从任何旧字节数组的开头或结尾删除 0 字节 会 更改值,在您所指的情况下,我们谈论的是整数的表示。如果 0 字节很重要,例如你想往返一些二进制数据,将二进制数据加载到 BigInteger
class 中是不合适的。我指的是我原来的例子,你不会认为 1
和 01
是不同的数字吧(尽管你会认为它们是不同的字符串)?
更新:关于字节序的说明:
整数在内存中可能有不同的表示方式。如果您看到数字 20
(普通十进制),您就会知道 2
指的是十进制数,但这只是约定俗成。我们可以将二十向后写为 02
,并将最大的单位放在数字的末尾。同样在计算机中,数字的顺序可以是我们平时熟悉的方式,也可以是"backwards"。鉴于此,不影响数字值的 0 可能位于字节数组的开头或结尾,我们必须知道在处理字节数组时字节应该以哪种方式循环"read".