C# BouncyCastle HMAC SHA1

C# BouncyCastle HMAC SHA1,c#,bouncycastle,hmac,hmacsha1,C#,Bouncycastle,Hmac,Hmacsha1,我有以下代码使用BouncyCastle(dotnet版本)从消息中获取HMAC-SHA1 我有一个小型的图书馆课程: public class HashingTools { static string hmacKey = "81310910a060c5705c1d3cedf370bcf9"; public static int HashSizeInBytes = 20; static KeyParameter keyParameter = null; priva

我有以下代码使用BouncyCastle(dotnet版本)从消息中获取HMAC-SHA1

我有一个小型的图书馆课程:

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个出错):

[测试]
公共void TestBulkHashing()
{
var messages=新列表();
foreach(可枚举范围内的var指数(0,100))
{
var buffer=新字节[4096];
随机r=新随机();
r、 下字节(缓冲区);
消息。添加(缓冲区);
}
Parallel.ForEach(消息,m=>
{
HashingTools.HashSha1(m);
});
}

正如@dlatikay正确推测的那样,这是一个同步错误。Bouncycastle的类不是线程安全的,除非它们明确表示是线程安全的

如果修改
HashSha1
方法以显式同步线程,则不会出现异常:

公共静态字节[]HashSha1(字节[]消息){
字节[]结果=新字节[hmacInstance.GetMacSize()];
锁(HMA){
hmacInstance.BlockUpdate(消息,0,消息长度);
hmacInstance.DoFinal(结果为0);
}
返回结果;
}

至于您关于优化的问题,Bouncycastle已经预先计算了计算中涉及密钥的部分。调用
DoFinal(…)
时,内部状态将重置为此预先计算的值,因此如果使用相同的键,则无需再次调用下一个HMac的
Init()
。您的代码已经利用了这种优化,因此我认为除非您想编写自己的哈希代码,否则您可以做的事情不会太多。

无法复制,我也不例外。编辑您的问题以包含不起作用的代码和异常的完整堆栈跟踪。我已编辑问题以包含如何复制。仅关键字
static
的外观是有问题的。共享内部静态状态的东西正是线程安全或不安全的原因。某些链接可能指向以下位置:,-
System.Random
也可能不是线程安全的。
[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);
    });
}