Frage

Syncthing uses the following Go code to compute a "Node ID," a base32 encoded SHA256 hash of an SSL certificate:

func certID(bs []byte) string {
    hf := sha256.New()
    hf.Write(bs)
    id := hf.Sum(nil)
    return strings.Trim(base32.StdEncoding.EncodeToString(id), "=")
}

As far as I can tell, the certificate is just passed in as raw bytes:

 // ...
    remoteID := certID(certs[0].Raw)
 // ...

I have tried to replicate this in Java (I'm somewhat new to Java), using the following method:

public static String ComputeSTNodeID(Certificate cert) {
    MessageDigest md = MessageDigest.getInstance("SHA256");
    return BaseEncoding.base32().encode(md.digest(cert.getEncoded())).replaceAll("=", "");
}

(BaseEncoding is borrowed from Google's Guava library.)

For a given certificate, the calculations are different:

Go:   T2JOFPRO7UJB4YHXOSCY4U4YQEFLFI355JQKRD7ZB2ZLEPU6RD4Q
Java: HMKJKSJPB7CM54YHMYIFAN5F7MZAHOFXX4XG5SQWAZLY4I4ROJFA

What am I doing wrong? @fge and I have worked out that the .getEncoded() call is not returning the same thing as what is contained in the Go .Raw member.

War es hilfreich?

Lösung

That is not really a full answer but using Guava you can make your life easier by using a Hasher instead of MessageDigest.

Why? Because Hasher extends PrimitiveSink, which means you can create a Funnel for Certificate; you'll only have to change the Funnel to get that part right!

Illustration:

public enum CertificateFunnel
    implements Funnel<Certificate>
{
    INSTANCE
    {
        @Override
        public void funnel(final Certificate from, final PrimitiveSink into)
        {
            into.putBytes(from.getEncoded());
        }
    }
}

You would then have a private static final HashFunction SHA256:

private static final HashFunction SHA256 = Hashing.sha256();

And also a private static final BaseEncoding BASE32_NOPAD since instances of BaseEncoding are thread safe and immutable:

private static final BaseEncoding BASE32_NOPAD
    = BaseEncoding.base32().omitPadding(); // No need to strip `=`!

You would then feed the certificate with:

final Hasher hasher = SHA256.newHasher();

// Funnel the certificate...
hasher.putObject(certificate, CertificateFunnel.INSTANCE);

// Then encode
return BASE32_NOPAD.encode(hasher.hashCode().asBytes());

Just my .02 bitcoins.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top