class KeyUtils {

    public static String truncateKey(String key) {
        byte[] keyBytes = key.getBytes(Charsets.UTF_8);

        if (keyBytes.length < MAX_KEY_BYTES || (keyBytes.length == MAX_KEY_BYTES && keyBytes[keyBytes.length - 1] != LAST_HASH_CHAR)) {
            // Key is short enough
            // If the key ends in equal sign, it could conflict with a truncated/hashed key, so
            // truncate and hash it
            return key;
        }

        // Generate hash of original, full key
        byte[] keyHash = generateKeyHash(keyBytes);
        assert keyHash.length == HASH_LENGTH;
        assert keyHash[keyHash.length - 1] == LAST_HASH_CHAR;

        // Overwrite ending partial character with single byte chars
        // This is not strictly required, but keeps the key valid UTF-8
        int lastCharIndex = KEY_TRUNCATE_BYTES - 1;

        while ((keyBytes[lastCharIndex] & 0xC0) == 0x80) {
            lastCharIndex -= 1;
        }

        if (utf8CharLen(keyBytes[lastCharIndex]) > (KEY_TRUNCATE_BYTES - lastCharIndex)) {
            while (lastCharIndex < KEY_TRUNCATE_BYTES) {
                keyBytes[lastCharIndex++] = '+';
            }
        }

        // Append key hash
        System.arraycopy(keyHash, 0, keyBytes, KEY_TRUNCATE_BYTES, keyHash.length);
        return new String(keyBytes, 0, MAX_KEY_BYTES, Charsets.UTF_8);
    }

}