这个 MessageDigest 包装器线程安全吗?

Is this MessageDigest wrapper thread-safe?

我编写了自己的简化 MessageDigest 包装器,现在我想知道它是否线程安全。

public final class SimpleIMD implements ImmutableMessageDigest {
    private final MessageDigest md;

    public SimpleIMD(MessageDigest md) {
        this.md = this.cloneMessageDigest(md);
    }

    private MessageDigest cloneMessageDigest(MessageDigest original) {
        MessageDigest clone = null;
        try {
            clone = (MessageDigest) original.clone();
        } catch (CloneNotSupportedException cnse) {
            throw new RuntimeException(
                "Failed to instantiate a new SimpleImd instance.",
                cnse
            );
        } finally {
            return clone;
        }
    }

    @Override
    public byte[] digest() {
        return this.md.digest();
    }

    @Override
    public ImmutableMessageDigest update(byte[] arr, int offset, int len) {
        MessageDigest newMsgDigest = this.cloneMessageDigest(this.md);
        newMsgDigest.update(arr, offset, len);
        return new SimpleIMD(newMsgDigest);
    }
}

如我所料,我的代码不是线程安全的。

例如,如果 2 个线程共享同一个 SimpleIMD 对象,并且方法调用的时间顺序将如下所示:

  T1                 T2
  |                  |
update()             |
  |                  |
  |                digest()
  |                  |
  |                  |
  |                  |

那么不能保证 update() 会在 digest() 之前完成。

事实上,digest() 甚至可能在 update() 之前重置基础 MessageDigest 实例,并且 T1 将具有错误的哈希值。这个问题可以通过对新副本执行 digest() 来解决。

所以方法:

@Override
public byte[] digest() {
    return this.md.digest();
}

必须更改为:

@Override
public byte[] digest() {
    return this.cloneMessageDigest(this.md).digest();
}

更新

此处介绍的解决方案已纳入我编写的开源库 ImmutableMessageDigest that's part of Caesar