RSA Public-Private Key Pair Guide
Complete guide to using RSA encryption with KeyClaim for enhanced security
Overview
This guide explains how to use RSA public-private key encryption with KeyClaim to enhance security. The flow works as follows:
- Generate a public-private key pair
- Store the private key securely on your client (never send it to the server)
- Upload the public key to KeyClaim server
- Server encrypts challenges with your public key
- Client decrypts challenges with your private key
- Continue with normal HMAC validation flow
Why Use RSA Encryption?
- Enhanced Security: Challenges are encrypted, making them useless even if intercepted
- MITM Protection: Attackers cannot read encrypted challenges without the private key
- Forward Secrecy: Each challenge is unique and encrypted independently
Step 1: Generate Key Pair
Option A: Using KeyClaim Dashboard (Recommended)
- Log in to your KeyClaim dashboard
- Navigate to API Keys → Key Pairs
- Click Generate New Key Pair
- Choose key size (2048 or 4096 bits recommended)
- Click Generate
- IMPORTANT: Save your private key immediately - it's only shown once!
Step 2: Store Your Private Key Securely
⚠️ CRITICAL SECURITY RULES:
- NEVER send your private key to the server
- NEVER commit private keys to version control
- NEVER share private keys publicly
- ALWAYS store private keys in secure storage (keychain, secure vault, environment variables)
Storage Options by Platform:
Web Applications
- • Browser: Web Crypto API
- • Environment Variables
- • Secure Vault Services
Mobile Applications
- • iOS: Keychain Services
- • Android: Keystore System
- • React Native: react-native-keychain
Backend Applications
- • Environment Variables
- • Encrypted Files
- • Cloud Secrets
Step 3: Upload Public Key to Server
The public key is safe to share and should be stored on the KeyClaim server.
Using Dashboard:
If generated via dashboard, the public key is automatically saved. If generated locally, use the Upload Public Key feature.
Using API:
POST /api/keys/generate-keypair
Authorization: Bearer YOUR_TOKEN
{
"name": "My Key Pair",
"keySize": 2048
}Step 4: Associate Public Key with API Key
- Go to API Keys in dashboard
- Select your API key
- Choose the key pair from dropdown
- Save
Step 5: Create Challenge (Automatic Encryption)
When creating a challenge, if your API key has a key pair assigned, the challenge will be automatically encrypted:
POST /api/challenge/create
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
{
"ttl": 30
}Response:
{
"challenge": "base64_encrypted_challenge_here",
"expires_in": 30
}Note: Encryption is automatic if a key pair is assigned to your API key. No need to specify encrypted: true - it happens automatically.
Step 6: Decrypt Challenge on Client
Decrypt the challenge using your private key. See platform-specific examples below:
JavaScript/TypeScript (Web)
async function decryptChallenge(encryptedChallenge, privateKeyPEM) {
// Import private key
const privateKey = await crypto.subtle.importKey(
'pkcs8',
pemToArrayBuffer(privateKeyPEM),
{
name: 'RSA-OAEP',
hash: 'SHA-256',
},
false,
['decrypt']
)
// Decrypt
const encryptedBuffer = base64ToArrayBuffer(encryptedChallenge)
const decryptedBuffer = await crypto.subtle.decrypt(
{ name: 'RSA-OAEP' },
privateKey,
encryptedBuffer
)
return new TextDecoder().decode(decryptedBuffer)
}Node.js
const crypto = require('crypto')
function decryptChallenge(encryptedChallenge, privateKeyPEM) {
const encryptedBuffer = Buffer.from(encryptedChallenge, 'base64')
const decrypted = crypto.privateDecrypt(
{
key: privateKeyPEM,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: 'sha256',
},
encryptedBuffer
)
return decrypted.toString('utf8')
}Python
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
import base64
def decrypt_challenge(encrypted_challenge, private_key_pem):
private_key = serialization.load_pem_private_key(
private_key_pem.encode('utf-8'),
password=None
)
encrypted_bytes = base64.b64decode(encrypted_challenge)
decrypted = private_key.decrypt(
encrypted_bytes,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return decrypted.decode('utf-8')Note: For more platform-specific examples (PHP, Java, Kotlin, C#, Go, Android, iOS, React Native), see the complete guide in the repository or contact support.
Step 7: Continue with Normal Flow
After decrypting the challenge, continue with the standard HMAC validation:
// 1. Decrypt challenge
const decryptedChallenge = await decryptChallenge(encryptedChallenge, privateKey)
// 2. Generate HMAC response
const response = await generateHMACResponse(decryptedChallenge, apiKey)
// 3. Validate
const validation = await fetch('/api/challenge/validate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
},
body: JSON.stringify({
challenge: encryptedChallenge, // Send encrypted challenge
response: response,
decryptedChallenge: decryptedChallenge // Server verifies this matches
})
})Complete Example Flow
1. Generate Key Pair (One Time)
// Via dashboard or API
const keyPair = await generateKeyPair()
// Save privateKey securely
// Public key is stored on server2. Create Challenge (Automatic Encryption)
const response = await fetch('/api/challenge/create', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
ttl: 30
})
})
// If API key has a key pair assigned, challenge will be automatically encrypted
const { challenge: encryptedChallenge } = await response.json()3. Decrypt Challenge
const decryptedChallenge = await decryptChallenge(
encryptedChallenge,
PRIVATE_KEY
)4. Generate HMAC Response
const hmacResponse = await generateHMACResponse(
decryptedChallenge,
API_KEY
)5. Validate
const validation = await fetch('/api/challenge/validate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
challenge: encryptedChallenge,
response: hmacResponse,
decryptedChallenge: decryptedChallenge
})
})
const result = await validation.json()
// { valid: true, ... }Security Best Practices
✅ DO:
- • Store private keys in secure keychain/keystore
- • Use environment variables for private keys
- • Rotate keys periodically
- • Use 2048-bit or larger keys
- • Never log private keys
- • Use HTTPS for all API calls
❌ DON'T:
- • Commit private keys to version control
- • Send private keys to the server
- • Share private keys between applications
- • Use weak key sizes (< 2048 bits)
- • Store private keys in plain text files
- • Log or print private keys
FAQ
Q: Can I use the same key pair for multiple API keys?
A: Yes, but it's recommended to use separate key pairs for better security isolation.
Q: What happens if I lose my private key?
A: You'll need to generate a new key pair and update your API key association. The old public key will be removed.
Q: Can I regenerate the private key from the public key?
A: No, that's cryptographically impossible. Always backup your private key securely.
Q: How often should I rotate keys?
A: Recommended: Every 6-12 months, or immediately if compromised.