跳到主要内容

Identifiers

In this document, we will talk about how CherryGrove manages arbitrary identifiers with some surprising security flaws and how we fix them.

General: The Way to Arbitrariness

It's namespaces. CherryGrove ensures every mod has its own namespace, or it will refuse to create world / open world.

Like Minecraft, CherryGrove uses namespace:identifier format. Intrinsic identifiers have an empty namespace, like :BlockRenderComp and :item.

Components

Components are the basic building blocks of CherryGrove. They are the terminal storage division of everything.

However, because components need to be a key in the storage, we need a fixed length for the identifier. So we use a hash of the identifier as the key. The hash is a 64-bit value and have a very low chance of natural collision. The bigger problem is that our source code is publicly available, any pack creator can know a known component's hash and brute-force through their own namespace to find a collision to gain complete access to the storage. What's worse, we allow registering components on world startup, so they can even use local GPU to brute-force and target every component in the world.

There are two approaches to solve this problem: the first one is to hide details of the hash result by API abstraction, so that the pack won't know it; the second one is to use a world-specific key (salt) to hash the identifier and make it infeasibly long that the pack creator can't brute-force it. We choose both of them because we want to be secure and also want to eliminate natual collisions using the second way. If we find a hash collision, we can simply change the key. When we finished building the hash map, we will store the key in the storage. The key is 128-bit long and is generated by a cryptographically secure random number generator. No one can brute-force it in a reasonable time.