Skip to main content
Version: v0.13

Signing and Verification

The IDK provides comprehensive support for creating and verifying cryptographic signatures. This guide covers raw signatures, the signature algorithms supported, and best practices.

Raw Signatures

Raw signatures operate directly on byte arrays without additional structure. They're suitable when you need full control over the data format or when integrating with systems that expect raw signatures.

Creating Raw Signatures

val keyManager = session.component.keyManagerService

// Generate or retrieve a signing key
val keyPair = keyManager.generateKeyAsync(
providerId = null,
alias = "signing-key",
alg = SignatureAlgorithm.ECDSA_SHA256
)

// Prepare the data to sign
val data = "Important message to sign".encodeToByteArray()

// Get key info for signing (need private key access)
val keyInfo = keyPair.cborToManagedKeyInfo(visibility = KeyVisibility.PRIVATE)

// Create the signature
val signature = keyManager.createRawSignature(
keyInfo = keyInfo,
input = data,
requireX5Chain = false
)

// The signature is a raw byte array
println("Signature length: ${signature.size} bytes")

Verifying Raw Signatures

// 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 verified successfully")
} else {
println("Signature verification failed - data may have been tampered with")
}

Signature Algorithms

The IDK supports multiple signature algorithms. Choose based on your security requirements and interoperability needs.

ECDSA (Elliptic Curve Digital Signature Algorithm)

ECDSA is the most common choice for mobile applications due to its compact signatures and good performance.

AlgorithmCurveSignature SizeSecurity Level
ECDSA_SHA256P-25664 bytes128-bit
ECDSA_SHA384P-38496 bytes192-bit
ECDSA_SHA512P-521132 bytes256-bit
// ECDSA_SHA256 - recommended for most use cases
val es256Key = keyManager.generateKeyAsync(
alias = "es256-key",
alg = SignatureAlgorithm.ECDSA_SHA256
)

// ECDSA_SHA384 - higher security, larger signatures
val es384Key = keyManager.generateKeyAsync(
alias = "es384-key",
alg = SignatureAlgorithm.ECDSA_SHA384
)

// ECDSA_SHA512 - highest security, largest signatures
val es512Key = keyManager.generateKeyAsync(
alias = "es512-key",
alg = SignatureAlgorithm.ECDSA_SHA512
)

RSA Signatures

RSA signatures are larger but offer broad compatibility with legacy systems.

AlgorithmDescription
RSA_SHA256RSA PKCS#1 v1.5 with SHA-256
RSA_SHA384RSA PKCS#1 v1.5 with SHA-384
RSA_SHA512RSA PKCS#1 v1.5 with SHA-512
RSA_SSA_PSS_SHA256_MGF1RSA-PSS with SHA-256
RSA_SSA_PSS_SHA384_MGF1RSA-PSS with SHA-384
RSA_SSA_PSS_SHA512_MGF1RSA-PSS with SHA-512
// RSA-PSS with SHA-256 (recommended over PKCS#1 v1.5)
val rsaPssKey = keyManager.generateKeyAsync(
alias = "rsa-pss-key",
alg = SignatureAlgorithm.RSA_SSA_PSS_SHA256_MGF1
)

// RSA PKCS#1 v1.5 with SHA-256 (for legacy compatibility)
val rsaKey = keyManager.generateKeyAsync(
alias = "rsa-key",
alg = SignatureAlgorithm.RSA_SHA256
)

Including X.509 Certificates

When signing for external parties, you may need to include the X.509 certificate chain that vouches for your signing key:

// Sign with certificate chain included
val signature = keyManager.createRawSignature(
keyInfo = keyInfo,
input = data,
requireX5Chain = true // Include X.509 certificate chain
)

// The key info must have an associated certificate for this to work
// If no certificate is available and requireX5Chain is true,
// the operation will fail

Encryption and Decryption

The KeyManagerService also supports content encryption operations:

// Encrypt data
val encryptionResult = keyManager.encrypt(
keyInfo = keyInfo,
plaintext = "Secret message".encodeToByteArray(),
algorithm = ContentEncryptionAlgorithm.A256GCM,
additionalAuthenticatedData = "context".encodeToByteArray() // Optional AAD
)

// Access encrypted components
val ciphertext = encryptionResult.ciphertext
val iv = encryptionResult.iv
val authTag = encryptionResult.authTag

// Decrypt data
val plaintext = keyManager.decrypt(
keyInfo = keyInfo,
ciphertext = ciphertext,
algorithm = ContentEncryptionAlgorithm.A256GCM,
iv = iv,
authTag = authTag,
additionalAuthenticatedData = "context".encodeToByteArray()
)

Content Encryption Algorithms

AlgorithmDescription
A128GCMAES-128-GCM
A192GCMAES-192-GCM
A256GCMAES-256-GCM

Key Wrapping

Wrap and unwrap keys for secure key transport:

// Wrap a key for transport
val wrappedKey = keyManager.wrapKey(
wrappingKeyInfo = wrappingKeyInfo,
keyToWrap = secretKey,
algorithm = KeyWrapAlgorithm.RSA_OAEP_256
)

// Unwrap a received key
val unwrappedKey = keyManager.unwrapKey(
unwrappingKeyInfo = unwrappingKeyInfo,
wrappedKey = wrappedKey,
algorithm = KeyWrapAlgorithm.RSA_OAEP_256
)

Key Wrap Algorithms

AlgorithmDescription
RSA_OAEPRSA-OAEP with SHA-1
RSA_OAEP_256RSA-OAEP with SHA-256
RSA_OAEP_512RSA-OAEP with SHA-512

Key Agreement

Perform ECDH key agreement to establish shared secrets:

// Perform ECDH key agreement
val sharedSecret = keyManager.performKeyAgreement(
privateKeyInfo = myPrivateKeyInfo,
publicKeyInfo = theirPublicKeyInfo,
algorithm = KeyAgreementAlgorithm.ECDH_ES_HKDF_256,
keyDataLen = 32 // Desired output length in bytes
)

// Use the shared secret for symmetric encryption

Key Agreement Algorithms

AlgorithmDescription
ECDH_ES_HKDF_256ECDH-ES with HKDF-SHA256
ECDH_ES_HKDF_512ECDH-ES with HKDF-SHA512
ECDH_SS_HKDF_256ECDH-SS with HKDF-SHA256
ECDH_SS_HKDF_512ECDH-SS with HKDF-SHA512

Best Practices

When implementing signing and verification:

Always verify signatures before trusting data. Never assume data is authentic without cryptographic verification.

Use appropriate algorithms for your security requirements. ECDSA_SHA256 provides good security for most applications. Use ECDSA_SHA384 or ECDSA_SHA512 for higher security requirements.

Protect signing keys. Use the mobile KMS provider for hardware-backed protection on mobile devices.

Consider replay attacks. Signatures alone don't prevent replay attacks. Include timestamps, nonces, or sequence numbers in signed data.

Log signature failures. Failed signature verifications may indicate attacks or data corruption and should be logged for security monitoring.

Handle errors appropriately. Signature operations can fail for various reasons including key not found, hardware errors, or missing certificates.