This is a micro library providing AES encryption/decryption of fs2.Stream[F, Byte]
.
It uses AES GCM (Galois/Counter Mode) without padding.
It is published for Scala 2.13.x and 3.x and uses (and builds on) Cats Effect 3 and fs2 3.
"me.wojnowski" %% "fs2-aes" % "x.y.z"
val streamOfBytes: fs2.Stream[F, Byte] = ...
val encryptedStreamOfBytes: fs2.Stream[F, Byte] =
streamOfBytes.through(Aes.encrypt(key, chunkSize))
import me.wojnowski.fs2.aes.Aes
import cats.effect.std.SecureRandom
import fs2.Stream
import javax.crypto.SecretKey
val streamOfBytes: Stream[F, Byte] = ...
val key: SecretKey = ... // hint: Aes.keyFromHex
SecureRandom.javaSecuritySecureRandom[F].flatMap { implicit secureRandom =>
val encryptedStreamOfBytes = streamOfBytes.through(Aes.encrypt(key))
...
}
val encryptedStreamOfBytes: fs2.Stream[F, Byte] = ...
val decryptedStreamOfBytes: fs2.Stream[F, Byte] =
streamOfBytes.through(Aes.decrypt(key))
import me.wojnowski.fs2.aes.Aes
import fs2.Stream
import javax.crypto.SecretKey
val encryptedStreamOfBytes: Stream[F, Byte] = ...
val key: SecretKey = ... // hint: Aes.keyFromHex
val decryptedStreamOfBytes = streamOfBytes.through(Aes.decrypt(key))
There's a handy keyFromHex
method provided:
import me.wojnowski.fs2.aes.Aes
val maybeKey: Option[SecretKey] =
Aes.keyFromHex("8460623cf2eb7059f5a2f653513cfe66d9c21196a330414d4b3bf1f3f838d884")
Aes.generateKeyHexString[IO]
method might be used to generate a key like in a following example:
import cats.effect.IO
import cats.effect.IOApp
import cats.effect.std.SecureRandom
object KeyGenerator extends IOApp.Simple {
override def run: IO[Unit] =
for {
secureRandom <- SecureRandom.javaSecuritySecureRandom[IO]
key <- Aes.generateKeyHexString[IO](256)(secureRandom, implicitly)
_ <- IO.println(s"😱 Secret: $key")
} yield ()
}
For processing of large data it is useful to split it into smaller chunks. This library assumes the chunk size is constant throughout the whole stream, which it ensures by re-chunking it to provided chunk size.
While a default chunk size of 4 MiBs is provided, it is strongly advised to use a custom chunk size suited for a particular use-case.
Chunk size used for encryption is embedded at in the encrypted stream, so it would be automatically read during encryption. For details, take a look at Data format section.
The encrypted stream consist of:
- Chunk size [4 bytes]
- Chunks of encrypted data
- Initialisation Vector (IV) [12 bytes]
- Encrypted data [ChunkSize]
- Authentication Tag [16 bytes]
Therefore, the resulting stream/file size will increase by 4 bytes and 28 bytes per each chunk.
This projects keeps early semver versioning, so only bugfix releases are binary compatible.