Syncthing使用以下 Go 代码计算“节点 ID”,即 SSL 证书的 base32 编码 SHA256 哈希值:
func certID(bs []byte) string {
hf := sha256.New()
hf.Write(bs)
id := hf.Sum(nil)
return strings.Trim(base32.StdEncoding.EncodeToString(id), "=")
}
据我所知,证书是 just passed in作为原始字节:
// ...
remoteID := certID(certs[0].Raw)
// ...
我尝试使用以下方法在 Java 中复制它(我对 Java 有点陌生):
public static String ComputeSTNodeID(Certificate cert) {
MessageDigest md = MessageDigest.getInstance("SHA256");
return BaseEncoding.base32().encode(md.digest(cert.getEncoded())).replaceAll("=", "");
}
(BaseEncoding
是从 Google 的 Guava 库中借用的。)
对于给定的证书,计算是不同的:
Go: T2JOFPRO7UJB4YHXOSCY4U4YQEFLFI355JQKRD7ZB2ZLEPU6RD4Q
Java: HMKJKSJPB7CM54YHMYIFAN5F7MZAHOFXX4XG5SQWAZLY4I4ROJFA
我做错了什么? @fge 和我发现 .getEncoded()
调用返回的内容与 Go .Raw
成员中包含的内容不同。
最佳答案
这并不是一个完整的答案,但使用 Guava 可以让您的生活更轻松,方法是使用 Hasher
而不是 MessageDigest
。
为什么?因为Hasher
扩展了PrimitiveSink
,这意味着你可以为Certificate
创建一个Funnel
;您只需更改 Funnel
即可使该部分正确!
插图:
public enum CertificateFunnel
implements Funnel<Certificate>
{
INSTANCE
{
@Override
public void funnel(final Certificate from, final PrimitiveSink into)
{
into.putBytes(from.getEncoded());
}
}
}
然后您将拥有一个private static final HashFunction SHA256
:
private static final HashFunction SHA256 = Hashing.sha256();
还有一个 private static final BaseEncoding BASE32_NOPAD
因为 BaseEncoding
的实例是线程安全且不可变的:
private static final BaseEncoding BASE32_NOPAD
= BaseEncoding.base32().omitPadding(); // No need to strip `=`!
然后您将向证书提供:
final Hasher hasher = SHA256.newHasher();
// Funnel the certificate...
hasher.putObject(certificate, CertificateFunnel.INSTANCE);
// Then encode
return BASE32_NOPAD.encode(hasher.hashCode().asBytes());
只是我的 .02 比特币。
关于java - 证书的 base32 编码散列不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23670452/