-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #31 from capcom6/feature/encryption
End-to-end encryption support
- Loading branch information
Showing
27 changed files
with
666 additions
and
187 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
118 changes: 118 additions & 0 deletions
118
app/schemas/me.capcom.smsgateway.data.AppDatabase/5.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
{ | ||
"formatVersion": 1, | ||
"database": { | ||
"version": 5, | ||
"identityHash": "4a86263b9bb6a736271cc66c6faca254", | ||
"entities": [ | ||
{ | ||
"tableName": "Message", | ||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `text` TEXT NOT NULL, `source` TEXT NOT NULL DEFAULT 'Local', `state` TEXT NOT NULL, `isEncrypted` INTEGER NOT NULL DEFAULT 0, `createdAt` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`id`))", | ||
"fields": [ | ||
{ | ||
"fieldPath": "id", | ||
"columnName": "id", | ||
"affinity": "TEXT", | ||
"notNull": true | ||
}, | ||
{ | ||
"fieldPath": "text", | ||
"columnName": "text", | ||
"affinity": "TEXT", | ||
"notNull": true | ||
}, | ||
{ | ||
"fieldPath": "source", | ||
"columnName": "source", | ||
"affinity": "TEXT", | ||
"notNull": true, | ||
"defaultValue": "'Local'" | ||
}, | ||
{ | ||
"fieldPath": "state", | ||
"columnName": "state", | ||
"affinity": "TEXT", | ||
"notNull": true | ||
}, | ||
{ | ||
"fieldPath": "isEncrypted", | ||
"columnName": "isEncrypted", | ||
"affinity": "INTEGER", | ||
"notNull": true, | ||
"defaultValue": "0" | ||
}, | ||
{ | ||
"fieldPath": "createdAt", | ||
"columnName": "createdAt", | ||
"affinity": "INTEGER", | ||
"notNull": true, | ||
"defaultValue": "0" | ||
} | ||
], | ||
"primaryKey": { | ||
"columnNames": [ | ||
"id" | ||
], | ||
"autoGenerate": false | ||
}, | ||
"indices": [], | ||
"foreignKeys": [] | ||
}, | ||
{ | ||
"tableName": "MessageRecipient", | ||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`messageId` TEXT NOT NULL, `phoneNumber` TEXT NOT NULL, `state` TEXT NOT NULL, `error` TEXT, PRIMARY KEY(`messageId`, `phoneNumber`), FOREIGN KEY(`messageId`) REFERENCES `Message`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", | ||
"fields": [ | ||
{ | ||
"fieldPath": "messageId", | ||
"columnName": "messageId", | ||
"affinity": "TEXT", | ||
"notNull": true | ||
}, | ||
{ | ||
"fieldPath": "phoneNumber", | ||
"columnName": "phoneNumber", | ||
"affinity": "TEXT", | ||
"notNull": true | ||
}, | ||
{ | ||
"fieldPath": "state", | ||
"columnName": "state", | ||
"affinity": "TEXT", | ||
"notNull": true | ||
}, | ||
{ | ||
"fieldPath": "error", | ||
"columnName": "error", | ||
"affinity": "TEXT", | ||
"notNull": false | ||
} | ||
], | ||
"primaryKey": { | ||
"columnNames": [ | ||
"messageId", | ||
"phoneNumber" | ||
], | ||
"autoGenerate": false | ||
}, | ||
"indices": [], | ||
"foreignKeys": [ | ||
{ | ||
"table": "Message", | ||
"onDelete": "CASCADE", | ||
"onUpdate": "NO ACTION", | ||
"columns": [ | ||
"messageId" | ||
], | ||
"referencedColumns": [ | ||
"id" | ||
] | ||
} | ||
] | ||
} | ||
], | ||
"views": [], | ||
"setupQueries": [ | ||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", | ||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '4a86263b9bb6a736271cc66c6faca254')" | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 72 additions & 0 deletions
72
app/src/main/java/me/capcom/smsgateway/modules/encryption/EncryptionService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package me.capcom.smsgateway.modules.encryption | ||
|
||
import android.util.Base64 | ||
import javax.crypto.Cipher | ||
import javax.crypto.SecretKey | ||
import javax.crypto.SecretKeyFactory | ||
import javax.crypto.spec.IvParameterSpec | ||
import javax.crypto.spec.PBEKeySpec | ||
import javax.crypto.spec.SecretKeySpec | ||
|
||
class EncryptionService( | ||
private val settings: EncryptionSettings, | ||
) { | ||
fun decrypt(encryptedText: String): String { | ||
val chunks = encryptedText.split('$') | ||
if (chunks.size < 5) | ||
throw RuntimeException("Invalid encrypted data format") | ||
|
||
if (chunks[1] != "aes-256-cbc/pbkdf2-sha1") { | ||
throw RuntimeException("Unsupported algorithm") | ||
} | ||
|
||
val params = parseParams(chunks[2]) | ||
if (!params.containsKey("i")) { | ||
throw RuntimeException("Missing iteration count") | ||
} | ||
|
||
val salt = decode(chunks[3]) | ||
val text = chunks[4] | ||
|
||
val passphrase = requireNotNull(settings.passphrase) { "Passphrase is not set" } | ||
val secretKey = generateSecretKeyFromPassphrase( | ||
passphrase.toCharArray(), | ||
salt, | ||
256, | ||
params.getValue("i").toInt() | ||
) | ||
|
||
return decryptText(text, secretKey, salt) | ||
} | ||
|
||
private fun decryptText(encryptedText: String, secretKey: SecretKey, iv: ByteArray): String { | ||
val ivSpec = IvParameterSpec(iv) | ||
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") | ||
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec) | ||
val encryptedBytes = decode(encryptedText) | ||
val decryptedBytes = cipher.doFinal(encryptedBytes) | ||
return String(decryptedBytes) | ||
} | ||
|
||
private fun decode(input: String): ByteArray { | ||
return Base64.decode(input, Base64.DEFAULT) | ||
} | ||
|
||
private fun generateSecretKeyFromPassphrase( | ||
passphrase: CharArray, | ||
salt: ByteArray, | ||
keyLength: Int = 256, | ||
iterationCount: Int = 300_000 | ||
): SecretKey { | ||
val keySpec = PBEKeySpec(passphrase, salt, iterationCount, keyLength) | ||
val keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1") | ||
val keyBytes = keyFactory.generateSecret(keySpec).encoded | ||
return SecretKeySpec(keyBytes, "AES") | ||
} | ||
|
||
private fun parseParams(params: String): Map<String, String> { | ||
return params.split(',') | ||
.map { it.split('=', limit = 2) } | ||
.associate { it[0] to it[1] } | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
app/src/main/java/me/capcom/smsgateway/modules/encryption/EncryptionSettings.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package me.capcom.smsgateway.modules.encryption | ||
|
||
import me.capcom.smsgateway.modules.settings.KeyValueStorage | ||
import me.capcom.smsgateway.modules.settings.get | ||
|
||
class EncryptionSettings( | ||
private val storage: KeyValueStorage, | ||
) { | ||
var passphrase: String? | ||
get() = storage.get<String>(PASSPHRASE) | ||
set(value) = storage.set(PASSPHRASE, value) | ||
|
||
companion object { | ||
private const val PASSPHRASE = "passphrase" | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
app/src/main/java/me/capcom/smsgateway/modules/encryption/Module.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package me.capcom.smsgateway.modules.encryption | ||
|
||
import org.koin.dsl.module | ||
|
||
val encryptionModule = module { | ||
single { | ||
EncryptionService(get()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.