-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Enable Rfc2898DeriveBytes on Browser WASM #71768
Conversation
Note regarding the 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. |
Tagging subscribers to this area: @dotnet/area-system-security, @vcsjones Issue DetailsMarks the APIs as supported on Browser, and enables Rfc2898 tests on Browser WASM. Contributes to #40074 (In draft until #71693 is merged, since this is built on top of that PR.)
|
Tagging subscribers to 'arch-wasm': @lewing Issue DetailsMarks the APIs as supported on Browser, and enables Rfc2898 tests on Browser WASM. Contributes to #40074 (In draft until #71693 is merged, since this is built on top of that PR.)
|
src/libraries/Common/src/System/Security/Cryptography/HashOneShotHelpers.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/System/Security/Cryptography/PasswordBasedEncryption.cs
Outdated
Show resolved
Hide resolved
...em.Security.Cryptography/src/System/Security/Cryptography/HMACHashProvider.Browser.Native.cs
Outdated
Show resolved
Hide resolved
...ystem.Security.Cryptography/src/System/Security/Cryptography/Pbkdf2Implementation.Browser.cs
Outdated
Show resolved
Hide resolved
...tem.Security.Cryptography/src/System/Security/Cryptography/SHAHashProvider.Browser.Native.cs
Outdated
Show resolved
Hide resolved
Marks the APIs as supported on Browser, and enables Rfc2898 tests on Browser WASM. Use SubtleCrypto deriveBits API to implement one shot Pbkdf2. Contributes to dotnet#40074
{ | ||
using (Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes( | ||
password.ToArray(), | ||
salt.ToArray(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no way to stay in the span universe all the way down? Are we accepting arrays from public entrypoints, passing them around as span, and then ToArray'ing here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's possible but we've avoided optimizing the non-one-shot implementation of PBKDF2 when we've talked about it in the past.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that this is the way the existing "mobile" platforms are implementing this functionality:
Lines 27 to 36 in 6a02d5d
using (Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes( | |
password.ToArray(), | |
salt.ToArray(), | |
iterations, | |
hashAlgorithmName, | |
clearPassword: true)) | |
{ | |
byte[] result = deriveBytes.GetBytes(destination.Length); | |
result.AsSpan().CopyTo(destination); | |
} |
which is used by Android and non-macOS AppleCrypto (iOS, tvOS, etc.).
There's no way to stay in the span universe all the way down?
Not without some decent refactoring to Rfc2898DeriveBytes
in order to make the managed algorithm completely "one shot", and then build the instance based Rfc2898DeriveBytes
methods on top of it.
Are we accepting arrays from public entrypoints, passing them around as span, and then ToArray'ing here?
In one overload, yes, and in most overloads no. This method is called from these public end-points:
runtime/src/libraries/System.Security.Cryptography/ref/System.Security.Cryptography.cs
Lines 1734 to 1739 in 6a02d5d
public static byte[] Pbkdf2(byte[] password, byte[] salt, int iterations, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, int outputLength) { throw null; } | |
public static byte[] Pbkdf2(System.ReadOnlySpan<byte> password, System.ReadOnlySpan<byte> salt, int iterations, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, int outputLength) { throw null; } | |
public static void Pbkdf2(System.ReadOnlySpan<byte> password, System.ReadOnlySpan<byte> salt, System.Span<byte> destination, int iterations, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { } | |
public static byte[] Pbkdf2(System.ReadOnlySpan<char> password, System.ReadOnlySpan<byte> salt, int iterations, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, int outputLength) { throw null; } | |
public static void Pbkdf2(System.ReadOnlySpan<char> password, System.ReadOnlySpan<byte> salt, System.Span<byte> destination, int iterations, System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { } | |
public static byte[] Pbkdf2(string password, byte[] salt, int iterations, System.Security.Cryptography.HashAlgorithmName hashAlgorithm, int outputLength) { throw null; } |
Only the top overload is taking 2 byte[]
s, passing them through as spans, and then ToArray'ing here. The bottom overload takes a string, which turns into UTF8 bytes in either a rented array or stackalloc'd span, and then passed in here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be simpler to implement a one shot in managed code with IncrementalHash instead of trying to get the streaming PBKDF2 to allocate less. I have a branch with this. Happy to upstream it as a follow up to this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a branch with this. Happy to upstream it as a follow up to this.
I think that would be great!
@@ -256,6 +256,24 @@ async function sign(type, key, data) { | |||
return Array.from(new Uint8Array(signResult)); | |||
} | |||
|
|||
async function derive_bits(password, salt, iterations, hashAlgorithm, lengthInBytes) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels like this function should either a) take PBKDF2 as a parameter, or b) include it in the name; since it's not applying a general/generic KDF, but a specific one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The approach I've been taking (for sign
- HMAC - and encrypt_decrypt
- AES-CBC) is to name the methods the same as the SubtleCrypto APIs, and then taking whatever parameters it needs from the managed code for now. And when we need to add more parameters/options in the future, we would add the parameters/refactor then.
This way it keeps it simple for now, and if we don't need to add anymore in the future it keeps it simple then too.
Adding the parameters now doesn't guarantee that other params can be used in the future without adding more parameters and needing to refactor then as well. For example, if we wanted to add ECDH, we would need to pass a public key as well.
At least that was my reasoning. Thoughts? I can change this approach to one of the above, if you want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm. Since the calling code and the acting code get delivered together I guess the signature is allowed to be modified as needed, so... I suppose it works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, if these APIs were public or somehow permanent, I would take a much different approach.
LGTM, other than the concern about the naming/signature of derive_bits. |
/azp run runtime-wasm |
Azure Pipelines successfully started running 1 pipeline(s). |
AOT wasm failures are #71838. |
Marks the APIs as supported on Browser, and enables Rfc2898 tests on Browser WASM.
Use SubtleCrypto deriveBits API to implement one shot Pbkdf2.
Also, make HKDF supported on Browser.
Contributes to #40074