Add argon2kt native implementation to Android (#1241)

This commit is contained in:
Leendert de Borst
2025-09-18 09:37:22 +02:00
committed by Leendert de Borst
parent 81a5155734
commit 952cfd9a28
3 changed files with 64 additions and 0 deletions

View File

@@ -186,6 +186,9 @@ dependencies {
// Add vector drawable support for SVG
implementation("com.caverock:androidsvg-aar:1.4")
// Add Argon2 library for password key derivation
implementation("com.lambdapioneer.argon2kt:argon2kt:1.4.0")
// Test dependencies
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.mockito:mockito-core:4.0.0'

View File

@@ -778,6 +778,27 @@ class NativeVaultManager(reactContext: ReactApplicationContext) :
}
}
/**
* Derive a key from a password using Argon2Id.
* @param password The password to derive from
* @param salt The salt to use
* @param encryptionType The type of encryption (should be "Argon2Id")
* @param encryptionSettings JSON string with encryption parameters
* @param promise The promise to resolve
*/
@ReactMethod
override fun deriveKeyFromPassword(password: String, salt: String, encryptionType: String, encryptionSettings: String, promise: Promise) {
try {
val derivedKey = vaultStore.deriveKeyFromPassword(password, salt, encryptionType, encryptionSettings)
// Return as base64 string
val base64Key = android.util.Base64.encodeToString(derivedKey, android.util.Base64.NO_WRAP)
promise.resolve(base64Key)
} catch (e: Exception) {
Log.e(TAG, "Error deriving key from password", e)
promise.reject("ERR_DERIVE_KEY", "Failed to derive key from password: ${e.message}", e)
}
}
/**
* Open the autofill settings page.
* @param promise The promise to resolve

View File

@@ -6,6 +6,9 @@ import android.os.Handler
import android.os.Looper
import android.util.Base64
import android.util.Log
import com.lambdapioneer.argon2kt.Argon2Kt
import com.lambdapioneer.argon2kt.Argon2Mode
import com.lambdapioneer.argon2kt.Argon2Version
import net.aliasvault.app.vaultstore.interfaces.CredentialOperationCallback
import net.aliasvault.app.vaultstore.interfaces.CryptoOperationCallback
import net.aliasvault.app.vaultstore.keystoreprovider.KeystoreOperationCallback
@@ -240,6 +243,43 @@ class VaultStore(
return this.storageProvider.getKeyDerivationParams()
}
/**
* Derive a key from a password using Argon2Id.
* @param password The password to derive from
* @param salt The salt to use
* @param encryptionType The type of encryption (should be "Argon2Id")
* @param encryptionSettings JSON string with encryption parameters
* @return The derived key as a ByteArray
*/
fun deriveKeyFromPassword(password: String, salt: String, encryptionType: String, encryptionSettings: String): ByteArray {
if (encryptionType != "Argon2Id") {
throw IllegalArgumentException("Unsupported encryption type: $encryptionType")
}
// Parse encryption settings JSON
val settings = JSONObject(encryptionSettings)
val iterations = settings.getInt("Iterations")
val memorySize = settings.getInt("MemorySize")
val parallelism = settings.getInt("DegreeOfParallelism")
// Create Argon2 instance
val argon2 = Argon2Kt()
// Hash the password using Argon2Id
val hashResult = argon2.hash(
mode = Argon2Mode.ARGON2_ID,
password = password.toByteArray(Charsets.UTF_8),
salt = salt.toByteArray(Charsets.UTF_8),
tCostInIterations = iterations,
mCostInKibibyte = memorySize,
parallelism = parallelism,
hashLengthInBytes = 32,
version = Argon2Version.V13,
)
return hashResult.rawHashAsByteArray()
}
/**
* Store the encrypted database in the storage provider.
* @param encryptedData The encrypted database as a base64 encoded string