Skip to main content

Cryptographic Key Management Guide

This guide provides comprehensive information about cryptographic key management in React Native Biometrics, including detailed comparisons, platform-specific behaviors, and advanced usage patterns.

Overview

React Native Biometrics supports two types of cryptographic keys for secure biometric operations:

  • EC256 (Elliptic Curve P-256): Modern, efficient, and secure
  • RSA2048 (RSA 2048-bit): Legacy-compatible and widely supported

Key Types Comparison

EC256 (Elliptic Curve P-256)

Advantages:

  • Smaller key size: More efficient storage and transmission
  • Better performance: Faster key generation and cryptographic operations
  • Modern security: Based on elliptic curve cryptography standards
  • Hardware acceleration: Optimized support on modern devices
  • Secure Enclave support: On iOS, keys are stored in hardware-protected Secure Enclave

Use Cases:

  • New applications without legacy constraints
  • High-performance requirements
  • Mobile-first applications
  • When hardware security is prioritized

Platform Behavior:

  • iOS: Default key type, stored in Secure Enclave when available
  • Android: Supported, stored in Android Keystore

RSA2048 (RSA 2048-bit)

Advantages:

  • Wide compatibility: Supported by virtually all systems and libraries
  • Legacy support: Compatible with older infrastructure
  • Industry standard: Well-established in enterprise environments
  • Proven security: Long track record of secure implementations

Use Cases:

  • Integration with legacy systems
  • Enterprise environments with RSA requirements
  • Compliance with specific security standards
  • Backward compatibility needs

Platform Behavior:

  • iOS: Stored in regular keychain (not Secure Enclave)
  • Android: Default key type, stored in Android Keystore

Platform-Specific Defaults

Why Different Defaults?

Each platform uses the key type that best leverages its security capabilities:

  • iOS defaults to EC256: Takes advantage of Secure Enclave hardware security
  • Android defaults to RSA2048: Maintains backward compatibility with existing Android implementations

Security Implications

PlatformDefaultStorage LocationHardware Protection
iOSEC256Secure Enclave✅ Yes (when available)
iOSRSA2048Keychain❌ No
AndroidRSA2048Android Keystore✅ Yes
AndroidEC256Android Keystore✅ Yes

Advanced Usage Patterns

Explicit Key Type Selection

import { createKeys } from '@sbaiahmed1/react-native-biometrics';

// Force EC256 on both platforms (recommended for new apps)
const ecResult = await createKeys(undefined, 'ec256');

// Force RSA2048 on both platforms (for legacy compatibility)
const rsaResult = await createKeys(undefined, 'rsa2048');

Platform-Specific Key Selection

import { Platform } from 'react-native';
import { createKeys } from '@sbaiahmed1/react-native-biometrics';

// Use optimal key type for each platform
const keyType = Platform.OS === 'ios' ? 'ec256' : 'rsa2048';
const result = await createKeys(undefined, keyType);

Custom Key Aliases with Types

// Different key types for different purposes
const primaryKeys = await createKeys('primary.biometric', 'ec256');
const backupKeys = await createKeys('backup.biometric', 'rsa2048');

Migration Strategy

When migrating from RSA to EC keys:

import { deleteKeys, createKeys, keyExists } from '@sbaiahmed1/react-native-biometrics';

async function migrateToEC256() {
try {
// Check if old RSA keys exist
const hasOldKeys = await keyExists('legacy.rsa.key');

if (hasOldKeys) {
// Create new EC256 keys
await createKeys('modern.ec.key', 'ec256');

// Verify new keys work, then delete old ones
await deleteKeys('legacy.rsa.key');

console.log('Successfully migrated to EC256 keys');
}
} catch (error) {
console.error('Migration failed:', error);
}
}

Non-Biometric Signing (Keystore/Keychain Keys Without Prompts)

For device-bound signing without any user interaction — server authentication, request signing, attestation — keys can be created with no user-authentication requirement. The private key still never leaves the Android Keystore / iOS Keychain; only the prompt is removed. Hardware backing follows the same platform matrix as biometric keys (see the table above): Android keys are TEE/StrongBox-backed, iOS EC keys use the Secure Enclave on device, and iOS RSA keys reside in the regular Keychain without hardware protection — non-exportable via the API, but not hardware-resident. This covers the use cases previously served by react-native-rsa-native.

import {
createKeysWithOptions,
keyExists,
getPublicKey,
sign,
deleteKeys,
SignatureAlgorithm,
} from '@sbaiahmed1/react-native-biometrics';

// 1. Create a hardware-backed key that never prompts
const { publicKey } = await createKeysWithOptions({
keyAlias: 'server-auth-key',
keyType: 'rsa2048',
requireAuthentication: false,
});

// 2. Prompt-free existence check
const exists = await keyExists('server-auth-key');

// 3. Public key as base64 X.509 SubjectPublicKeyInfo DER (both platforms)
const { publicKey: spki } = await getPublicKey('server-auth-key');

// 4. Sign without any prompt
const result = await sign({
keyAlias: 'server-auth-key',
data: payload,
algorithm: SignatureAlgorithm.SHA512withRSA, // optional, defaults to SHA-256
});

// 5. Cleanup
await deleteKeys('server-auth-key');

