jedisct1 / libsodium

A modern, portable, easy to use crypto library.

Home Page:https://libsodium.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

AES-256 GCM crypto_stream - are there any plans to support it?

tomekit opened this issue · comments

I was wondering if there are any plans to implement AES-256 GCM streaming (both authenticated and unauthenticated).
Am I right that there are already multiple other unauthenticated streaming implementations, including XChaCha20?
Screenshot from 2023-01-26 12-07-57

We're running client-side encrypted file manager using S3 protocol. We're using AES-GCM encryption which initially AWS introduced in their SDK's: https://docs.aws.amazon.com/general/latest/gr/aws_sdk_cryptography.html#crypto_features

When we allow user to download huge files we stream and perform authentication using PointyCastle (which is Dart implementation of Java's BouncyCastle). It works fine, it's just dead slow. We're experimenting with libsodium and performance results are great, but current non-streaming implementation forces us to limit max size of attachment to avoid memory issues.
This would also allow us to stream video (it's just there would be no seeking, since stream would have to start from the beginning).

The second use case which we aim to implement is video preview with seeking option. This would have to work in an unauthenticated mode and there would have to be possibility to initialize the IV counter based on the video preview position.

I would like just ask if there are any plans for building some stuff around AES-256 GCM streaming. Thanks.

After some initial investigation and given cross-platform availability we will be exploring potential migration towards XChaCha20-Poly1305 which seem to tick all of the boxes. Whilst it would be useful to hear if libsodium plans to support AES-256 GCM streams and if https://github.com/jedisct1/swift-sodium will support AES-256 GCM at all, I am going to close this issue, as I don't feel this deserve to be the TOP1 open issue :)

Thanks for the great work.

AES-GCM is authenticated by design. In order to decrypt a ciphertext, even partially, the entire ciphertext has to be seen in order to check the authentication tag, before releasing the decrypted message. It also has a hard limit of 64 GB.

In order to encrypt arbitrary large content, and even support seeking, what you can do is split the content into fixed-size chunks, and encrypt them individually, using the chunk number as a nonce.

Also see https://doc.libsodium.org/secret-key_cryptography/encrypted-messages

Thank you for your comment.

I am still not sure about splitting content into fixed-size chunk for a video stream, because plaintext content position gets out of sync with ciphertext (due to additional authentication for each fixed-sized chunk).
That means that if a video client (which operates on a decrypted data) requests certain byte position using e.g. HTTP RANGE, server would normally return something which isn't in line with what was requested.
You would then have to make either client or server aware of the cipher construction, which isn't feasible for us (we can't change the S3 protocol and would have to implement video client separately on each platform given our cross-platform support).

That's why I was looking more into unauthenticated territory (think of AES-128 used in HLS streams).
Given that AES-GCM is nothing else than AES-CTR + incremented nonce/IV by 1 + GHASH, I was really thinking of treating the same ciphertext differently depending on the use case / security expectations.

I wouldn't be far away, trying to adjust things with AES and not afraid of Pull Requests, but given we still have an option to switch ciphers, it sounds like sticking to XChaCha20 might be better long-term move in general.