-
-
Notifications
You must be signed in to change notification settings - Fork 8
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
Streaming decryption #36
Comments
Thanks for opening an issue! Could you say a bit more about your requirements here? We added the |
Correct, we have no fd or path. In this case it's actually a custom object that implements file-like methods (it inherits But if you are doing buffering yourself then I would expect probably any python object that just implements |
Got it, thanks for explaining! I'm open to supporting this, but I need to think a bit more about how I want to do it: I'd generally prefer to keep this package's dependencies to a bare minimum, and I want to make sure the downsides of using a file-like object API are communicated well to users (specifically, there's much more "critical" time spent in the CPython interpreter, so fileobj I/O is a lot slower than acquiring a file on just the Rust side.) |
I gave this some more thought:
Let me know if this sounds reasonable to you! TL;DR: I'd be willing to accept a PR for fileobj support, but only if your other options here are exhausted 🙂 |
We would prefer not to route it thru the filesystem if possible. Another approach could be chunked decryption, where we would get bytes however we want in python and repeatedly pass an incremental It looks like the rust age library has an API for this https://github.com/str4d/rage/blob/bccc4bc9497e0a4542219787ec8183414d1bd9a5/age/src/primitives/stream.rs#L197 I guess you would need to expose |
That's understandable; does Re: chunked decryption: this would also be reasonable! |
Hello, I'm looking for this too. We have a decryption service that reads file from remote storage and writes the decrypted bytes to the caller. This service has no disk available to store the encrypted or decrypted state (plus we pass that stream through other filters like decompression and checksumming). We have an API that basically looks like this on our end and all decryptors implement it: def filter(input: io.BufferedReader, output: io.BufferedWriter):
... The simplest implementation of this is what we have for zstd decompression (also rust bindings): def zstd_decompress_filter(input: io.IOBase, output: io.IOBase) -> str:
dctx = zstandard.ZstdDecompressor()
dctx.copy_stream(input, output) |
Could you check and see if |
I don't know memfd, never used it. Unless I'm missing something, I will create an input and output anonymous files and I will have to write the whole file into that anonymous file, basically loading it fully in memory. That's not streaming. Here is what I came up with, take it as pseudocode. def age_decrypt_filter(path: str, request_output: io.BytesIO) -> str:
s3_input = s3.get_stream(path)
inputfd = os.memfd_create("s3-input")
outputfd = os.memfd_create("age-output")
recipient = pyrage.x25519.Recipient.from_str("age1z...")
with open(inputfd, "rb") as age_input:
shutil.copyfileobj(s3_input, age_input)
with open(outputfd, "wb") as age_output:
age_input.seek(0, os.SEEK_SET)
pyrage.decrypt_file(age_input, age_output, [recipient])
age_output.seek(0, os.SEEK_SET)
zstd_decompress_filter(age_output, request_output)
def zstd_decompress_filter(input: io.IOBase, output: io.IOBase) -> str:
dctx = zstandard.ZstdDecompressor()
dctx.copy_stream(input, output) |
The trick here would be to use demand-paging with TL;DR this is do-able, but probably not practically. Sorry for taking you down a rabbit hole 🙂 Looks like a fileobj-based interface is probably for the best, after all. Would you be interested in submitting a patch for that, potentially based on the work in #32? |
Any plans to support streaming decryption from a file-like object? We want to stream large encrypted files from an sftp server and decrypt them on the fly as we write them somewhere else.
It looks like
decrypt_file
is basically doing that, we just need an API that takes the actual file-like fileobj.pyrage/src/lib.rs
Line 224 in aab0f86
Maybe using something like this https://github.com/omerbenamram/pyo3-file
The text was updated successfully, but these errors were encountered: