Skip to content

Implement DocumentManagerSdJwt #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ mockito-android = "4.0.0"
mockito-inline = "4.0.0"
mockk = "1.13.5"
nimbus-sdk = "11.8"
securityCrypto = "1.1.0-alpha06"
sonarqube = "4.4.1.3373"
test-core = "1.4.0"
test-rules = "1.4.0"
Expand Down Expand Up @@ -62,6 +63,7 @@ mockito-inline = { module = "org.mockito:mockito-inline", version.ref = "mockito
mockito-kotlin = { module = "org.mockito.kotlin:mockito-kotlin", version.ref = "mockito-inline" }
mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
nimbus-oauth2-oidc-sdk = { module = "com.nimbusds:oauth2-oidc-sdk", version.ref = "nimbus-sdk" }
security-crypto = { module = "androidx.security:security-crypto", version.ref = "securityCrypto" }
test-core = { module = "androidx.test:core", version.ref = "test-core" }
test-coreKtx = { module = "androidx.test:core-ktx", version.ref = "test-core" }
test-rules = { module = "androidx.test:rules", version.ref = "test-rules" }
Expand Down
1 change: 1 addition & 0 deletions wallet-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ dependencies {

//sdjwt
api libs.eudi.lib.jvm.sdjwt.kt
implementation libs.security.crypto

testImplementation libs.junit
testImplementation libs.junit.jupiter.params
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ object EudiWallet : KeyGenerator by KeyGeneratorImpl {
fun init(context: Context, config: EudiWalletConfig) {
this.context = context.applicationContext
this._config = config
DocumentManagerSdJwt.init(context, config.userAuthenticationRequired)
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,76 @@
package eu.europa.ec.eudi.wallet.issue.openid4vci

class DocumentManagerSdJwt {
import android.content.Context
import eu.europa.ec.eudi.wallet.util.getEncryptedSharedPreferences
import org.json.JSONException
import org.json.JSONObject
import java.util.Base64

private val documents: Map<String, String> = mapOf() //SHARED PREFS
object DocumentManagerSdJwt {
private lateinit var dataStore: SdJwtDocumentDataStore

private val testDocument =
"""eyJ4NWMiOlsiTUlJQ2REQ0NBaHVnQXdJQkFnSUJBakFLQmdncWhrak9QUVFEQWpDQmlERUxNQWtHQTFVRUJoTUNSRVV4RHpBTkJnTlZCQWNNQmtKbGNteHBiakVkTUJzR0ExVUVDZ3dVUW5WdVpHVnpaSEoxWTJ0bGNtVnBJRWR0WWtneEVUQVBCZ05WQkFzTUNGUWdRMU1nU1VSRk1UWXdOQVlEVlFRRERDMVRVRkpKVGtRZ1JuVnVhMlVnUlZWRVNTQlhZV3hzWlhRZ1VISnZkRzkwZVhCbElFbHpjM1ZwYm1jZ1EwRXdIaGNOTWpRd05UTXhNRGd4TXpFM1doY05NalV3TnpBMU1EZ3hNekUzV2pCc01Rc3dDUVlEVlFRR0V3SkVSVEVkTUJzR0ExVUVDZ3dVUW5WdVpHVnpaSEoxWTJ0bGNtVnBJRWR0WWtneENqQUlCZ05WQkFzTUFVa3hNakF3QmdOVkJBTU1LVk5RVWtsT1JDQkdkVzVyWlNCRlZVUkpJRmRoYkd4bGRDQlFjbTkwYjNSNWNHVWdTWE56ZFdWeU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRU9GQnE0WU1LZzR3NWZUaWZzeXR3QnVKZi83RTdWaFJQWGlObTUyUzNxMUVUSWdCZFh5REsza1Z4R3hnZUhQaXZMUDN1dU12UzZpREVjN3FNeG12ZHVLT0JrRENCalRBZEJnTlZIUTRFRmdRVWlQaENrTEVyRFhQTFcyL0owV1ZlZ2h5dyttSXdEQVlEVlIwVEFRSC9CQUl3QURBT0JnTlZIUThCQWY4RUJBTUNCNEF3TFFZRFZSMFJCQ1l3SklJaVpHVnRieTV3YVdRdGFYTnpkV1Z5TG1KMWJtUmxjMlJ5ZFdOclpYSmxhUzVrWlRBZkJnTlZIU01FR0RBV2dCVFVWaGpBaVRqb0RsaUVHTWwyWXIrcnU4V1F2akFLQmdncWhrak9QUVFEQWdOSEFEQkVBaUFiZjVUemtjUXpoZldvSW95aTFWTjdkOEk5QnNGS20xTVdsdVJwaDJieUdRSWdLWWtkck5mMnhYUGpWU2JqVy9VLzVTNXZBRUM1WHhjT2FudXNPQnJvQmJVPSIsIk1JSUNlVENDQWlDZ0F3SUJBZ0lVQjVFOVFWWnRtVVljRHRDaktCL0gzVlF2NzJnd0NnWUlLb1pJemowRUF3SXdnWWd4Q3pBSkJnTlZCQVlUQWtSRk1ROHdEUVlEVlFRSERBWkNaWEpzYVc0eEhUQWJCZ05WQkFvTUZFSjFibVJsYzJSeWRXTnJaWEpsYVNCSGJXSklNUkV3RHdZRFZRUUxEQWhVSUVOVElFbEVSVEUyTURRR0ExVUVBd3d0VTFCU1NVNUVJRVoxYm10bElFVlZSRWtnVjJGc2JHVjBJRkJ5YjNSdmRIbHdaU0JKYzNOMWFXNW5JRU5CTUI0WERUSTBNRFV6TVRBMk5EZ3dPVm9YRFRNME1EVXlPVEEyTkRnd09Wb3dnWWd4Q3pBSkJnTlZCQVlUQWtSRk1ROHdEUVlEVlFRSERBWkNaWEpzYVc0eEhUQWJCZ05WQkFvTUZFSjFibVJsYzJSeWRXTnJaWEpsYVNCSGJXSklNUkV3RHdZRFZRUUxEQWhVSUVOVElFbEVSVEUyTURRR0ExVUVBd3d0VTFCU1NVNUVJRVoxYm10bElFVlZSRWtnVjJGc2JHVjBJRkJ5YjNSdmRIbHdaU0JKYzNOMWFXNW5JRU5CTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFWUd6ZHdGRG5jNytLbjVpYkF2Q09NOGtlNzdWUXhxZk1jd1pMOElhSUErV0NST2NDZm1ZL2dpSDkycU1ydTVwL2t5T2l2RTBSQy9JYmRNT052RG9VeWFObU1HUXdIUVlEVlIwT0JCWUVGTlJXR01DSk9PZ09XSVFZeVhaaXY2dTd4WkMrTUI4R0ExVWRJd1FZTUJhQUZOUldHTUNKT09nT1dJUVl5WFppdjZ1N3haQytNQklHQTFVZEV3RUIvd1FJTUFZQkFmOENBUUF3RGdZRFZSMFBBUUgvQkFRREFnR0dNQW9HQ0NxR1NNNDlCQU1DQTBjQU1FUUNJR0VtN3drWktIdC9hdGI0TWRGblhXNnlybndNVVQydTEzNmdkdGwxMFk2aEFpQnVURnF2Vll0aDFyYnh6Q1AweFdaSG1RSzlrVnl4bjhHUGZYMjdFSXp6c3c9PSJdLCJraWQiOiJNSUdVTUlHT3BJR0xNSUdJTVFzd0NRWURWUVFHRXdKRVJURVBNQTBHQTFVRUJ3d0dRbVZ5YkdsdU1SMHdHd1lEVlFRS0RCUkNkVzVrWlhOa2NuVmphMlZ5WldrZ1IyMWlTREVSTUE4R0ExVUVDd3dJVkNCRFV5QkpSRVV4TmpBMEJnTlZCQU1NTFZOUVVrbE9SQ0JHZFc1clpTQkZWVVJKSUZkaGJHeGxkQ0JRY205MGIzUjVjR1VnU1hOemRXbHVaeUJEUVFJQkFnPT0iLCJ0eXAiOiJ2YytzZC1qd3QiLCJhbGciOiJFUzI1NiJ9.eyJwbGFjZV9vZl9iaXJ0aCI6eyJfc2QiOlsiUDZiLUxnTk9fRUlpNm5ubmRCbW1wS1FIdDVvTlBpLVVsWldGRmU4VnFDMCJdfSwiX3NkIjpbIi1sOFBnZ2hLdEFmZUFwZXRDOEZGS0lfcGFlVkV4bmY4dFpJZzZCQ205TlkiLCJDSEhVb1JySFhIbXNvbHVEbEtqMWF1X3RmTEVKUmYzUUszVzFLZkVXYUlZIiwiQ1cwbVBFblFMMnhZYWxEbXBRLS11Vkg5bEM1cG1MU1JEeTdjblRBU0FfNCIsIkd5dEtxYzM0SHM2UjAtTEpMWVNYOUJVSGloZi1kbmtoYV9KM1NlQWN2M0EiLCJOZGZkeEJWY0Q4Smo5MHIyUUxFamhvMkpDTjRPWWRxeG1KcGs0S1hmVlp3IiwiZDJjNDdxZ3pGR1lDR194dFFYYVNEeEdueWpwZXFrRk16bV92MDVERjFOSSIsIm1zVW1QVEE4ZE1rRFRvam43cm5waFEzRnpjN3k4NkptT1NkX2NaWWdKQXMiXSwiYWRkcmVzcyI6eyJfc2QiOlsiQ2ZtTlY3WVNfMURod3NIUi1scWRScXAtT1NETFpVS2FBR3F3eHhMdzZTOCIsIkt0VjdoblFuNXdINVlIYXBfajhXX3BmMlJnV2x1LWZFSTd6VTNLOWo4NGsiLCJid19TVUtCWERnVDVYdE04Z1l3OFVvY05pV0JTNDN3T1lXazZGMjZQRlY0IiwiekRSTndDMkV0UUZoaWVpRmJtUEtiYy1ISU5nZnZ6SnpGSi1qUFdhOHdtMCJdfSwiaXNzdWluZ19jb3VudHJ5IjoiREUiLCJ2Y3QiOiJ1cm46ZXUuZXVyb3BhLmVjLmV1ZGk6cGlkOjEiLCJpc3N1aW5nX2F1dGhvcml0eSI6IkRFIiwiX3NkX2FsZyI6InNoYS0yNTYiLCJpc3MiOiJodHRwczovL2RlbW8ucGlkLWlzc3Vlci5idW5kZXNkcnVja2VyZWkuZGUvYyIsImNuZiI6eyJqd2siOnsia3R5IjoiRUMiLCJjcnYiOiJQLTI1NiIsIngiOiJUZVdfdEJIM01KM3M4RHA3NE1oMWtWdUNvWURMaGlIMW56dFcxVnVUcEpRIiwieSI6IkdtRFVXQXVibmQxbHlnUEJSX1ZvVUt0YkR6SEYtNFBma3daQjhwMnU4SUEifX0sImV4cCI6MTcyMzYxNjc1MSwiaWF0IjoxNzIyNDA3MTUxLCJhZ2VfZXF1YWxfb3Jfb3ZlciI6eyJfc2QiOlsiM1pqTUJkM1pRbThGYzFtQmwtZC1PLVFJaTA3YkpjY3lzNDlqaFlPNVJVYyIsIjY3YVN5dzJGenVaQjVJZXV6Q1V1VXNuVml5T3owUDBCckdQMzFhbGtCbjAiLCJDZkQ1MEstcHRwaXpGQnB2cE8yWFhyaVFfRzdWcGIxRDB3bGdjUHpUSlQ0IiwiSW1qU0I2Z2lhMDhZeXhRUFBfcXp5d1FFamcwU254R1ZxWlVfTl9FVFl2SSIsIlExZ1ZOSWtIYWU0ZGdmY2RoSUwwTEZIckdSX3dBZUpRT0ZwbTljbXBaREUiLCJYY290cHIzV3Q5U21jUjZDSzhtMlBPRE5zRXBDWnRRelZGT1N3UnJ5QXMwIl19fQ.xqQyzeKALOWVnmJBx7BjH8YBdwu-5H51f6dkUkXsp2BcwUDUvo-ni4NVo3cB9FKf-eoCU4e_jJIuYr5o-S003w~WyJHV3JoVGVzaDE4Y191aEgtR01ORFJ3IiwiZmFtaWx5X25hbWUiLCJNVVNURVJNQU5OIl0~WyJaZGRMRzhBd0dDWTF3Sm9qWmkweEpBIiwiZ2l2ZW5fbmFtZSIsIkVSSUtBIl0~WyJIWHVBd3JXaXVBT01hN0JfZ2ZVZlhnIiwiYmlydGhkYXRlIiwiMTk4NC0wMS0yNiJd~WyJFcVAtNnY5eVdZOGdKSmItMFVLMUh3IiwiYWdlX2JpcnRoX3llYXIiLDE5ODRd~WyJEMTdfUGxGdHlDVml0V3JvaTJ5bEtRIiwiYWdlX2luX3llYXJzIiw0MF0~WyJiMkp3ZjZhakN1eXoyWmxfUDd3bnZ3IiwiYmlydGhfZmFtaWx5X25hbWUiLCJHQUJMRVIiXQ~WyJBUzZNRjJrZFVBdmQ5S1p0Wnl3N1FnIiwibmF0aW9uYWxpdGllcyIsWyJERSJdXQ~WyJFWmVrOFMxMUlBNUZwVG1Iem1mTW5BIiwiMTIiLHRydWVd~WyJLcEdrWW85SzA2NThyZnVyZHJPLUJRIiwiMTQiLHRydWVd~WyJqQkRBVzdsWWRrUVNvRUV2c2hfMm1BIiwiMTYiLHRydWVd~WyItTUc3M3hwNUhnOHpBRFVaNU9lN1B3IiwiMTgiLHRydWVd~WyJiMGNwT0ZxT0lVeW53cDdma0ZoN3RRIiwiMjEiLHRydWVd~WyJZS3o1SUZPQk5mZHc4R2JhU3l1TlJ3IiwiNjUiLGZhbHNlXQ~WyJMNHY3ajc1N2poS1BPX2xtTmMxQ0dnIiwibG9jYWxpdHkiLCJCRVJMSU4iXQ~WyJIVEVzdmZpZEtBTXV2aFdFbW9DN25nIiwibG9jYWxpdHkiLCJLw5ZMTiJd~WyJfWDMtalZFMWdkWWlTNmY0RGhFU3V3IiwiY291bnRyeSIsIkRFIl0~WyI5b1huQTNBM01PWGZhbV9jdzZ5N1ZBIiwicG9zdGFsX2NvZGUiLCI1MTE0NyJd~WyJGNzNmMThYSnpWbzYtbG1tTzJoUnBnIiwic3RyZWV0X2FkZHJlc3MiLCJIRUlERVNUUkFTU0UgMTciXQ~"""
fun init(context: Context, requiresUserAuth: Boolean) {
dataStore = SdJwtDocumentDataStore(context, requiresUserAuth)
}

fun getDocumentById(id: String): SdJwtDocument {
TODO()
fun storeDocument(id: String, credentials: String) {
dataStore.add(id, credentials)
}

fun getAllDocuments(): List<SdJwtDocument> {
TODO()
fun getDocumentById(id: String) = dataStore.get(id)

fun getAllDocuments() = dataStore.getAll()
}

data class SdJwtDocument(
val id: String,
val vct: String,
val docName: String,
val requiresUserAuth: Boolean,
val data: String,
)

private class SdJwtDocumentDataStore(
context: Context,
val requiresUserAuth: Boolean,
) {
private var sharedPreferences = getEncryptedSharedPreferences(context)

fun add(id: String, credentials: String) {
sharedPreferences.edit().putString(PREFIX_ID + id, credentials).apply()
}

fun storeDocument(id: String, credential: String) {
fun get(id: String) = sharedPreferences.getString(PREFIX_ID + id, null)?.toDocument(id, requiresUserAuth)

fun getAll() = sharedPreferences.all.filter {
it.key.startsWith(PREFIX_ID)
}.mapNotNull {
(it.value as? String)?.toDocument(it.key, requiresUserAuth)
}

private fun makeDocument(id: String, credential: String): SdJwtDocument {
TODO()
private companion object {
private const val PREFIX_ID = "id:"
}
}

private fun String.toDocument(
id: String,
requiresUserAuth: Boolean,
) = try {
val payloadString = split(".")[1]
val payloadJson = JSONObject(String(Base64.getUrlDecoder().decode(payloadString)))

val vct = payloadJson.getString("vct")
val docName = "Personalausweis"
val data = payloadJson.toString()

data class SdJwtDocument(
val id: String,
val data: String //Hier mehr
SdJwtDocument(
id = id,
vct = vct,
docName = docName,
requiresUserAuth = requiresUserAuth,
data = data,
)
} catch (_: JSONException) {
null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package eu.europa.ec.eudi.wallet.util

import android.content.Context
import android.content.SharedPreferences
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import javax.crypto.AEADBadTagException

private const val PREF_FILE_NAME = "secure_prefs"

@Throws(java.security.GeneralSecurityException::class, java.io.IOException::class)
fun getEncryptedSharedPreferences(context: Context): SharedPreferences {
val masterKey: MasterKey = MasterKey
.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()

return try {
createEncryptedSharedPreferences(context, masterKey)
} catch (e: AEADBadTagException) {
clearEncryptedSharedPreferences(context)
createEncryptedSharedPreferences(context, masterKey)
}
}

@Throws(java.security.GeneralSecurityException::class, java.io.IOException::class)
private fun createEncryptedSharedPreferences(
context: Context,
masterKey: MasterKey,
) = EncryptedSharedPreferences.create(
context,
PREF_FILE_NAME,
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

private fun clearEncryptedSharedPreferences(context: Context) {
context.getSharedPreferences(PREF_FILE_NAME, Context.MODE_PRIVATE).edit().clear().apply()
}
Loading