• 
      

    Add a registry for managing key types.

    Review Request #15183 — Created July 21, 2026 and updated

    Information

    cryptozoology
    master

    Reviewers

    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
    Add a registry for managing key types.
    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).
    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 …

    david david

    Do we not want to reexport KeyTypesRegistry as well?

    david david

    We should protect this with the registry's lock so we don't end up with issues across threads: with self._lock: for …

    david david

    This ends up caching None for invalid values, making it so a stream of Secret.decode() calls with random alg= values …

    david david

    Same here regarding self._lock and not caching invalid values. Perhaps we could extract this into a helper?

    david david

    Can we make this use the same typed signature as the base class?

    david david

    This reads a little odd. How about just "This clears the algorithm caches whenever an item is registered"?

    david david

    Can we make this use the same typed signature as the base class?

    david david

    Same here re: "This will be used"

    david david

    If we wrap the cache writes in with self._lock its less of an issue, but this is rebinding rather than …

    david david

    The actual implementation is named "KeyTypesRegistry" (with an s). The name here (and in all the test methods/docstrings) is incorrect. …

    david david

    Can we call registry.populate() here so that this matches more closely with test_get_for_keywrap_alg_uses_cache?

    david david

    Inside _get_or_add_cached we iterate through the registry in the cache miss path. If the registry hasn't populated yet it will …

    david david

    This isn't quite right, we're returning a key class, not an instance.

    david david
    david
    1. 
        
    2. Show all issues

      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.

      1. Let me think about that outside of this change. That's really more about the relationship between those classes, and probably should live there.

    3. cryptozoology/keys/__init__.py (Diff revision 1)
       
       
       
       
       
       
       
      Show all issues

      Do we not want to reexport KeyTypesRegistry as well?

      1. I don't see any reason to. It's not something a caller would use, just unit tests. We don't do this elsewhere.

    4. cryptozoology/keys/registry.py (Diff revision 1)
       
       
       
       
       
       
       
       
      Show all issues

      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
      
    5. cryptozoology/keys/registry.py (Diff revision 1)
       
       
      Show all issues

      This ends up caching None for invalid values, making it so a stream of Secret.decode() calls with random alg= values grows memory without bound.

      Can we only cache positive results?

      Same for the keywrap algorithm.

      1. A None result is a valid result for this function and should be cached. If this is called 10 times for the same unsupported algorithm, we want that None result instead of looping 10 times and performing regex matches or string parsing on the same thing each time. I can address the unbound growth issue.

    6. cryptozoology/keys/registry.py (Diff revision 1)
       
       
       
       
       
       
       
       
      Show all issues

      Same here regarding self._lock and not caching invalid values. Perhaps we could extract this into a helper?

      1. I thought about that, but it's two simple tight loops. I don't want to over-engineer this.

      2. Alright, there's going to be more engineering required for the unbound growth issue, so I guess I will do this in some form.

    7. cryptozoology/keys/registry.py (Diff revision 1)
       
       
      Show all issues

      Can we make this use the same typed signature as the base class?

      1. It's a callback handler. It only needs to accept what it needs to deal with. We use this pattern plenty, ignoring the arguments if we don't need them, so we don't have to micromanage the signature.

    8. cryptozoology/keys/registry.py (Diff revision 1)
       
       
       
      Show all issues

      This reads a little odd. How about just "This clears the algorithm caches whenever an item is registered"?

    9. cryptozoology/keys/registry.py (Diff revision 1)
       
       
      Show all issues

      Can we make this use the same typed signature as the base class?

    10. cryptozoology/keys/registry.py (Diff revision 1)
       
       
      Show all issues

      Same here re: "This will be used"

    11. cryptozoology/keys/registry.py (Diff revision 1)
       
       
       
      Show all issues

      If we wrap the cache writes in with self._lock its less of an issue, but this is rebinding rather than clearing. I think it would be better to use self._*_map.clear() here.

      1. We also use this to set the state initially. I could separate that out but I'm not sure we gain anything from this. Absolute worst-case here (if we didn't lock on iterate) is that we cache a thing that then quickly falls out of cache, or we put a value in cache that was just put in cache from another thread. And I think that's the same as calling .clear(). Not sure it's worth worrying about.

    12. cryptozoology/keys/tests/test_registry.py (Diff revision 1)
       
       
       
      Show all issues

      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 KeyTypeRegistry is perhaps the better one to use.

      1. I renamed it at one point. I'll rename it back.

    13. Show all issues

      Can we call registry.populate() here so that this matches more closely with test_get_for_keywrap_alg_uses_cache?

    14. 
        
    chipx86
    david
    1. 
        
    2. cryptozoology/keys/registry.py (Diff revision 2)
       
       
       
       
       
       
       
       
       
      Show all issues

      Inside _get_or_add_cached we iterate through the registry in the cache miss path. If the registry hasn't populated yet it will call populate(), 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

    3. cryptozoology/keys/registry.py (Diff revision 2)
       
       
       
      Show all issues

      This isn't quite right, we're returning a key class, not an instance.

    4. 
        
    chipx86
    Review request changed
    Change Summary:
    • Registries are now populated before locking when fetching by algorithm.
    • Fixed a return type in the docstring.
    Commits:
    Summary ID
    Add a registry for managing key types.
    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).
    5dfabcea925bf7710f2d5ee48fc40a167ed0f22f
    Add a registry for managing key types.
    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).
    a23ed43afbc580db35b61914181269dfb0c49a85

    Checks run (2 succeeded)

    flake8 passed.
    JSHint passed.
    david
    1. Ship It!
    2.