Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Abstract Hkdf and HkdfExtract over hmac::Mac #80

Open
ia0 opened this issue May 17, 2023 · 7 comments
Open

Abstract Hkdf and HkdfExtract over hmac::Mac #80

ia0 opened this issue May 17, 2023 · 7 comments

Comments

@ia0
Copy link

ia0 commented May 17, 2023

I might be missing something about the rational behind the HmacImpl sealed trait (like some implicit invariant), but I'm wondering why Hkdf and HkdfExtract are not parametrized by hmac::Mac instead. This trait already provides OutputSizeUser.

This would be useful when someone has both a Digest and a Mac hardware implementation and would like to compute HKDF using that Mac hardware implementation instead of using the SimpleHmac software implementation on top of the Digest hardware implementation.

@tarcieri
Copy link
Member

Sounds good to me. It would be nice to be able to support hardware accelerators.

@newpavlov
Copy link
Member

Note that HKDF is defined in terms of HMAC. So I don't think it will be correct to use the Mac trait here. At the very least, we would need a trait for a MAC function which can be initialized with keys of any length. We also use the sealed trait to hide these unwieldy bounds, but it should be solved in future releases (see RustCrypto/MACs#104). Right now we rely on block-level API in our implementation to reduce size of the Hkdf struct, to support slice-based hardware implementations we would need a bit of redesign.

AFAIK HMAC is usually supported in HSM-like hardware to protect keys from leaking, not for efficiency sake. Can you provide an example of hardware which you would like to target?

@ia0
Copy link
Author

ia0 commented May 21, 2023

Good point, an HmacMarker would be needed to replace the sealed trait (similar to the existing HashMarker and MacMarker), or the sealed trait could be renamed and exposed.

I'm not following the block-level API comment. The code only seems to use slices. However something to note is that the current implementation optimizes by reusing the core. An implementation that doesn't permit this (hardware implementations usually don't) would just define the core to be the pseudo random key and not precompute anything.

I sadly cannot provide an example hardware. But yes this is not about performance.

(I'm currently on vacations for 3 weeks so might not be able to reply until then.)

@tarcieri
Copy link
Member

tarcieri commented May 21, 2023

AFAIK HMAC is usually supported in HSM-like hardware to protect keys from leaking, not for efficiency sake.

When I say "cryptographic accelerator" I mean TPM/SEP-like cryptographic coprocessor, and yes one of its main purposes of the kind I have in mind is to airgap and provide access control around keys including preventing exfiltration of the raw key material, but also such coprocessors include fixed functions of various cryptographic algorithms that run faster than the software equivalent on an MCU, so it's a little of both. I have one device that works this way with a baked-in device unique hardware key, however we did not wrap the HMAC functionality it provides, but instead we wrapped the device unique keyed AES functionality and use that to store the encryption of the base derivation key which we use to initialize HKDF, which works too.

But also, I maintain crates like yubikey and yubihsm which also provide hardware-backed HMAC, though these do not provide a trait-based API like we're discussing. FWIW here's an example of the current HMAC-based API:

https://docs.rs/yubihsm/latest/yubihsm/client/struct.Client.html#method.sign_hmac

It would need a sort of proxy type which knows the key ID a priori to implement a Mac-like API.

At the very least, we would need a trait for a MAC function which can be initialized with keys of any length.

Well it'd be really nice to completely decouple KeyInit and Mac so the latter can be used with ^^^ devices which don't accept a raw key at all, but rather a "handle" to a key stored in hardware.

@newpavlov
Copy link
Member

@ia0

I'm not following the block-level API comment.

See how the Hkdf struct is defined. It uses I::Core, which does have any internal buffers. In the case of hardware-based implementation we would need to use some kind of handle there.

@tarcieri

FWIW here's an example of the current HMAC-based API:

Note that for HKDF we need an update-based API. If YubiHSM provides only whole message signing API, then a wrapper would need to assemble a full message on heap, which will be somewhat inefficient.

@ia0
Copy link
Author

ia0 commented May 22, 2023

See how the Hkdf struct is defined. It uses I::Core, which does have any internal buffers.

It's probably simpler if I write a PR when I'm back in 3 weeks. There looks like there is a misunderstanding on what is being achieved here, since your comments don't seem to reply to what I say. Code is probably easier to understand.

ia0 added a commit to ia0/KDFs that referenced this issue Jun 29, 2023
@ia0
Copy link
Author

ia0 commented Jun 29, 2023

Sorry for the very long delay, but I finally got time to get to this. I've created #82 to show an example of what I mean. Here are the main points:

  • [library] Expose the sealed trait as HmacImpl removing one hop (this is just for illustration, of course documentation and other things need to be addressed)
  • [test] I chose as example a hardware that can run a single HMAC instance which is what I have
  • Note that the current HMAC (and hash) APIs don't support errors which is not great when implementing them with hardware. Hardware can always fail in particular when it has security protection and detects glitch attempts (changes in temperature or voltage for example). But I have an idea to work around this limitation: Add error support when RustCrypto doesn't google/wasefire#176

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants