extracting a dedicated media decrypter
This commit is contained in:
parent
b3d4f79d8c
commit
3c2a226555
|
@ -1,7 +1,6 @@
|
||||||
package app.dapk.st.messenger
|
package app.dapk.st.messenger
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Base64
|
|
||||||
import app.dapk.st.matrix.sync.RoomEvent
|
import app.dapk.st.matrix.sync.RoomEvent
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import coil.decode.DataSource
|
import coil.decode.DataSource
|
||||||
|
@ -14,15 +13,6 @@ import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import okio.Buffer
|
import okio.Buffer
|
||||||
import java.security.MessageDigest
|
|
||||||
import javax.crypto.Cipher
|
|
||||||
import javax.crypto.spec.IvParameterSpec
|
|
||||||
import javax.crypto.spec.SecretKeySpec
|
|
||||||
|
|
||||||
private const val CRYPTO_BUFFER_SIZE = 32 * 1024
|
|
||||||
private const val CIPHER_ALGORITHM = "AES/CTR/NoPadding"
|
|
||||||
private const val SECRET_KEY_SPEC_ALGORITHM = "AES"
|
|
||||||
private const val MESSAGE_DIGEST_ALGORITHM = "SHA-256"
|
|
||||||
|
|
||||||
class DecryptingFetcherFactory(private val context: Context) : Fetcher.Factory<RoomEvent.Image> {
|
class DecryptingFetcherFactory(private val context: Context) : Fetcher.Factory<RoomEvent.Image> {
|
||||||
override fun create(data: RoomEvent.Image, options: Options, imageLoader: ImageLoader): Fetcher {
|
override fun create(data: RoomEvent.Image, options: Options, imageLoader: ImageLoader): Fetcher {
|
||||||
|
@ -34,6 +24,8 @@ private val http = OkHttpClient()
|
||||||
|
|
||||||
class DecryptingFetcher(private val data: RoomEvent.Image, private val context: Context) : Fetcher {
|
class DecryptingFetcher(private val data: RoomEvent.Image, private val context: Context) : Fetcher {
|
||||||
|
|
||||||
|
private val mediaDecrypter = MediaDecrypter()
|
||||||
|
|
||||||
override suspend fun fetch(): FetchResult {
|
override suspend fun fetch(): FetchResult {
|
||||||
val response = http.newCall(Request.Builder().url(data.imageMeta.url).build()).execute()
|
val response = http.newCall(Request.Builder().url(data.imageMeta.url).build()).execute()
|
||||||
val outputStream = when {
|
val outputStream = when {
|
||||||
|
@ -44,32 +36,7 @@ class DecryptingFetcher(private val data: RoomEvent.Image, private val context:
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleEncrypted(response: Response, keys: RoomEvent.Image.ImageMeta.Keys): Buffer {
|
private fun handleEncrypted(response: Response, keys: RoomEvent.Image.ImageMeta.Keys): Buffer {
|
||||||
val key = Base64.decode(keys.k.replace('-', '+').replace('_', '/'), Base64.DEFAULT)
|
return response.body?.byteStream()?.let { mediaDecrypter.decrypt(it, keys) } ?: Buffer()
|
||||||
val initVectorBytes = Base64.decode(keys.iv, Base64.DEFAULT)
|
|
||||||
|
|
||||||
val decryptCipher = Cipher.getInstance(CIPHER_ALGORITHM)
|
|
||||||
val secretKeySpec = SecretKeySpec(key, SECRET_KEY_SPEC_ALGORITHM)
|
|
||||||
val ivParameterSpec = IvParameterSpec(initVectorBytes)
|
|
||||||
decryptCipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec)
|
|
||||||
|
|
||||||
val messageDigest = MessageDigest.getInstance(MESSAGE_DIGEST_ALGORITHM)
|
|
||||||
|
|
||||||
var read: Int
|
|
||||||
val d = ByteArray(CRYPTO_BUFFER_SIZE)
|
|
||||||
var decodedBytes: ByteArray
|
|
||||||
|
|
||||||
val outputStream = Buffer()
|
|
||||||
response.body?.let {
|
|
||||||
it.byteStream().use {
|
|
||||||
read = it.read(d)
|
|
||||||
while (read != -1) {
|
|
||||||
messageDigest.update(d, 0, read)
|
|
||||||
decodedBytes = decryptCipher.update(d, 0, read)
|
|
||||||
outputStream.write(decodedBytes)
|
|
||||||
read = it.read(d)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return outputStream
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package app.dapk.st.messenger
|
||||||
|
|
||||||
|
import android.util.Base64
|
||||||
|
import app.dapk.st.matrix.sync.RoomEvent
|
||||||
|
import okio.Buffer
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.security.MessageDigest
|
||||||
|
import javax.crypto.Cipher
|
||||||
|
import javax.crypto.spec.IvParameterSpec
|
||||||
|
import javax.crypto.spec.SecretKeySpec
|
||||||
|
|
||||||
|
private const val CRYPTO_BUFFER_SIZE = 32 * 1024
|
||||||
|
private const val CIPHER_ALGORITHM = "AES/CTR/NoPadding"
|
||||||
|
private const val SECRET_KEY_SPEC_ALGORITHM = "AES"
|
||||||
|
private const val MESSAGE_DIGEST_ALGORITHM = "SHA-256"
|
||||||
|
|
||||||
|
class MediaDecrypter {
|
||||||
|
|
||||||
|
fun decrypt(input: InputStream, keys: RoomEvent.Image.ImageMeta.Keys): Buffer {
|
||||||
|
val key = Base64.decode(keys.k.replace('-', '+').replace('_', '/'), Base64.DEFAULT)
|
||||||
|
val initVectorBytes = Base64.decode(keys.iv, Base64.DEFAULT)
|
||||||
|
|
||||||
|
val decryptCipher = Cipher.getInstance(CIPHER_ALGORITHM)
|
||||||
|
val secretKeySpec = SecretKeySpec(key, SECRET_KEY_SPEC_ALGORITHM)
|
||||||
|
val ivParameterSpec = IvParameterSpec(initVectorBytes)
|
||||||
|
decryptCipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec)
|
||||||
|
|
||||||
|
val messageDigest = MessageDigest.getInstance(MESSAGE_DIGEST_ALGORITHM)
|
||||||
|
|
||||||
|
var read: Int
|
||||||
|
val d = ByteArray(CRYPTO_BUFFER_SIZE)
|
||||||
|
var decodedBytes: ByteArray
|
||||||
|
|
||||||
|
val outputStream = Buffer()
|
||||||
|
input.use {
|
||||||
|
read = it.read(d)
|
||||||
|
while (read != -1) {
|
||||||
|
messageDigest.update(d, 0, read)
|
||||||
|
decodedBytes = decryptCipher.update(d, 0, read)
|
||||||
|
outputStream.write(decodedBytes)
|
||||||
|
read = it.read(d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return outputStream
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -38,9 +38,15 @@ internal class SendMessageUseCase(
|
||||||
}
|
}
|
||||||
|
|
||||||
is MessageService.Message.ImageMessage -> {
|
is MessageService.Message.ImageMessage -> {
|
||||||
|
val request = when (message.sendEncrypted) {
|
||||||
|
true -> {
|
||||||
|
throw IllegalStateException()
|
||||||
|
}
|
||||||
|
|
||||||
|
false -> {
|
||||||
val imageContent = imageContentReader.read(message.content.uri)
|
val imageContent = imageContentReader.read(message.content.uri)
|
||||||
val uri = httpClient.execute(uploadRequest(imageContent.content, imageContent.fileName, imageContent.mimeType)).contentUri
|
val uri = httpClient.execute(uploadRequest(imageContent.content, imageContent.fileName, imageContent.mimeType)).contentUri
|
||||||
val request = sendRequest(
|
sendRequest(
|
||||||
roomId = message.roomId,
|
roomId = message.roomId,
|
||||||
eventType = EventType.ROOM_MESSAGE,
|
eventType = EventType.ROOM_MESSAGE,
|
||||||
txId = message.localId,
|
txId = message.localId,
|
||||||
|
@ -54,6 +60,9 @@ internal class SendMessageUseCase(
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
httpClient.execute(request).eventId
|
httpClient.execute(request).eventId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue