RFC 4122 requires the use of MD5 oder SHA-1 to generate name-based UUIDs, prefering SHA-1 when possible. Since the standard has not been updated since more than a decade, more robust hash functions are not included in the standard. SHA-256 for example has a better resistance against preimage and collision attacks than SHA-1 and should retain these properties even after truncation. For that reason I developed the following class using SHA-256 to create the message digest, instead of MD5 or SHA-1.

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Objects;
import java.util.UUID;
 
/**
 * Class to create name-based UUIDs using SHA-256 as hashing function.
 * <p>A lot of code in here is taken from {@link UUID}.</p>
 */
public class UUIDSha256 {
 
    /**
     * Static factory to retrieve a name-based (hashing) {@link UUID} based on
     * the specified namespace and name.
     * <p>This method corresponds to {@link UUID#nameUUIDFromBytes(byte[])}</p>
     *
     * @param namespace namespace for the UUID
     * @param name byte array
     * @return A {@link UUID} generated from the specified namespace and name
     */
    public static UUID nameUUIDFromNamespaceAndBytes(UUID namespace, byte[] name) {
        Objects.requireNonNull(namespace, "namespace is null");
        Objects.requireNonNull(name, "name is null");
 
        MessageDigest md;
        try {
            md = MessageDigest.getInstance("SHA-256");
        } catch (NoSuchAlgorithmException nsae) {
            throw new InternalError("SHA-256 not supported");
        }
 
        md.update(toBytes(namespace));
        md.update(name);
        byte[] sha256Bytes = md.digest();
 
        sha256Bytes[6] &= 0x0f; /* clear version */
        sha256Bytes[6] |= 0x50; /* set to version 5 */
        sha256Bytes[8] &= 0x3f; /* clear variant */
        sha256Bytes[8] |= 0x80; /* set to IETF variant */
 
        return fromBytes(Arrays.copyOfRange(sha256Bytes, 0, 16));
    }
 
    private static UUID fromBytes(byte[] data) {
        long msb = 0;
        long lsb = 0;
 
        assert data.length == 16 : "data must be 16 bytes in length";
 
        for (int i = 0; i < 8; i++) {
            msb = (msb << 8) | (data[i] & 0xff);
        }
 
        for (int i = 8; i < 16; i++) {
            lsb = (lsb << 8) | (data[i] & 0xff);
        }
 
        return new UUID(msb, lsb);
    }
 
    private static byte[] toBytes(UUID uuid) {
        byte[] out = new byte[16];
 
        long msb = uuid.getMostSignificantBits();
        long lsb = uuid.getLeastSignificantBits();
 
        for (int i = 0; i < 8; i++) {
            out[i] = (byte) ((msb >> ((7 - i) * 8)) & 0xff);
        }
 
        for (int i = 8; i < 16; i++) {
            out[i] = (byte) ((lsb >> ((15 - i) * 8)) & 0xff);
        }
 
        return out;
    }
}