Add a registry for managing key types.
Review Request #15183 — Created July 21, 2026 and updated
This introduces
KeyTypesRegistry, which tracks all key types supported
by Cryptozoology. This provides access to keys by key type ID and by
encryption or keywrap algorithm.While this only includes support for AES and EC keys right now, it would
allow callers to provide or override key types as needed.The existing call sites that hard-code knowledge of key types now make
use of the registry to fetch keys by ID or algorithm, except where
appropriate (e.g., if explicitly an AES key needs to be created).
Unit tests pass.
| Summary | ID |
|---|---|
| a23ed43afbc580db35b61914181269dfb0c49a85 |
| Description | From | Last Updated |
|---|---|---|
|
Do we want to document somewhere that get_key_type('ec') resolves only to the private key class? It feels a little confusing … |
|
|
|
Do we not want to reexport KeyTypesRegistry as well? |
|
|
|
We should protect this with the registry's lock so we don't end up with issues across threads: with self._lock: for … |
|
|
|
This ends up caching None for invalid values, making it so a stream of Secret.decode() calls with random alg= values … |
|
|
|
Same here regarding self._lock and not caching invalid values. Perhaps we could extract this into a helper? |
|
|
|
Can we make this use the same typed signature as the base class? |
|
|
|
This reads a little odd. How about just "This clears the algorithm caches whenever an item is registered"? |
|
|
|
Can we make this use the same typed signature as the base class? |
|
|
|
Same here re: "This will be used" |
|
|
|
If we wrap the cache writes in with self._lock its less of an issue, but this is rebinding rather than … |
|
|
|
The actual implementation is named "KeyTypesRegistry" (with an s). The name here (and in all the test methods/docstrings) is incorrect. … |
|
|
|
Can we call registry.populate() here so that this matches more closely with test_get_for_keywrap_alg_uses_cache? |
|
|
|
Inside _get_or_add_cached we iterate through the registry in the cache miss path. If the registry hasn't populated yet it will … |
|
|
|
This isn't quite right, we're returning a key class, not an instance. |
|
-
-
Do we want to document somewhere that
get_key_type('ec')resolves only to the private key class? It feels a little confusing that we have separate public and private classes but only the private one is registered. -
-
We should protect this with the registry's lock so we don't end up with issues across threads:
with self._lock: for key_cls in self: ... self._enc_key_cache_map[alg] = key_cls -
This ends up caching
Nonefor invalid values, making it so a stream ofSecret.decode()calls with randomalg=values grows memory without bound.Can we only cache positive results?
Same for the keywrap algorithm.
-
Same here regarding
self._lockand not caching invalid values. Perhaps we could extract this into a helper? -
-
This reads a little odd. How about just "This clears the algorithm caches whenever an item is registered"?
-
-
-
If we wrap the cache writes in
with self._lockits less of an issue, but this is rebinding rather than clearing. I think it would be better to useself._*_map.clear()here. -
The actual implementation is named "KeyTypesRegistry" (with an s). The name here (and in all the test methods/docstrings) is incorrect.
That said, all of our other registries are named in the singular, so
KeyTypeRegistryis perhaps the better one to use. -
Can we call
registry.populate()here so that this matches more closely withtest_get_for_keywrap_alg_uses_cache?
- Change Summary:
-
- Renamed
KeyTypesRegistrytoKeyTypeRegistry(and same for the singleton). - The algorithm lookup caches now employ a LRU, and access is managed by a wrapper function.
- Made it clear that the arguments going to the registry hooks are unused.
- Renamed
- Commits:
-
Summary ID 908e102286672e8dda1fcd967449e9c176c4e818 5dfabcea925bf7710f2d5ee48fc40a167ed0f22f
Checks run (2 succeeded)
-
-
Inside
_get_or_add_cachedwe iterate through the registry in the cache miss path. If the registry hasn't populated yet it will callpopulate(), which triggers a reset of the caches. This means the active cache would be different than the one bound inside the parameter here.We should probably do:
self.populate() # Ensure defaults have been added. with self._lock: return self._get_or_add_cached(...)Some for
get_for_keywrap_alg -
- Change Summary:
-
- Registries are now populated before locking when fetching by algorithm.
- Fixed a return type in the docstring.
- Commits:
-
Summary ID 5dfabcea925bf7710f2d5ee48fc40a167ed0f22f a23ed43afbc580db35b61914181269dfb0c49a85