Secure Vault
Secure Vault lets an application obtain a base KDK (Key Derivation Key) after a successful strong user authentication. The base KDK is not an encryption or MAC key and cannot be used directly — instead, the application can derive purpose-specific keys from it. This functionality is available only when the activation is already on protocol version 4.0.
Use Secure Vault when you need a stable, high-entropy root for deriving multiple scoped keys (encryption, MAC, wrapping keys, etc.) tied to the user’s successful strong authentication, without persisting those child keys. The PowerAuth Mobile SDK guarantees that the base KDKs remain stable during the lifetime of an activation.
Key identifiers
Two base KDKs are available, depending on the authentication factors used:
KNOWLEDGE- available after successful authentication with possession + knowledge factors.KNOWLEDGE_OR_BIOMETRY- available after any successful 2FA authentication. This key is at least as strong asKNOWLEDGEand can be used wherever a biometry-backed flow is acceptable.
Obtaining the “KNOWLEDGE” base KDK
// 2FA authentication. It uses device-related key and user PIN code.
val authentication = PowerAuthAuthentication.possessionWithPassword("1234")
val keyIdentifier = PowerAuthSecureVaultKeyId.KNOWLEDGE
// Fetch the encryption key with the given index
powerAuthSDK.fetchSecureVaultKey(context, authentication, keyIdentifier, object: IFetchSecureVaultKeyListener {
override fun onFetchSecureVaultKeySucceed(vaultKey: PowerAuthSecureVaultKey) {
// Derive a 32-byte key
val derivedKey = vaultKey.deriveKey(1000, 32)
val keyData = derivedKey.sensitiveData
}
override fun onFetchSecureVaultKeyFailed(throwable: Throwable) {
// Report error
}
})
Obtaining the “KNOWLEDGE_OR_BIOMETRY” base KDK
// 2FA authentication. It uses device-related key and user PIN code.
// Alternatively, you can obtain authentication object with biometric authentication
// using authenticateUsingBiometrics() function.
val authentication = PowerAuthAuthentication.possessionWithPassword("1234")
val keyIdentifier = PowerAuthSecureVaultKeyId.KNOWLEDGE_OR_BIOMETRY
// Fetch the encryption key with the given index
powerAuthSDK.fetchSecureVaultKey(context, authentication, keyIdentifier, object: IFetchSecureVaultKeyListener {
override fun onFetchSecureVaultKeySucceed(vaultKey: PowerAuthSecureVaultKey) {
// Derive a 32-byte key
val derivedKey = vaultKey.deriveKey(1000, 32)
val keyData = derivedKey.sensitiveData
}
override fun onFetchSecureVaultKeyFailed(throwable: Throwable) {
// Report error
}
})
Security Recommendations
- Do not store derived keys on the device. Always acquire the base KDK when needed and derive the keys for each specific purpose.
- Destroy the base KDK as soon as possible.
- Never reuse a derived key for multiple purposes (e.g., don’t use one key for both encryption and authentication).
- When encrypting different data sets, derive a new key with a different index.
- If your application uses multiple keys, maintain a registry of derivation indices to avoid accidental key reuse.
Obtaining Legacy Encryption Key
If your activation is still using PowerAuth protocol 3.3, you can obtain the legacy encryption key as follows:
// 2FA authentication. It uses device-related key and user PIN code.
val authentication = PowerAuthAuthentication.possessionWithPassword("1234")
// Select custom key index
val index = 1000L
// Fetch the encryption key with the given index
powerAuthSDK.fetchEncryptionKey(context, authentication, index, object: IFetchEncryptionKeyListener {
override fun onFetchEncryptionKeySucceed(encryptionKey: SecureData) {
// ... use the encryption key to encrypt or decrypt data
val keyBytes = encryptionKey.sensitiveData
}
override fun onFetchEncryptionKeyFailed(t: Throwable) {
// Report error
}
})
This function is useful if you still have local data encrypted with a key generated by an older SDK version. It is recommended to decrypt the data with the old key and re-encrypt it using the new key, acquired via the fetchSecureVaultKey() function.