Storage
Add the ability to store document​
In this section (Storage folder), you’ll set up the components needed to manage secure credentials using the multipaz SDK. The classes that handles the storage part of the identity includes:
-
Storage
: Local data storage that will hold the data items. Implementations for both Android and iOS are provided by Multipaz. -
SecureArea
: An abstraction for cryptographic key handling. On Android, this uses the Keystore; on iOS, it uses the Secure Enclave. -
SecureAreaRepository
: A registry of availableSecureArea
implementations, it controls for “SecureArea” implementation -
DocumentStore
: ​​Class for storing real-world identity documents.
We’ll guide you through integrating and initializing these components in your KMP app.
Step 1: Initialize Storage
​
In your UI code in App.kt, call the following to obtain a Storage instance suitable for the platform, ensuring that the data is not backed up(We do not want our database to be backed-up as it is useless without private keys,in the secure area (which are not, and cannot be backed-up),this function ensures the database file is excluded from Android's backup system:
//TODO : storage = Platform.nonBackedUpStorage
storage = Platform.nonBackedUpStorage()
Step 3: Create a SecureArea
​
This code is in App.kt. SecureArea suitable for the platform to represent cryptographic key containers. For example, they can leverage the Android Keystore or use SecureEnclaveSecureArea in iOS.
//TODO: secureArea = Platform.getSecureArea()
secureArea = Platform.getSecureArea()
The Platform.getSecureArea() function returns platform-specific secure area implementations that use hardware-backed key storage:in android it is Android Keystore system, in iOS,it is SecureEnclaveSecureArea
Step 4: Register it in a SecureAreaRepository
​
Create a secureAreaRepository that manages secure area implementations.This code is located in App.kt:
//TODO: secureAreaRepository = SecureAreaRepository.Builder().add(secureArea).build()
secureAreaRepository = SecureAreaRepository.Builder()
.add(secureArea)
.build()
Step 5: Initialize the DocumentStore
​
In App.kt, DocumentStore is the main API used to create, list, and manage verifiable documents. It connects your Storage and SecureAreaRepository.
*//TODO: documentStore = buildDocumentStore(storage = storage, secureAreaRepository = secureAreaRepository) {}*
documentStore = buildDocumentStore(
storage = storage,
secureAreaRepository = secureAreaRepository
) {}
Once initialized, you can start interacting with the store to create, delete, or retrieve documents.
Step 6: Create a new Document​
In App.kt, You can create a simple Document
like this:
val profile = ByteString(
getDrawableResourceBytes(
getSystemResourceEnvironment(),
Res.drawable.profile
)
)
//TODO: document = documentStore.createDocument(*
// displayName ="Tom Lee's Utopia Membership",
// typeDisplayName = "Membership Card",
// cardArt = profile,
// other = UtopiaMemberInfo().toJsonString().encodeToByteString(),
// )
document = documentStore.createDocument(
displayName ="Tom Lee's Utopia Membership",
typeDisplayName = "Membership Card",
cardArt = profile,
other = UtopiaMemberInfo().toJsonString().encodeToByteString(),
)
“Res.drawable.proifle”: here add a profile.png in “/src/commonMain/composeResources/drawable” folder
Step 7: Fetch and Display Documents​
In App.kt, get documents IDs in the DocumentStore
:
val listIDs = documentStore.listDocuments().
Create Credential​
A document is a container that holds multiple credentials and represents an identity document (like a driver's license or passport). Credential is the actual cryptographic proof within a document that can be presented to verifiers.
We will discuss how to create a credential and bind it to the document created above.
In App.kt
Step 1: Establish validity times​
val now = Clock.System.now()
val signedAt = now
val validFrom = now
val validUntil = now + 365.days
now is captured from the system clock. The credential is considered signed at signedAt, becomes valid at validFrom, and remains valid for 365 days (validUntil).
Step 2: Generate the IACA certificate​
“generateIacaCertificate” creates a self‑signed Issuing Authority Certificate Authority (IACA) certificate.
val iacaKey = Crypto.createEcPrivateKey(EcCurve.P256)
val iacaCert = MdocUtil.generateIacaCertificate(
iacaKey = iacaKey,
subject = X500Name.fromName(name = "CN=Test IACA Key"),
serial = ASN1Integer.fromRandom(numBits = 128),
validFrom = validFrom,
validUntil = validUntil,
issuerAltNameUrl = "https://issuer.example.com",
crlUrl = "https://issuer.example.com/crl"
)
Step 3: Generate the DS certificate​
“generateDsCertificate” issues a Document Signing (DS) certificate from the IACA key. Its parameters are:
val dsKey = Crypto.createEcPrivateKey(EcCurve.P256)
val dsCert = MdocUtil.generateDsCertificate(
iacaCert = iacaCert,
iacaKey = iacaKey,
dsKey = dsKey.publicKey,
subject = X500Name.fromName(name = "CN=Test DS Key"),
serial = ASN1Integer.fromRandom(numBits = 128),
validFrom = validFrom,
validUntil = validUntil
)
Step 4: Create the credential with sample data​
“createMdocCredentialWithSampleData” adds an MdocCredential to the document using the specified secureArea.
val mdocCredential =
DrivingLicense.getDocumentType().createMdocCredentialWithSampleData(
document = document,
secureArea = secureArea,
createKeySettings = CreateKeySettings(
algorithm = Algorithm.ESP256,
nonce = "Challenge".encodeToByteString(),
userAuthenticationRequired = true
),
dsKey = dsKey,
dsCertChain = X509CertChain(listOf(dsCert)),
signedAt = signedAt,
validFrom = validFrom,
validUntil = validUntil,
)
Step 5: Start exporting credential​
Now the credentials exist in your documents, however, they won't be accessible through Android/ios credential manager system. In order to be accessed by the credential manager system, you need to export the credentials
if (DigitalCredentials.Default.available) {
//TODO: DigitalCredentials.Default.startExportingCredentials(
// documentStore = documentStore,
// documentTypeRepository = documentTypeRepository*
// )
DigitalCredentials.Default.startExportingCredentials(
documentStore = documentStore,
documentTypeRepository = documentTypeRepository
)
}