Skip to content

User/khangnguyen/mscrypto traits - #106

Draft
Khang (nnmkhang) wants to merge 3 commits into
release/0.6.0from
user/khangnguyen/mscrypto-traits
Draft

User/khangnguyen/mscrypto traits#106
Khang (nnmkhang) wants to merge 3 commits into
release/0.6.0from
user/khangnguyen/mscrypto-traits

Conversation

@nnmkhang

Copy link
Copy Markdown
Contributor

Description of Changes:

Breaking Changes if any:

✅ Admin Checklist

  • Review the PR description and ensure all necessary details are included.
  • Update/add unit tests for changed code.
  • Update/add documentation for new or changed APIs.
  • Run cargo test --all-features on Windows and WSL.

Check the Developer Guidelines in DEVELOPER.md for more info.

@nnmkhang

Copy link
Copy Markdown
Contributor Author

Hey Sam, large PR so some notes that might help:

This is the order I think you should look:

  1. Contract for the traits from mscrypto. Specifically at proivder.rs, this is what bcrypt and symcrypt have to do in order to be used as a provider. The distinction here is that this is an owned object thats pulled in as a dependency rather than a feature. This solves most of the cargo clobbering issues that we were worried about with the feature design.
  2. Sha3 feature in the mscrypto/cargo.toml this feature enables/disables sha3, we will also do the same for each PQC algorithm as well.
  3. mscrypto-symcrypt, this will be the most familiar for both for both of us, I'm just fulfilling the contract from the traits defined in step 1.
  4. mscrypto-bcrypt, this is the tricker part because of the bcrypt APIs, we check if the sha3 handle is available via sha3_available. This is used in the lib.rs for mscrypto-bcrypt to probe during build as well.

I will leave other notes inline at the call sites.

I also made a small sample program that shows how the provider would be chosen etc.

RE: the discussion on Sha3. wondering your thoughts, It might just be easier to have SHAX return a ?, its a bit ugly, but makes the maintenance slightly easier for us. I am still on the fence about this tbh.

// windows-sys exposes the SHA-2 algorithm pseudo-handles but not the SHA-3 ones, so
// define them the same way it defines its own (a BCRYPT_ALG_HANDLE built from the value
// in the bcrypt pseudo-handle table). SHA-3 pseudo-handles exist on Windows 11 24H2 and later.
#[cfg(feature = "sha3")]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will switch these once they land in windows.rs

}

impl HashOps for BcryptHasher {
fn update(&mut self, data: &[u8]) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this over-engineered? I dont think anyone is going to ever hash a big file like this in one shot

BcryptHasher::new(alg, len)
}

fn digest(&self, algorithm: BaseHashAlgorithm, data: &[u8]) -> Digest {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could one shot here with the bcrypt API, but see the other note about large hashes


/// Panics on a non-success `NTSTATUS`. Used on the infallible SHA-2 path (and once
/// SHA-3 is running), where a failure is catastrophic and cannot be reported.
fn expect_success(call: &str, status: NTSTATUS) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on this panic idea. I assume that any error (aside from unavailable for sha3) would be catastrophic enough to panic anyways. In my mind there are few ways a hash can error out


/// Probes SHA-3 availability, then verifies the require-list. SHA-2 needs no
/// setup (pseudo-handles), so it never fails here.
pub fn build(self) -> Result<BcryptProvider, ProviderBuildError> {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where we would error if SHA3 is not available

}
}

fn backend_info() -> BackendInfo {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will try to find a way to use bcrypt / windows version number as a pseudo version

@nnmkhang Khang (nnmkhang) Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now looking at it, might make sense for the version to just be a string, then we can do checks per provider rather than forcing bcrypt into the symcrypt semver semantics.

// first use, which aborts on a mismatch, so there is no recoverable failure to
// report today. A graceful module-init entry point will surface an incompatible
// module here as `ProviderBuildError::Backend { backend, operation }`.
fn initialize_module() -> Result<(), ProviderBuildError> {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will replace with SymCryptModuleInitEX so we can probe during build and graceful error on old versions of SymCrypt.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will only support new versions of symcrypt.dll for this crate

@@ -0,0 +1,19 @@
// Records how symcrypt-sys is linked so the provider can report it through

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WIP

Comment thread mscrypto/src/hash.rs
/// visibility. Ordinary callers receive a `Digest` from `Hash::digest` /
/// `HashOps::finalize` and read it via `as_bytes` / `as_ref`.
#[doc(hidden)]
pub mod provider {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is separate since every API needs to be public for the trait to work. However, this is an implementation detail for the provider and should not be exposed to the caller. We can't physically stop them from using this. but hiding it like this from the docs is the best work around imo.

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

Successfully merging this pull request may close these issues.

1 participant