Behavior Notes

  • createKeysWithOptions defaults to requireAuthentication: true, which is identical to createKeys — the non-biometric mode is strictly opt-in.
  • sign() never shows a prompt. Called on a biometric-gated key it resolves with { success: false, errorCode: 'KEY_REQUIRES_AUTHENTICATION' } — use signWithOptions() for those keys.
  • The reverse works: signWithOptions() on a no-auth key signs silently and resolves with authType: 0.
  • On iOS, no-auth keys use kSecAttrAccessibleWhenUnlockedThisDeviceOnly: they don't depend on a passcode being set, but are unusable while the device is locked and never migrate to another device.

Signature Algorithms

sign() accepts SHA256withRSA, SHA512withRSA, SHA256withECDSA, and SHA512withECDSA (the algorithm must match the key type). Constraints:

  • Android: keys created before SHA-512 support was added, and keys generated inside StrongBox, only permit SHA-256. Requesting SHA-512 on such a key fails with UNSUPPORTED_ALGORITHM; recreate the key to enable SHA-512 (StrongBox keys stay SHA-256 only).
  • iOS: the algorithm is chosen per call, so SHA-512 works with existing keys too.

Public Key Formats

getPublicKey() always returns base64-encoded X.509 SubjectPublicKeyInfo (SPKI) DER, directly consumable by standard tooling (openssl pkey -pubin -inform DER). Note that the publicKey returned by createKeys/createKeysWithOptions/getAllKeys is unchanged for backward compatibility: on Android and for iOS EC keys it is also SPKI, but iOS RSA keys are returned as raw PKCS#1 DER there. Prefer getPublicKey() when a server needs to consume the key.

Performance Considerations

Key Generation Speed

Key TypeiOSAndroidNotes
EC256~50-100ms~100-200msFaster on iOS with Secure Enclave
RSA2048~200-500ms~300-600msSlower due to larger key size

Memory Usage

  • EC256: ~32 bytes private key, ~65 bytes public key
  • RSA2048: ~256 bytes private key, ~256 bytes public key

Cryptographic Operations

EC256 operations are generally 2-4x faster than RSA2048 for:

  • Signature generation
  • Signature verification
  • Key derivation

Security Best Practices

Key Storage Security

  1. iOS EC256: Automatically uses Secure Enclave when available
  2. Android: Both key types benefit from Android Keystore hardware backing
  3. Key Aliases: Use descriptive, unique aliases to avoid conflicts

Key Lifecycle Management

// Good: Explicit key management
async function setupBiometrics() {
try {
// Check if keys already exist
const exists = await keyExists();

if (!exists) {
// Create keys with appropriate type
await createKeys(undefined, 'ec256');
}

return true;
} catch (error) {
console.error('Biometric setup failed:', error);
return false;
}
}

// Good: Cleanup on logout/uninstall
async function cleanupBiometrics() {
try {
await deleteKeys();
console.log('Biometric keys cleaned up');
} catch (error) {
console.error('Cleanup failed:', error);
}
}

Error Handling

import { createKeys, BiometricError } from '@sbaiahmed1/react-native-biometrics';

async function createKeysWithFallback() {
try {
// Try EC256 first (recommended)
return await createKeys(undefined, 'ec256');
} catch (error) {
if (error.code === 'KeyGenerationFailed') {
console.warn('EC256 failed, falling back to RSA2048');
// Fallback to RSA2048
return await createKeys(undefined, 'rsa2048');
}
throw error;
}
}

Troubleshooting

Common Issues

  1. Key generation fails on older devices: Use RSA2048 as fallback
  2. Secure Enclave unavailable: EC256 will fall back to regular keychain on iOS
  3. Key alias conflicts: Use unique, descriptive aliases
  4. Performance issues: Consider key type and device capabilities

Debugging Key Types

import { createKeys } from '@sbaiahmed1/react-native-biometrics';

async function debugKeyCreation() {
const startTime = Date.now();

try {
const result = await createKeys('debug.key', 'ec256');
const duration = Date.now() - startTime;

console.log(`EC256 key created in ${duration}ms`);
console.log('Public key length:', result.publicKey.length);

return result;
} catch (error) {
console.error('Key creation debug info:', {
error: error.message,
code: error.code,
duration: Date.now() - startTime
});
throw error;
}
}

Migration Guide

iOS Access-Control Migration (.biometryAny vs .biometryCurrentSet)

On iOS, key access-control policy is fixed at key creation time:

  • Existing keys remain bound to the policy they were created with.
  • New keys can use:
    • .biometryAny (default/backward-compatible)
    • .biometryCurrentSet (use biometricStrength: 'strong' during createKeys)
    • .userPresence (when allowDeviceCredentials is true)

Migration recommendations:

  1. Keep existing aliases on .biometryAny for compatibility unless stricter behavior is required.
  2. To adopt .biometryCurrentSet, roll keys by alias (deleteKeys then createKeys with biometricStrength: 'strong').
  3. Communicate to users that .biometryCurrentSet keys are invalidated after biometric enrollment changes and require key re-enrollment.

From Legacy Implementations

If you're upgrading from an older version that only supported RSA:

  1. Assess current usage: Determine if you need backward compatibility
  2. Choose strategy: Gradual migration vs. clean slate
  3. Test thoroughly: Verify key operations on target devices
  4. Plan rollback: Keep RSA2048 as fallback option

Version Compatibility

  • v3.0+: Full support for both EC256 and RSA2048
  • v2.x: RSA2048 only
  • v1.x: Limited key management features