diff --git a/app/src/androidTest/java/com/futo/platformplayer/EncryptionProviderTests.kt b/app/src/androidTest/java/com/futo/platformplayer/EncryptionProviderTests.kt index f4605efdb5ab04cb65c6780c1b70bc12a1567824..51319782c8fee65ef8661ac29c7afdcbdb3c2904 100644 --- a/app/src/androidTest/java/com/futo/platformplayer/EncryptionProviderTests.kt +++ b/app/src/androidTest/java/com/futo/platformplayer/EncryptionProviderTests.kt @@ -36,23 +36,6 @@ class EncryptionProviderTests { assertArrayEquals(bytes, decrypted); } - @Test - fun testEncryptDecryptBytesPassword() { - val encryptionProvider = EncryptionProvider.instance - val bytes = "This is a test string.".toByteArray(); - val password = "1234".padStart(32, '9'); - - // Encrypt the plaintext - val ciphertext = encryptionProvider.encrypt(bytes, password) - - // Decrypt the ciphertext - val decrypted = encryptionProvider.decrypt(ciphertext, password) - - // The decrypted string should be equal to the original plaintext - assertArrayEquals(bytes, decrypted); - - } - private fun assertArrayEquals(a: ByteArray, b: ByteArray) { assertEquals(a.size, b.size); for(i in 0 until a.size) { diff --git a/app/src/androidTest/java/com/futo/platformplayer/PasswordEncryptionProviderTests.kt b/app/src/androidTest/java/com/futo/platformplayer/PasswordEncryptionProviderTests.kt new file mode 100644 index 0000000000000000000000000000000000000000..98d26a222acc4300cd722f4f698a2eed3cebe961 --- /dev/null +++ b/app/src/androidTest/java/com/futo/platformplayer/PasswordEncryptionProviderTests.kt @@ -0,0 +1,31 @@ +package com.futo.platformplayer + +import com.futo.platformplayer.encryption.EncryptionProvider +import com.futo.platformplayer.encryption.PasswordEncryptionProvider +import junit.framework.TestCase.assertEquals +import org.junit.Test + +class PasswordEncryptionProviderTests { + @Test + fun testEncryptDecryptBytesPassword() { + val password = "1234".padStart(32, '9'); + val encryptionProvider = PasswordEncryptionProvider(password); + val bytes = "This is a test string.".toByteArray(); + + // Encrypt the plaintext + val ciphertext = encryptionProvider.encrypt(bytes) + + // Decrypt the ciphertext + val decrypted = encryptionProvider.decrypt(ciphertext) + + // The decrypted string should be equal to the original plaintext + assertArrayEquals(bytes, decrypted); + } + + private fun assertArrayEquals(a: ByteArray, b: ByteArray) { + assertEquals(a.size, b.size); + for(i in 0 until a.size) { + assertEquals(a[i], b[i]); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/encryption/EncryptionProvider.kt b/app/src/main/java/com/futo/platformplayer/encryption/EncryptionProvider.kt index 86d1d885fd70c57da0c469fa14e7f2e77e7331b1..d02b54f2e639cda8326f169aa63f6a6ee37d3d9d 100644 --- a/app/src/main/java/com/futo/platformplayer/encryption/EncryptionProvider.kt +++ b/app/src/main/java/com/futo/platformplayer/encryption/EncryptionProvider.kt @@ -3,6 +3,7 @@ package com.futo.platformplayer.encryption import android.security.keystore.KeyGenParameterSpec import android.security.keystore.KeyProperties import android.util.Base64 +import com.futo.polycentric.core.EncryptionProvider import java.security.Key import java.security.KeyStore import javax.crypto.Cipher @@ -25,35 +26,32 @@ class EncryptionProvider { .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setRandomizedEncryptionRequired(false) .build()); - + keyGenerator.generateKey(); } } - fun encrypt(decrypted: String, password: String? = null): String { - val encodedBytes = encrypt(decrypted.toByteArray(), password); + fun encrypt(decrypted: String): String { + val encodedBytes = encrypt(decrypted.toByteArray()); val encrypted = Base64.encodeToString(encodedBytes, Base64.DEFAULT); return encrypted; } - fun encrypt(decrypted: ByteArray, password: String? = null): ByteArray { + fun encrypt(decrypted: ByteArray): ByteArray { val c: Cipher = Cipher.getInstance(AES_MODE); - val keyToUse = if(password == null) secretKey else SecretKeySpec(password.toByteArray(), "AES"); - c.init(Cipher.ENCRYPT_MODE, keyToUse, GCMParameterSpec(128, FIXED_IV)); + c.init(Cipher.ENCRYPT_MODE, secretKey, GCMParameterSpec(128, FIXED_IV)); val encodedBytes: ByteArray = c.doFinal(decrypted); return encodedBytes; } - fun decrypt(encrypted: String, password: String? = null): String { + fun decrypt(encrypted: String): String { val c = Cipher.getInstance(AES_MODE); - val keyToUse = if(password == null) secretKey else SecretKeySpec(password.toByteArray(), "AES"); - c.init(Cipher.DECRYPT_MODE, keyToUse, GCMParameterSpec(128, FIXED_IV)); + c.init(Cipher.DECRYPT_MODE, secretKey, GCMParameterSpec(128, FIXED_IV)); val decrypted = String(c.doFinal(Base64.decode(encrypted, Base64.DEFAULT))); return decrypted; } - fun decrypt(encrypted: ByteArray, password: String? = null): ByteArray { + fun decrypt(encrypted: ByteArray): ByteArray { val c = Cipher.getInstance(AES_MODE); - val keyToUse = if(password == null) secretKey else SecretKeySpec(password.toByteArray(), "AES"); - c.init(Cipher.DECRYPT_MODE, keyToUse, GCMParameterSpec(128, FIXED_IV)); + c.init(Cipher.DECRYPT_MODE, secretKey, GCMParameterSpec(128, FIXED_IV)); return c.doFinal(encrypted); } diff --git a/app/src/main/java/com/futo/platformplayer/encryption/PasswordEncryptionProvider.kt b/app/src/main/java/com/futo/platformplayer/encryption/PasswordEncryptionProvider.kt new file mode 100644 index 0000000000000000000000000000000000000000..3b694b1935b6f3cf9346531fcd73451669f7952e --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/encryption/PasswordEncryptionProvider.kt @@ -0,0 +1,45 @@ + +package com.futo.platformplayer.encryption + +import android.util.Base64 +import javax.crypto.Cipher +import javax.crypto.spec.GCMParameterSpec +import javax.crypto.spec.SecretKeySpec + +class PasswordEncryptionProvider { + private val _key: SecretKeySpec; + + constructor(password: String) { + _key = SecretKeySpec(password.toByteArray(), "AES"); + } + + fun encrypt(decrypted: String): String { + val encodedBytes = encrypt(decrypted.toByteArray()); + val encrypted = Base64.encodeToString(encodedBytes, Base64.DEFAULT); + return encrypted; + } + fun encrypt(decrypted: ByteArray): ByteArray { + val c: Cipher = Cipher.getInstance(AES_MODE); + c.init(Cipher.ENCRYPT_MODE, _key, GCMParameterSpec(128, FIXED_IV)); + val encodedBytes: ByteArray = c.doFinal(decrypted); + return encodedBytes; + } + + fun decrypt(encrypted: String): String { + val c = Cipher.getInstance(AES_MODE); + c.init(Cipher.DECRYPT_MODE, _key, GCMParameterSpec(128, FIXED_IV)); + val decrypted = String(c.doFinal(Base64.decode(encrypted, Base64.DEFAULT))); + return decrypted; + } + fun decrypt(encrypted: ByteArray): ByteArray { + val c = Cipher.getInstance(AES_MODE); + c.init(Cipher.DECRYPT_MODE, _key, GCMParameterSpec(128, FIXED_IV)); + return c.doFinal(encrypted); + } + + companion object { + private val FIXED_IV = byteArrayOf(12, 43, 127, 2, 99, 22, 6, 78, 24, 53, 8, 101); + private const val AES_MODE = "AES/GCM/NoPadding"; + private val TAG = "PasswordEncryptionProvider"; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/states/StateBackup.kt b/app/src/main/java/com/futo/platformplayer/states/StateBackup.kt index c71fe8e90fe5418b14ac55cfc8800f5fbbcbce5a..9667f7ac44c862231df2735caa3509c5cf49b460 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateBackup.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateBackup.kt @@ -20,6 +20,7 @@ import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo import com.futo.platformplayer.copyTo import com.futo.platformplayer.copyToOutputStream import com.futo.platformplayer.encryption.EncryptionProvider +import com.futo.platformplayer.encryption.PasswordEncryptionProvider import com.futo.platformplayer.getInputStream import com.futo.platformplayer.getNowDiffHours import com.futo.platformplayer.getOutputStream @@ -106,7 +107,7 @@ class StateBackup { val data = export(); val zip = data.asZip(); - val encryptedZip = EncryptionProvider.instance.encrypt(zip, getAutomaticBackupPassword()); + val encryptedZip = PasswordEncryptionProvider(getAutomaticBackupPassword()).encrypt(zip); if(!Settings.instance.storage.isStorageMainValid(context)) { StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) { @@ -151,7 +152,7 @@ class StateBackup { throw IllegalStateException("Backup file does not exist"); val backupBytesEncrypted = backupFiles.first!!.readBytes(context) ?: throw IllegalStateException("Could not read stream of [${backupFiles.first?.uri}]"); - val backupBytes = EncryptionProvider.instance.decrypt(backupBytesEncrypted, getAutomaticBackupPassword(password)); + val backupBytes = PasswordEncryptionProvider(getAutomaticBackupPassword(password)).decrypt(backupBytesEncrypted); importZipBytes(context, scope, backupBytes); Logger.i(TAG, "Finished AutoBackup restore"); } @@ -179,7 +180,7 @@ class StateBackup { throw ex; val backupBytesEncrypted = backupFiles.second!!.readBytes(context) ?: throw IllegalStateException("Could not read stream of [${backupFiles.second?.uri}]"); - val backupBytes = EncryptionProvider.instance.decrypt(backupBytesEncrypted, getAutomaticBackupPassword(password)); + val backupBytes = PasswordEncryptionProvider(getAutomaticBackupPassword(password)).decrypt(backupBytesEncrypted); importZipBytes(context, scope, backupBytes); Logger.i(TAG, "Finished AutoBackup restore"); }