Key Management
The IDK provides a unified key management system through the KeyManagerService. This service abstracts the details of different key storage backends, allowing you to generate, store, and use cryptographic keys consistently across platforms and providers.
KeyManagerService Overview
The KeyManagerService is the central entry point for all cryptographic key operations. It delegates actual key operations to registered KMS providers while presenting a consistent interface.
Key capabilities include:
- Key generation with configurable algorithms
- Key storage and retrieval
- Signing and verification operations
- Encryption and decryption
- Key wrapping and unwrapping
- Key agreement for establishing shared secrets
- Provider capability querying
Accessing the Service
The KeyManagerService is available from the session component:
- Android/Kotlin
- iOS/Swift
val keyManager = session.component.keyManagerService
let keyManager = session.component.keyManagerService
Generating Keys
Generate cryptographic key pairs using the generateKeyAsync method:
- Android/Kotlin
- iOS/Swift
import com.sphereon.crypto.core.SignatureAlgorithm
import com.sphereon.crypto.jose.JwkUse
import com.sphereon.crypto.core.KeyOperations
// Generate an ECDSA P-256 signing key
val signingKeyPair = keyManager.generateKeyAsync(
providerId = null, // Use default provider
alias = "my-signing-key",
use = JwkUse.sig,
keyOperations = arrayOf(KeyOperations.SIGN, KeyOperations.VERIFY),
alg = SignatureAlgorithm.ECDSA_SHA256,
keyVisibility = KeyVisibility.PRIVATE
)
// Generate with a specific provider
val awsKeyPair = keyManager.generateKeyAsync(
providerId = "aws",
alias = "my-aws-key",
use = JwkUse.sig,
alg = SignatureAlgorithm.ECDSA_SHA256
)
import SphereonCrypto
// Generate an ECDSA P-256 signing key
let signingKeyPair = try await keyManager.generateKeyAsync(
providerId: nil, // Use default provider
alias: "my-signing-key",
use: .sig,
keyOperations: [.sign, .verify],
alg: .ecdsaSha256,
keyVisibility: .private_
)
// Generate with a specific provider
let awsKeyPair = try await keyManager.generateKeyAsync(
providerId: "aws",
alias: "my-aws-key",
use: .sig,
alg: .ecdsaSha256
)
Supported Algorithms
The IDK supports the following signature algorithms:
| Algorithm | Description | Curve/Size |
|---|---|---|
ECDSA_SHA256 | ECDSA with SHA-256 | P-256 |
ECDSA_SHA384 | ECDSA with SHA-384 | P-384 |
ECDSA_SHA512 | ECDSA with SHA-512 | P-521 |
RSA_SHA256 | RSA PKCS#1 v1.5 with SHA-256 | 2048+ bits |
RSA_SHA384 | RSA PKCS#1 v1.5 with SHA-384 | 2048+ bits |
RSA_SHA512 | RSA PKCS#1 v1.5 with SHA-512 | 2048+ bits |
RSA_SSA_PSS_SHA256_MGF1 | RSA-PSS with SHA-256 | 2048+ bits |
RSA_SSA_PSS_SHA384_MGF1 | RSA-PSS with SHA-384 | 2048+ bits |
RSA_SSA_PSS_SHA512_MGF1 | RSA-PSS with SHA-512 | 2048+ bits |
ManagedKeyPair
After generating a key, you receive a ManagedKeyPair containing both COSE and JOSE representations:
- Android/Kotlin
- iOS/Swift
// ManagedKeyPair contains both formats
val keyPair: ManagedKeyPair = keyManager.generateKeyAsync(...)
// Access COSE format
val cosePublicKey = keyPair.cose.publicCoseKey
val cosePrivateKey = keyPair.cose.privateCoseKey // May be null for hardware keys
// Access JOSE/JWK format
val publicJwk = keyPair.jose.publicJwk
val privateJwk = keyPair.jose.privateJwk // May be null for hardware keys
// Key identifiers
val kid = keyPair.kid
val alias = keyPair.alias
val providerId = keyPair.providerId
// ManagedKeyPair contains both formats
let keyPair: ManagedKeyPair = try await keyManager.generateKeyAsync(...)
// Access COSE format
let cosePublicKey = keyPair.cose.publicCoseKey
let cosePrivateKey = keyPair.cose.privateCoseKey // May be nil for hardware keys
// Access JOSE/JWK format
let publicJwk = keyPair.jose.publicJwk
let privateJwk = keyPair.jose.privateJwk // May be nil for hardware keys
// Key identifiers
let kid = keyPair.kid
let alias = keyPair.alias
let providerId = keyPair.providerId
Key Info Types
The IDK provides different key info types for different use cases:
- Android/Kotlin
- iOS/Swift
// Convert to ManagedKeyInfo for COSE operations
val coseKeyInfo: ManagedKeyInfoType<CoseKeyType> = keyPair.cborToManagedKeyInfo(
visibility = KeyVisibility.PUBLIC
)
// Convert to ManagedKeyInfo for JOSE operations
val joseKeyInfo: ManagedKeyInfoType<JwkType> = keyPair.joseToManagedKeyInfo(
visibility = KeyVisibility.PUBLIC
)
// Generic conversion with encoding specification
val keyInfo = keyPair.toManagedKeyInfo<CoseKeyType>(
visibility = KeyVisibility.PRIVATE,
keyEncoding = KeyEncoding.COSE
)
// Access key info properties
val providerId = keyInfo.providerId
val alias = keyInfo.alias
val signatureAlgorithm = keyInfo.signatureAlgorithm
val x5c = keyInfo.x5c // X.509 certificate chain if available
// Convert to ManagedKeyInfo for COSE operations
let coseKeyInfo: ManagedKeyInfoType = keyPair.cborToManagedKeyInfo(
visibility: .public_
)
// Convert to ManagedKeyInfo for JOSE operations
let joseKeyInfo: ManagedKeyInfoType = keyPair.joseToManagedKeyInfo(
visibility: .public_
)
// Access key info properties
let providerId = keyInfo.providerId
let alias = keyInfo.alias
let signatureAlgorithm = keyInfo.signatureAlgorithm
let x5c = keyInfo.x5c // X.509 certificate chain if available
Signing Data
Create signatures using stored keys:
- Android/Kotlin
- iOS/Swift
// Get key info for signing (needs private key access)
val keyInfo = keyPair.cborToManagedKeyInfo(visibility = KeyVisibility.PRIVATE)
// Sign raw bytes
val data = "Hello, World!".encodeToByteArray()
val signature = keyManager.createRawSignature(
keyInfo = keyInfo,
input = data,
requireX5Chain = false
)
// Sign with X.509 certificate chain requirement
val signatureWithCert = keyManager.createRawSignature(
keyInfo = keyInfo,
input = data,
requireX5Chain = true // Requires associated certificate
)
// Get key info for signing (needs private key access)
let keyInfo = keyPair.cborToManagedKeyInfo(visibility: .private_)
// Sign raw bytes
let data = "Hello, World!".data(using: .utf8)!
let signature = try await keyManager.createRawSignature(
keyInfo: keyInfo,
input: data,
requireX5Chain: false
)
// Sign with X.509 certificate chain requirement
let signatureWithCert = try await keyManager.createRawSignature(
keyInfo: keyInfo,
input: data,
requireX5Chain: true // Requires associated certificate
)
Verifying Signatures
Verify signatures against public keys:
- Android/Kotlin
- iOS/Swift
// Get public key info for verification
val publicKeyInfo = keyPair.cborToManagedKeyInfo(visibility = KeyVisibility.PUBLIC)
// Verify the signature
val isValid = keyManager.isValidRawSignature(
keyInfo = publicKeyInfo,
input = data,
signature = signature
)
if (isValid) {
println("Signature is valid")
} else {
println("Signature verification failed")
}
// Get public key info for verification
let publicKeyInfo = keyPair.cborToManagedKeyInfo(visibility: .public_)
// Verify the signature
let isValid = try await keyManager.isValidRawSignature(
keyInfo: publicKeyInfo,
input: data,
signature: signature
)
if isValid {
print("Signature is valid")
} else {
print("Signature verification failed")
}
Key Retrieval
Retrieve previously generated keys using the key store:
- Android/Kotlin
- iOS/Swift
// List all keys in the key store
val allKeys = keyManager.keyStore.listKeys()
for (keyInfo in allKeys) {
println("Key: ${keyInfo.alias}, Provider: ${keyInfo.providerId}")
}
// Get a specific key
val keyInfo = KeyInfo<CoseKeyType>(
alias = "my-signing-key",
providerId = keyManager.defaultProviderId()
)
val existingKey = keyManager.keyStore.getKey(keyInfo)
// List all keys in the key store
let allKeys = try await keyManager.keyStore.listKeys()
for keyInfo in allKeys {
print("Key: \(keyInfo.alias), Provider: \(keyInfo.providerId)")
}
// Get a specific key
let keyInfo = KeyInfo(
alias: "my-signing-key",
providerId: keyManager.defaultProviderId()
)
let existingKey = try await keyManager.keyStore.getKey(keyInfo: keyInfo)
Key Deletion
Remove keys that are no longer needed:
- Android/Kotlin
- iOS/Swift
// Delete a specific key
val keyInfo = KeyInfo<CoseKeyType>(
alias = "my-signing-key",
providerId = keyManager.defaultProviderId()
)
val deleted = keyManager.keyStore.deleteKey(keyInfo)
if (deleted) {
println("Key deleted successfully")
}
// Delete a specific key
let keyInfo = KeyInfo(
alias: "my-signing-key",
providerId: keyManager.defaultProviderId()
)
let deleted = try await keyManager.keyStore.deleteKey(keyInfo: keyInfo)
if deleted {
print("Key deleted successfully")
}
Provider Management
Query and manage KMS providers:
- Android/Kotlin
- iOS/Swift
// Get default provider ID
val defaultProvider = keyManager.defaultProviderId()
// List all registered providers
val providerIds = keyManager.getProviderIds()
// Get a specific provider
val provider = keyManager.getProviderById("software")
// Find provider by algorithm support
val ecdsaProvider = keyManager.getKmsBySignatureAlgorithm(SignatureAlgorithm.ECDSA_SHA256)
// Query providers by capabilities
val queryResult = keyManager.queryProviderAsync(
KmsProviderQuery(
signatureAlgorithm = SignatureAlgorithm.ECDSA_SHA256,
requireHardwareBacking = true
)
)
when (queryResult) {
is IdkResult.Success -> {
val provider = queryResult.value.provider
println("Found provider: ${provider.id}")
}
is IdkResult.Failure -> {
println("No matching provider found")
}
}
// Get default provider ID
let defaultProvider = keyManager.defaultProviderId()
// List all registered providers
let providerIds = keyManager.getProviderIds()
// Get a specific provider
let provider = keyManager.getProviderById(id: "software")
// Find provider by algorithm support
let ecdsaProvider = keyManager.getKmsBySignatureAlgorithm(
alg: .ecdsaSha256
)
// Query providers by capabilities
let queryResult = try await keyManager.queryProviderAsync(
query: KmsProviderQuery(
signatureAlgorithm: .ecdsaSha256,
requireHardwareBacking: true
)
)
switch queryResult {
case .success(let value):
let provider = value.provider
print("Found provider: \(provider.id)")
case .failure:
print("No matching provider found")
}
Provider Capabilities
Query what operations a provider supports:
- Android/Kotlin
- iOS/Swift
// Get all capabilities from all providers
val capsResult = keyManager.getAllCapabilitiesAsync(includeDisabled = false)
when (capsResult) {
is IdkResult.Success -> {
for (cap in capsResult.value.capabilities) {
println("Provider: ${cap.providerId}")
println(" Storage types: ${cap.storageTypes.joinToString()}")
println(" Supports import: ${cap.supportsKeyImport}")
println(" Supports export: ${cap.supportsKeyExport}")
println(" Hardware backing: ${cap.supportsHardwareBacking}")
println(" Supported curves: ${cap.supportedCurves.joinToString()}")
println(" Supports signing: ${cap.supportsSigning()}")
println(" Supports encryption: ${cap.supportsEncryption()}")
}
}
is IdkResult.Failure -> {
println("Failed to get capabilities")
}
}
// Get all capabilities from all providers
let capsResult = try await keyManager.getAllCapabilitiesAsync(includeDisabled: false)
switch capsResult {
case .success(let value):
for cap in value.capabilities {
print("Provider: \(cap.providerId)")
print(" Storage types: \(cap.storageTypes)")
print(" Supports import: \(cap.supportsKeyImport)")
print(" Supports export: \(cap.supportsKeyExport)")
print(" Hardware backing: \(cap.supportsHardwareBacking)")
print(" Supported curves: \(cap.supportedCurves)")
print(" Supports signing: \(cap.supportsSigning())")
print(" Supports encryption: \(cap.supportsEncryption())")
}
case .failure:
print("Failed to get capabilities")
}
Key Lifecycle Best Practices
When managing cryptographic keys:
Generate keys with appropriate algorithms. ECDSA_SHA256 (ES256) is a good default for signing, offering a balance of security and performance.
Use meaningful aliases. Include context like purpose and creation date to simplify key management.
Scope keys appropriately. Keys are tied to their provider and cannot be transferred between providers.
Consider key rotation. For long-lived applications, implement key rotation where new keys are generated periodically and old keys retained for verification until they expire.
Use hardware backing when available. The mobile provider uses platform secure storage (iOS Secure Enclave, Android Keystore) which cannot export private keys.