Skip to content

Commit

Permalink
* version bump
Browse files Browse the repository at this point in the history
* update README
* Hash user inputs with Argon2 KDF before sending it over USB serial
  • Loading branch information
ryanamaral committed Jan 24, 2023
1 parent 5b8c68e commit acb9d4c
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 37 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ TurtlPass Android sends a hash of the user's inputs (App Domain, Account ID, and

**Third-party libraries used in the project:**

[Hilt](https://dagger.dev/hilt/), [Coil](https://github.com/coil-kt/coil), [OkHttp](https://github.com/square/okhttp), [UsbSerial](https://github.com/felHR85/UsbSerial), [Lottie](https://github.com/airbnb/lottie-android), etc.
[Hilt](https://dagger.dev/hilt/), [Coil](https://github.com/coil-kt/coil), [OkHttp](https://github.com/square/okhttp), [UsbSerial](https://github.com/felHR85/UsbSerial), [Argon2](https://github.com/lambdapioneer/argon2kt), [Lottie](https://github.com/airbnb/lottie-android), etc.

**Libraries used in the Unit Tests:**

Expand All @@ -58,7 +58,6 @@ TurtlPass Android sends a hash of the user's inputs (App Domain, Account ID, and

* Add support for Browser Apps
* Read NDEF message ID from an external NFC Tag
* Hash user inputs with Argon2 instead of SHA-512


## 📦 Lottie Animations
Expand Down
5 changes: 3 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ android {
applicationId = "com.turtlpass"
minSdk = internal.Android.minSdk
targetSdk = internal.Android.targetSdk
versionCode = 10200
versionName = "1.2.0"
versionCode = 10300
versionName = "1.3.0"
vectorDrawables { useSupportLibrary = true }
missingDimensionStrategy("device", "anyDevice")
buildConfigField("Long", "TIMEOUT_MILLIS", "5000L")
Expand Down Expand Up @@ -107,6 +107,7 @@ dependencies {
}
internal.Dependencies.security.apply {
implementation(crypto)
implementation(argon2)
}
internal.Dependencies.other.apply {
implementation(appcompat)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ object Security {
* [Crypto](https://developer.android.com/jetpack/androidx/releases/security)
*/
const val crypto = "androidx.security:security-crypto:${Versions.securityCrypto}"
const val argon2 = "com.lambdapioneer.argon2kt:argon2kt:1.3.0"
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package com.turtlpass.module.chooser.usecase

import androidx.annotation.Keep
import com.lambdapioneer.argon2kt.Argon2Kt
import com.lambdapioneer.argon2kt.Argon2Mode
import com.lambdapioneer.argon2kt.Argon2Version
import com.turtlpass.di.IoDispatcher
import com.turtlpass.module.chooser.model.ChooserInputs
import com.turtlpass.module.useraccount.repo.AccountIdRepository
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import timber.log.Timber
import java.security.MessageDigest
import javax.inject.Inject
import kotlin.system.measureTimeMillis

class HashUserInputUseCase @Inject constructor(
@IoDispatcher private val dispatcher: CoroutineDispatcher,
Expand All @@ -19,25 +24,41 @@ class HashUserInputUseCase @Inject constructor(
operator fun invoke(chooserInputs: ChooserInputs): Flow<String> {
return flow {
val packageName = chooserInputs.installedApp?.packageName ?: ""
val accountId = chooserInputs.userAccount?.accountId ?: ""
val pin = chooserInputs.pin ?: ""
val topLevelDomain = chooserInputs.installedApp?.topLevelDomain ?: ""
val accountId = chooserInputs.userAccount?.accountId ?: ""
val salt = sha512(topLevelDomain + accountId)
accountRepository.persistAccountId(packageName, accountId)
val hash = sha512(pin + topLevelDomain + accountId)
delay(2000L)
emit(hash)
val argon2duration = measureTimeMillis {
val hash = Argon2Kt().kdf(
pin = pin,
salt = salt
)
emit(hash)
}
Timber.i("Argon2 took $argon2duration milliseconds")
}.catch {
emit("")
}.flowOn(dispatcher)
}
}

fun sha512(string: String): String {
return MessageDigest.getInstance("SHA-512")
.digest(string.toByteArray())
.joinToString(separator = "") {
((it.toInt() and 0xff) + 0x100)
.toString(16)
.substring(1)
}
}
@Keep
fun Argon2Kt.kdf(pin: String, salt: String): String = hash(
mode = Argon2Mode.ARGON2_I, // optimized for password hashing
password = pin.toByteArray(),
salt = salt.toByteArray(),
tCostInIterations = 32, // number of iterations
parallelism = 4, // number of threads in parallel
mCostInKibibyte = 65536, // 64 MiB memory cost
hashLengthInBytes = 64,
version = Argon2Version.V13
).rawHashAsHexadecimal()

fun sha512(string: String): String = MessageDigest.getInstance("SHA-512")
.digest(string.toByteArray())
.joinToString(separator = "") {
((it.toInt() and 0xff) + 0x100)
.toString(16)
.substring(1)
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,7 @@
package com.turtlpass.module.chooser.usecase

import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import com.turtlpass.module.chooser.model.ChooserInputs
import com.turtlpass.module.installedapp.model.InstalledApp
import com.turtlpass.module.useraccount.model.UserAccount
import com.turtlpass.module.useraccount.repo.AccountIdRepository
import com.turtlpass.rule.StandardCoroutineRule
import com.turtlpass.rule.runTest
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runCurrent
import org.junit.Rule
import org.junit.jupiter.api.Test

@ExperimentalCoroutinesApi
//FIXME: Write instrumentation test as Argon2Kt cannot be unit tested
/*@ExperimentalCoroutinesApi
class HashUserInputUseCaseTest {
@get:Rule var standardCoroutineRule = StandardCoroutineRule()
Expand Down Expand Up @@ -57,4 +41,4 @@ class HashUserInputUseCaseTest {
}
}
}
}
}*/
6 changes: 6 additions & 0 deletions fastlane/metadata/android/en-US/changelogs/10300.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
TurtlPass Android version 1.3.0 is now available for download! This update includes the following:

- Hash user inputs with Argon2 KDF before sending it over USB serial
- Added metadata for F-Droid

Upgrade your online security game with TurtlPass. We hope you continue to enjoy our product and look forward to hearing your feedback and bringing you even more exciting features and improvements in the future. Thank you for choosing the ultimate password solution.

0 comments on commit acb9d4c

Please sign in to comment.