diff --git a/core/common/src/main/kotlin/eu/kanade/tachiyomi/util/storage/CbzCrypto.kt b/core/common/src/main/kotlin/eu/kanade/tachiyomi/util/storage/CbzCrypto.kt index 1f8a3f503..465534825 100644 --- a/core/common/src/main/kotlin/eu/kanade/tachiyomi/util/storage/CbzCrypto.kt +++ b/core/common/src/main/kotlin/eu/kanade/tachiyomi/util/storage/CbzCrypto.kt @@ -16,6 +16,8 @@ import uy.kohesive.injekt.injectLazy import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.InputStream +import java.nio.ByteBuffer +import java.nio.CharBuffer import java.security.KeyStore import java.security.SecureRandom import javax.crypto.Cipher @@ -33,28 +35,28 @@ object CbzCrypto { const val DATABASE_NAME = "tachiyomiEncrypted.db" const val DEFAULT_COVER_NAME = "cover.jpg" private val securityPreferences: SecurityPreferences by injectLazy() - private val keyStore = KeyStore.getInstance(KEYSTORE).apply { + private val keyStore = KeyStore.getInstance(Keystore).apply { load(null) } private val encryptionCipherCbz - get() = Cipher.getInstance(CRYPTO_SETTINGS).apply { + get() = Cipher.getInstance(CryptoSettings).apply { init( Cipher.ENCRYPT_MODE, - getKey(ALIAS_CBZ), + getKey(AliasCbz), ) } private val encryptionCipherSql - get() = Cipher.getInstance(CRYPTO_SETTINGS).apply { + get() = Cipher.getInstance(CryptoSettings).apply { init( Cipher.ENCRYPT_MODE, - getKey(ALIAS_SQL), + getKey(AliasSql), ) } private fun getDecryptCipher(iv: ByteArray, alias: String): Cipher { - return Cipher.getInstance(CRYPTO_SETTINGS).apply { + return Cipher.getInstance(CryptoSettings).apply { init( Cipher.DECRYPT_MODE, getKey(alias), @@ -69,12 +71,12 @@ object CbzCrypto { } private fun generateKey(alias: String): SecretKey { - return KeyGenerator.getInstance(ALGORITHM).apply { + return KeyGenerator.getInstance(Algorithm).apply { init( KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) - .setKeySize(KEY_SIZE) - .setBlockModes(BLOCK_MODE) - .setEncryptionPaddings(PADDING) + .setKeySize(KeySize) + .setBlockModes(BlockMode) + .setEncryptionPaddings(Padding) .setRandomizedEncryptionRequired(true) .setUserAuthenticationRequired(false) .build(), @@ -82,13 +84,13 @@ object CbzCrypto { }.generateKey() } - private fun encrypt(password: String, cipher: Cipher): String { + private fun encrypt(password: ByteArray, cipher: Cipher): String { val outputStream = ByteArrayOutputStream() outputStream.use { output -> output.write(cipher.iv) - ByteArrayInputStream(password.toByteArray()).use { input -> - val buffer = ByteArray(BUFFER_SIZE) - while (input.available() > BUFFER_SIZE) { + ByteArrayInputStream(password).use { input -> + val buffer = ByteArray(BufferSize) + while (input.available() > BufferSize) { input.read(buffer) output.write(cipher.update(buffer)) } @@ -98,51 +100,66 @@ object CbzCrypto { return Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT) } - private fun decrypt(encryptedPassword: String, alias: String): String { + private fun decrypt(encryptedPassword: String, alias: String): ByteArray { val inputStream = Base64.decode(encryptedPassword, Base64.DEFAULT).inputStream() return inputStream.use { input -> - val iv = ByteArray(IV_SIZE) + val iv = ByteArray(IvSize) input.read(iv) val cipher = getDecryptCipher(iv, alias) - ByteArrayOutputStream().use { output -> - val buffer = ByteArray(BUFFER_SIZE) - while (inputStream.available() > BUFFER_SIZE) { + ByteArrayOutputStreamPassword().use { output -> + val buffer = ByteArray(BufferSize) + while (inputStream.available() > BufferSize) { inputStream.read(buffer) output.write(cipher.update(buffer)) } output.write(cipher.doFinal(inputStream.readBytes())) - output.toString() + output.toByteArray().also { + output.clear() + } } } } fun deleteKeyCbz() { - keyStore.deleteEntry(ALIAS_CBZ) - generateKey(ALIAS_CBZ) + keyStore.deleteEntry(AliasCbz) + generateKey(AliasCbz) } fun encryptCbz(password: String): String { - return encrypt(password, encryptionCipherCbz) + return encrypt(password.toByteArray(), encryptionCipherCbz) } fun getDecryptedPasswordCbz(): CharArray { val encryptedPassword = securityPreferences.cbzPassword().get() if (encryptedPassword.isBlank()) error("This archive is encrypted please set a password") - return decrypt(encryptedPassword, ALIAS_CBZ).toCharArray() + val cbzBytes = decrypt(encryptedPassword, AliasCbz) + return Charsets.UTF_8.decode(ByteBuffer.wrap(cbzBytes)).array() + .also { + cbzBytes.fill('#'.code.toByte()) + } } private fun generateAndEncryptSqlPw() { val charPool: List = ('a'..'z') + ('A'..'Z') + ('0'..'9') - val password = (1..SQL_PASSWORD_LENGTH).map { - charPool[SecureRandom().nextInt(charPool.size)] - }.joinToString("", transform = { it.toString() }) - securityPreferences.sqlPassword().set(encrypt(password, encryptionCipherSql)) + val passwordArray = CharArray(SqlPasswordLength) + for (i in 0..