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

Ability to create ICryptoTransform, passing key and iv as Span<byte> #27118

Open
d3v3us opened this issue Aug 12, 2018 · 6 comments
Open

Ability to create ICryptoTransform, passing key and iv as Span<byte> #27118

d3v3us opened this issue Aug 12, 2018 · 6 comments
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Security
Milestone

Comments

@d3v3us
Copy link

d3v3us commented Aug 12, 2018

It could be for example in Aes class, where CreateEncryptor declared, we could pass Span for internal UniversalCryptoTransformer.

public int TransformBlock(
Span<byte> inputBuffer, 
int inputOffset, 
int inputCount, 
Span<byte> outputBuffer, 
int outputOffset) {
@d3v3us d3v3us changed the title Ability to create ICryptoTransform, passing key and iv as Spam<byte> Ability to create ICryptoTransform, passing key and iv as Span<byte> Aug 12, 2018
@morganbr
Copy link
Contributor

Creating a new object would have to copy the key and IV (Because the Span can't be copied to the fields of the new ICryptoTransform). We might want to consider encryption and decryption methods that don't require an ICryptoTransform and that accept Spans though. The API in dotnet/corefx#31389 could be a good general template for that.

@bartonjs
Copy link
Member

Really there are two different problems.

  1. Given a key/IV in a Span<byte> is it possible to instantiate an ICryptoTransform without ever copying it to an array in my (user, non-framework) code? (Which seems to be what the title is asking)
  2. Is it possible to do symmetric encryption where either the source or destination memory is only tracked (in some "this method") by a Span<byte>? (Which seems to be what the contents are asking)

The first one could be solved by making overloads to CreateEncryptor and CreateDecryptor which took in Span<byte>. The existing ones all copy the input key/iv anyways, so there aren't a whole lot of surprises to this approach. But it doesn't quite seem worth doing without the second part.

The second part doesn't have a very good solution right now. In the BCL our compatibility and breaking change rules say that we can't alter an interface once it ships, so we can't add new methods to ICryptoTransform. Sometimes we can work around that with extension methods, but an extension method on an interface can usually only simplify the API, not make there being an alternate way of doing work. So all an extension method could do is call ToArray and defer to the existing TransformBlock/TransformFinalBlock. That's kinda the opposite of what is desired.

The way forward is most likely via default interface implementations (so new span-based methods can defer to the array-based ones, but then all of our implementations can re-define their behavior to make the span path more optimal). As far as I know, that isn't available to corefx yet.

@d3v3us
Copy link
Author

d3v3us commented Aug 16, 2018

ToArray will create unnecessary allocations, but we can create an extension method as you mentioned, accepting Span or ReadOnlyMemory as an argument, then we could get ArraySegment from memory by calling MemoryMarshal.TryGetArray method, further we could get and access to array via arraysegment.Array property.
Am i missing something or it is good scenario for creating that extension?

@bartonjs
Copy link
Member

The correct (in a pure world) design for the API is ReadOnlySpan<byte> input, Span<byte> output, out int bytesConsumed, out int bytesWritten) (or something like that). From a Span you can't get back to the array, only Memory can do that (at least, I'm not seeing a way to do it from a Span). So it's not something that we can do yet in corefx.

TransformFinalBlock might be tricky either way, since you can't really make the Span version call the current one and then return false because the buffer was too small (because data might get lost). The interface default version would (thinking out loud) need to return false without calling TransformFinalBlock if the output span was insufficient for the number of blocks required for the input, plus one more whole block. Definitely a place where the overrides would do better.

@GSPP
Copy link

GSPP commented Aug 18, 2018

There needs to be a new interface to properly support Span and achieve the performance goals that Span is supposed to make possible. CryptoStream might need a pipeline based alternative. This would be a non-trivial overhaul of the crypto infrastructure.

@GSPP
Copy link

GSPP commented Jan 8, 2019

AES has fixed IV and key size. The data could be copied out into a field (not an array).

@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the 5.0 milestone Jan 31, 2020
@maryamariyan maryamariyan added the untriaged New issue has not been triaged by the area owner label Feb 23, 2020
@bartonjs bartonjs modified the milestones: 5.0.0, Future Jul 7, 2020
@bartonjs bartonjs removed the untriaged New issue has not been triaged by the area owner label Jul 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Security
Projects
None yet
Development

No branches or pull requests

6 participants