弹跳城堡 HMAC SHA1
BouncyCastle HMAC SHA1
我有以下代码使用 BouncyCastle(dotnet 版本)从消息中获取 HMAC-SHA1。
我有这个小图书馆class:
public class HashingTools
{
static string hmacKey = "81310910a060c5705c1d3cedf370bcf9";
public static int HashSizeInBytes = 20;
static KeyParameter keyParameter = null;
private static HMac hmacInstance;
static HashingTools()
{
hmacInstance = new HMac(new Sha1Digest());
hmacInstance.Init(newKeyParameter(Encoding.UTF8.GetBytes(hmacKey)));
}
public static byte[] HashSha1(byte[] message)
{
byte[] result = new byte[hmacInstance.GetMacSize()];
hmacInstance.BlockUpdate(message, 0, message.Length);
hmacInstance.DoFinal(result, 0);
return result;
}
}
我有很多消息通过这种方法,都使用相同的密钥:hmacKey
,我想尽可能加快速度,并尽可能多地重复使用,仍然是关于安全参数(随机性、新鲜度...)。
如果我尝试重用或并行化 hmac
实例,我会在 Org.BouncyCastle.Crypto.Macs.Hmac.BlockUpdate
.
中得到一个 "array out of bounds" 异常
我创建了这个用于复制的单元测试(1 或 2 个并行哈希函数正常,100 个出错):
[Test]
public void TestBulkHashing()
{
var messages = new List<byte[]>();
foreach (var index in Enumerable.Range(0, 100))
{
var buffer = new byte[4096];
Random r = new Random();
r.NextBytes(buffer);
messages.Add(buffer);
}
Parallel.ForEach(messages, m =>
{
HashingTools.HashSha1(m);
});
}
正如@dlatikay 正确推测的那样,这是一个同步错误。 Bouncycastle 的 类 不是线程安全的,除非他们明确说明它是线程安全的。
如果您修改 HashSha1
方法以显式同步线程,您将不会得到异常:
public static byte[] HashSha1(byte[] message) {
byte[] result = new byte[hmacInstance.GetMacSize()];
lock(hmacInstance) {
hmacInstance.BlockUpdate(message, 0, message.Length);
hmacInstance.DoFinal(result, 0);
}
return result;
}
关于您关于优化的问题,Bouncycastle 已经预先计算了涉及密钥的计算部分。当您调用 DoFinal(...)
时,内部状态将重置为此预先计算的值,因此如果您使用相同的密钥,则无需为下一个 HMac 再次调用 Init()
。您的代码已经利用了这种优化,所以我认为您无能为力,除非您想编写自己的哈希代码。
我有以下代码使用 BouncyCastle(dotnet 版本)从消息中获取 HMAC-SHA1。
我有这个小图书馆class:
public class HashingTools
{
static string hmacKey = "81310910a060c5705c1d3cedf370bcf9";
public static int HashSizeInBytes = 20;
static KeyParameter keyParameter = null;
private static HMac hmacInstance;
static HashingTools()
{
hmacInstance = new HMac(new Sha1Digest());
hmacInstance.Init(newKeyParameter(Encoding.UTF8.GetBytes(hmacKey)));
}
public static byte[] HashSha1(byte[] message)
{
byte[] result = new byte[hmacInstance.GetMacSize()];
hmacInstance.BlockUpdate(message, 0, message.Length);
hmacInstance.DoFinal(result, 0);
return result;
}
}
我有很多消息通过这种方法,都使用相同的密钥:hmacKey
,我想尽可能加快速度,并尽可能多地重复使用,仍然是关于安全参数(随机性、新鲜度...)。
如果我尝试重用或并行化 hmac
实例,我会在 Org.BouncyCastle.Crypto.Macs.Hmac.BlockUpdate
.
我创建了这个用于复制的单元测试(1 或 2 个并行哈希函数正常,100 个出错):
[Test]
public void TestBulkHashing()
{
var messages = new List<byte[]>();
foreach (var index in Enumerable.Range(0, 100))
{
var buffer = new byte[4096];
Random r = new Random();
r.NextBytes(buffer);
messages.Add(buffer);
}
Parallel.ForEach(messages, m =>
{
HashingTools.HashSha1(m);
});
}
正如@dlatikay 正确推测的那样,这是一个同步错误。 Bouncycastle 的 类 不是线程安全的,除非他们明确说明它是线程安全的。
如果您修改 HashSha1
方法以显式同步线程,您将不会得到异常:
public static byte[] HashSha1(byte[] message) {
byte[] result = new byte[hmacInstance.GetMacSize()];
lock(hmacInstance) {
hmacInstance.BlockUpdate(message, 0, message.Length);
hmacInstance.DoFinal(result, 0);
}
return result;
}
关于您关于优化的问题,Bouncycastle 已经预先计算了涉及密钥的计算部分。当您调用 DoFinal(...)
时,内部状态将重置为此预先计算的值,因此如果您使用相同的密钥,则无需为下一个 HMac 再次调用 Init()
。您的代码已经利用了这种优化,所以我认为您无能为力,除非您想编写自己的哈希代码。