Hacemos una revisión completa cada una de las reseñas de nuestro espacio con el objetivo de mostrarte siempre la información certera y actual.
Solución:
Ejemplo de cómo reproducir un archivo de audio encriptado, espero que esto ayude a alguien. Estoy usando Kotlin aquí
import android.net.Uri
import com.google.android.exoplayer2.C
import com.google.android.exoplayer2.upstream.DataSource
import com.google.android.exoplayer2.upstream.DataSourceInputStream
import com.google.android.exoplayer2.upstream.DataSpec
import com.google.android.exoplayer2.util.Assertions
import java.io.IOException
import javax.crypto.CipherInputStream
class EncryptedDataSource(upstream: DataSource) : DataSource
private var upstream: DataSource? = upstream
private var cipherInputStream: CipherInputStream? = null
override fun open(dataSpec: DataSpec?): Long
val cipher = getCipherInitDecrypt()
val inputStream = DataSourceInputStream(upstream, dataSpec)
cipherInputStream = CipherInputStream(inputStream, cipher)
inputStream.open()
return C.LENGTH_UNSET.toLong()
override fun read(buffer: ByteArray?, offset: Int, readLength: Int): Int
Assertions.checkNotNull(cipherInputStream)
val bytesRead = cipherInputStream!!.read(buffer, offset, readLength)
return if (bytesRead < 0)
C.RESULT_END_OF_INPUT
else bytesRead
override fun getUri(): Uri
return upstream!!.uri
@Throws(IOException::class)
override fun close()
if (cipherInputStream != null)
cipherInputStream = null
upstream!!.close()
En la función anterior, debe obtener Cipher que se usó para el cifrado y iniciarlo: algo como esto
fun getCipherInitDecrypt(): Cipher
val cipher = Cipher.getInstance("AES/CTR/NoPadding", "BC");
val iv = IvParameterSpec(initVector.toByteArray(charset("UTF-8")))
val skeySpec = SecretKeySpec(key, TYPE_RSA)
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv)
return cipher
El siguiente paso es crear DataSource.Factory
por DataSource
hemos implementado antes
import com.google.android.exoplayer2.upstream.DataSource
class EncryptedFileDataSourceFactory(var dataSource: DataSource) : DataSource.Factory
override fun createDataSource(): DataSource
return EncryptedDataSource(dataSource)
Y el último paso es la inicialización de los jugadores.
private fun prepareExoPlayerFromFileUri(uri: Uri)
val player = ExoPlayerFactory.newSimpleInstance(
DefaultRenderersFactory(this),
DefaultTrackSelector(),
DefaultLoadControl())
val playerView = findViewById(R.id.player_view)
playerView.player = player
val dsf = DefaultDataSourceFactory(this, Util.getUserAgent(this, "ExoPlayerInfo"))
//This line do the thing
val mediaSource = ExtractorMediaSource.Factory(EncryptedFileDataSourceFactory(dsf.createDataSource())).createMediaSource(uri)
player.prepare(mediaSource)
Finalmente encontré la solución.
Usé un no-padding para el algoritmo de cifrado, de esta manera:
cipher = Cipher.getInstance("AES/CTR/NoPadding", "BC");
para que el tamaño del archivo cifrado y el tamaño del archivo claro permanezcan iguales. Entonces ahora creé la secuencia:
cipherInputStream = new CipherInputStream(inputStream, cipher)
@Override
public int available() throws IOException
return in.available();
;
Esto se debe a que la documentación de Java dice sobre ChiperInputStream.available()
ese
Este método deberían ser anulado
y en realidad creo que es más como un MUST, porque los valores recuperados de ese método son a menudo realmente extraños.
¡Y eso es todo! Ahora funciona perfectamente.
No creo que una fuente de datos personalizada, con abrir / leer / cerrar, sea una solución para sus necesidades. Para un descifrado 'sobre la marcha' (valioso para archivos grandes, pero no solo), debe diseñar una arquitectura de transmisión.
Ya hay publicaciones similares a las tuyas. Para encontrarlos, no busque 'exoplayer', sino 'videoview' o 'mediaplayer'. Las respuestas deben ser compatibles.
Por ejemplo, reproducir archivos de video encriptados usando VideoView
Acuérdate de que tienes autorización de parafrasear tu experiencia si te fue preciso.