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

Implement hash and HMAC stream one shots #63757

Merged
merged 11 commits into from
Jan 23, 2022

Conversation

vcsjones
Copy link
Member

This implements hashing and HMAC statics for streams. Additionally,
"LiteHmac" and "LiteHash" were introduced. The existing HMAC and hash
provider functionality do some bookkeeping we don't need for resetting.
Since we do not need to use these hash handles after the digest has
been finalized, resetting is unnecessary work. For HMAC, that also means
keeping a copy of the key around for some implementations which we don't
need to do.

The LiteHash and LiteHmac types are implemented as structs with a common
interface. To avoid boxing, generics are used and constrained to the interface
where possible.

The Browser implementation just defers to the existing HashDispenser rather
than do anything novel.

Closes #62489.

This implements hashing and HMAC statics for streams. Additionally,
"LiteHmac" and "LiteHash" were introduced. The existing HMAC and hash
provider functionality do some bookkeeping we don't need for resetting.
Since we do not need to use these hash handles after the digest has
been finalized, resetting is unnecessary work. For HMAC, that also means
keeping a copy of the key around for some implementations which we don't
need to do.

The LiteHash and LiteHmac types are implemented as structs with a common
interface. To avoid boxing, generics are used and constrained to the interface
where possible.

The Browser implementation just defers to the existing HashDispenser rather
than do anything novel.
@dotnet-issue-labeler
Copy link

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost ghost added the community-contribution Indicates that the PR has been added by a community member label Jan 13, 2022
@ghost
Copy link

ghost commented Jan 13, 2022

Tagging subscribers to this area: @dotnet/area-system-security, @vcsjones, @krwq
See info in area-owners.md if you want to be subscribed.

Issue Details

This implements hashing and HMAC statics for streams. Additionally,
"LiteHmac" and "LiteHash" were introduced. The existing HMAC and hash
provider functionality do some bookkeeping we don't need for resetting.
Since we do not need to use these hash handles after the digest has
been finalized, resetting is unnecessary work. For HMAC, that also means
keeping a copy of the key around for some implementations which we don't
need to do.

The LiteHash and LiteHmac types are implemented as structs with a common
interface. To avoid boxing, generics are used and constrained to the interface
where possible.

The Browser implementation just defers to the existing HashDispenser rather
than do anything novel.

Closes #62489.

Author: vcsjones
Assignees: -
Labels:

area-System.Security, new-api-needs-documentation

Milestone: -

@vcsjones
Copy link
Member Author

Draft to get feedback from CI, and this is going to conflict with #63685. That should be merged first and I will resolve conflicts.

@vcsjones
Copy link
Member Author

This does not implement any shortcuts for some streams. We could possibly do this for MemoryStream (TryGetBuffer) and UnmanagedMemoryStream (PositionPointer). That can be done in a follow-up PR rather than make this PR bigger.

- Throw exceptions synchronously.
- Dispose of hash even if CryptoPool rent/return fails.
@vcsjones vcsjones force-pushed the hash-stream-oneshot-attempt-2 branch from 277d7a3 to d2720ee Compare January 13, 2022 20:49
}

/// This takes ownership of the hash parameter and disposes of it when done.
private static int ProcessStream<T>(T hash, Stream source, Span<byte> destination) where T : ILiteHash
Copy link
Contributor

Choose a reason for hiding this comment

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

I've done something similar (in readonly struct + generic constrained to interface) in a library I contribute to and while it works, any method called on that interface will force a defensive copy, since the compiler is not able to recognize that the struct method itself is readonly. I think it only sees the interface and thus decides on a defensive copy. I'm also not sure anymore whether without the in modifier as you have here, the compiler is able to figure it out properly or not.

Based on the size of the structs used, I assume it's not as relevant here, just wanted to mention it.

@vcsjones vcsjones marked this pull request as ready for review January 13, 2022 23:27
* OpenSsl / Android can wrap.
* Apple can wrap.
* Windows should not wrap. The HashProviderCng is somewhat specialized in its ability to reset. It did up-front check to determine if the platform supported reusable hash providers, and further had a single implementation for HMAC and Digests. The current Lite hash design requires that they remain separate types.
@vcsjones vcsjones requested a review from bartonjs January 21, 2022 21:53
@bartonjs bartonjs merged commit 1f2116c into dotnet:main Jan 23, 2022
@vcsjones vcsjones deleted the hash-stream-oneshot-attempt-2 branch January 24, 2022 02:27
@ghost ghost locked as resolved and limited conversation to collaborators Feb 23, 2022
@bartonjs bartonjs added the needs-further-triage Issue has been initially triaged, but needs deeper consideration or reconsideration label Aug 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Security community-contribution Indicates that the PR has been added by a community member needs-further-triage Issue has been initially triaged, but needs deeper consideration or reconsideration new-api-needs-documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[API Proposal]: One shot hashing of Stream
4 participants