Skip to content

Commit

Permalink
Fix decryption of non-buffered input stream (#16)
Browse files Browse the repository at this point in the history
* fix: Add test for decryption of non-buffered input stream
* fix: Fix decryption of non-buffered input stream
  • Loading branch information
osipxd authored Feb 26, 2023
1 parent fe5fef9 commit 9cefd66
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 3 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## [Unreleased]

### Fixed

- Fixed decryption fallback from StreamingAead to Aead (#15)

### Housekeeping

- Update Gradle to 7.6.1
Expand Down
2 changes: 2 additions & 0 deletions encrypted-datastore/src/main/kotlin/Aead.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import com.google.crypto.tink.Aead
import java.io.InputStream

internal fun Aead.newDecryptedStream(inputStream: InputStream): InputStream {
// Method 'decrypt' throws GeneralSecurityException for empty byte array,
// so let's check it is not empty.
return if (inputStream.available() > 0) {
decrypt(inputStream.readBytes(), null).inputStream()
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@ internal class StreamingAeadWithFallback(
) : StreamingAead by delegate {

override fun newDecryptingStream(ciphertextSource: InputStream, associatedData: ByteArray): InputStream {
// Input Stream should support mark and reset to make it reusable in fallback stream.
// NOTE: mark is called in delegate.newDecryptingStream
val inputStream = if (ciphertextSource.markSupported()) ciphertextSource else ciphertextSource.buffered()

return DecryptingStreamWithFallback(
stream = delegate.newDecryptingStream(ciphertextSource, associatedData),
fallbackStream = { fallback.newDecryptedStream(ciphertextSource) },
stream = delegate.newDecryptingStream(inputStream, associatedData),
fallbackStream = { fallback.newDecryptedStream(inputStream) },
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import com.google.crypto.tink.StreamingAead
import com.google.crypto.tink.aead.AeadConfig
import com.google.crypto.tink.streamingaead.StreamingAeadConfig
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.io.TempDir
import java.io.IOException
import java.nio.file.Path
import kotlin.io.path.div
import kotlin.io.path.inputStream
import kotlin.io.path.writeBytes
import kotlin.test.Test
import kotlin.test.assertEquals

Expand All @@ -16,6 +21,9 @@ internal class StreamingAeadWithFallbackTest {
private var aead: Aead
private var streamingAead: StreamingAead

@field:TempDir
lateinit var tempDir: Path

init {
AeadConfig.register()
StreamingAeadConfig.register()
Expand All @@ -37,7 +45,7 @@ internal class StreamingAeadWithFallbackTest {
}

@Test
fun `decrypt encrypted stream with decryption fallback`() {
fun `decrypt encrypted bytes stream with decryption fallback`() {
val plaintext = "Plaintext"
val encryptedStream = aead.encrypt(plaintext.toByteArray(), null).inputStream()
val decryptingStream = streamingAead.withDecryptionFallback(aead)
Expand All @@ -46,4 +54,19 @@ internal class StreamingAeadWithFallbackTest {
val decrypted = decryptingStream.readBytes().decodeToString()
assertEquals(plaintext, decrypted)
}

@Test
fun `decrypt encrypted file stream with decryption fallback`() {
val plaintext = "Plaintext"

val file = tempDir / "encrypted-file"
file.writeBytes(aead.encrypt(plaintext.toByteArray(), null))

val encryptedStream = file.inputStream()
val decryptingStream = streamingAead.withDecryptionFallback(aead)
.newDecryptingStream(encryptedStream, byteArrayOf())

val decrypted = decryptingStream.readBytes().decodeToString()
assertEquals(plaintext, decrypted)
}
}

0 comments on commit 9cefd66

Please sign in to comment.