Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is it safe to use string hashcode as etag

Given a certain input parameter, for a rest api i want to use the hashcode as etag. What is the probability that the json response has changed and the hashcode will be the same?

Alternatively is there a better way to do this?

@GET
    public Response getConfigurationForView(@PathParam("in1") String in1, @Context Request request) throws Exception {
        String jsonResponse = getJsonResponse(in1);
        EntityTag etag = new EntityTag(Integer.toString(in1.hashCode()) + "-" + Integer.toString(jsonResponse.hashCode()));
        ResponseBuilder builder = request.evaluatePreconditions(etag);


         if(builder == null){
             builder = Response.ok(jsonResponse, MediaType.APPLICATION_JSON);
             builder.tag(etag);
         }

        return builder.build();
    }
like image 908
David Michael Gang Avatar asked Oct 11 '25 13:10

David Michael Gang


1 Answers

Given you only have 4 billion possible hash codes for the whole variety of strings, there's a decent chance you'll eventually encounter ETag collisions.

Looking at how String.hashCode() is implemented:

        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;

-- you can even come up with possible collisions yourself. For instance, "" (an empty string) and "\0" (the string containing only \0 character) will give you the same hashCode of 0.

I would suggest you use a SHA1 hash (or MD5, but see these notes on security and CPU running time first).

Provided you proceed with SHA1 hash, your code might look like this:

public static String calculateEtag(final String s) throws java.security.NoSuchAlgorithmException {
    final java.nio.ByteBuffer buf = java.nio.charset.StandardCharsets.UTF_8.encode(s);
    final java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA1");
    buf.mark();
    digest.update(buf);
    buf.reset();
    return String.format("W/\"%s\"", javax.xml.bind.DatatypeConverter.printHexBinary(digest.digest()));
}

This will produce the output identical of that of sha1sum utility. You could use BigInteger to convert a byte buffer to a hex string as well:

new BigInteger(1, digest.digest()).toString(16)

-- but javax.xml.bind.DatatypeConverter.printHexBinary() is several times faster.

like image 98
Bass Avatar answered Oct 14 '25 02:10

Bass



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!