证书的base32编码哈希不匹配

时间:2014-05-15 06:07:29

标签: java android hash certificate guava

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成员中包含的内容相同的内容。

1 个答案:

答案 0 :(得分:2)

这不是一个完整的答案,但使用番石榴,您可以使用Hasher代替MessageDigest,让您的生活更轻松。

为什么呢?由于Hasher扩展了PrimitiveSink,这意味着您可以为Funnel创建Certificate;您只需更改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比特币。