-
Notifications
You must be signed in to change notification settings - Fork 0
Secure Password Encryption
briansemify edited this page Oct 24, 2025
·
2 revisions
This document outlines the recommended approach for securely encrypting passwords when integrating with the Semify API from third-party applications.
The Semify API supports secure password encryption using a hybrid RSA + AES approach, which provides maximum security while maintaining performance. This method ensures that passwords are never transmitted in plain text and can only be decrypted by the intended recipient.
- RSA Key Pair: Public/private key pair for secure key exchange
- AES Encryption: Symmetric encryption for actual password data
- JWT Tokens: Optional additional layer for validation and auditing
- Rate Limiting: Protection against brute force attacks
- Third party requests public key from Semify API
- Third party generates AES key and encrypts password
- Third party encrypts AES key with Semify's public key
- Third party sends encrypted data to Semify API
- Semify decrypts AES key with private key
- Semify decrypts password with AES key
-
Endpoint:
GET /api/v1/accounts/iam/key - Description: Retrieves the current RSA public key for encryption
- Response: Public key in PEM format
- Rate Limit: 100 requests per hour per client
-
Endpoint:
POST /api/v1/accounts/iam/credentials - Description: Submits encrypted password data for decryption
- Authentication: Bearer JWT token required
- Rate Limit: 10 requests per minute per client
// Generate random AES key (256-bit)
const aesKey = crypto.randomBytes(32);
// Generate random IV (128-bit)
const iv = crypto.randomBytes(16);// Encrypt password using AES-256-CBC
const cipher = crypto.createCipher('aes-256-cbc', aesKey);
cipher.setAutoPadding(true);
let encryptedPassword = cipher.update(password, 'utf8', 'base64');
encryptedPassword += cipher.final('base64');// Encrypt AES key with RSA public key
const encryptedAesKey = crypto.publicEncrypt({
key: publicKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
}, aesKey);const payload = {
encryptedPassword: encryptedPassword,
encryptedAesKey: encryptedAesKey.toString('base64'),
iv: iv.toString('base64'),
timestamp: new Date().toISOString(),
clientId: 'your-client-id'
};curl -H "Authorization: Bearer $TOKEN" \
"https://uat.services.semify.com/api/v1/accounts/iam/key"{
"publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...\n-----END PUBLIC KEY-----",
"keyId": "rsa-key-2024-01",
"algorithm": "RSA-OAEP",
"expiresAt": "2024-02-01T00:00:00Z"
}curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"encryptedPassword": "base64-encoded-aes-encrypted-password",
"encryptedAesKey": "base64-encoded-rsa-encrypted-aes-key",
"iv": "base64-encoded-iv",
"timestamp": "2024-01-15T10:30:00Z",
"clientId": "client-12345"
}' \
"https://uat.services.semify.com/api/v1/accounts/iam/credentials"{
"success": true,
"message": "Password decrypted and processed successfully",
"processedAt": "2024-01-15T10:30:01Z",
"clientId": "client-12345"
}{
"error": true,
"errorCode": "DECRYPTION_FAILED",
"message": "Failed to decrypt password. Check encryption parameters.",
"timestamp": "2024-01-15T10:30:00Z"
}-
INVALID_PUBLIC_KEY: Public key format is invalid -
DECRYPTION_FAILED: Password decryption failed -
RATE_LIMIT_EXCEEDED: Too many requests -
INVALID_CLIENT_ID: Client ID not recognized -
EXPIRED_TIMESTAMP: Request timestamp is too old (>5 minutes)
- Key Rotation: RSA keys are rotated monthly
- Key Storage: Private keys are stored securely using HSM or encrypted storage
- Key Distribution: Public keys are distributed via secure API endpoint
- RSA: 2048-bit minimum, OAEP padding
- AES: 256-bit key, CBC mode
- IV: Random 128-bit initialization vector
- Padding: PKCS7 padding for AES
- Public Key Requests: 100 per hour per client
- Password Submissions: 10 per minute per client
- Burst Protection: Maximum 5 requests in 10 seconds
- Timestamp Validation: Requests older than 5 minutes are rejected
- Client ID Validation: Only registered clients can submit passwords
- Payload Size: Maximum 10KB per request
async function getPublicKey() {
const response = await fetch('https://uat.services.semify.com/api/v1/accounts/iam/key', {
headers: {
'Authorization': `Bearer ${token}`
}
});
const data = await response.json();
return data.publicKey;
}async function encryptPassword(password, publicKey) {
// Generate AES key and IV
const aesKey = crypto.randomBytes(32);
const iv = crypto.randomBytes(16);
// Encrypt password with AES
const cipher = crypto.createCipher('aes-256-cbc', aesKey);
let encryptedPassword = cipher.update(password, 'utf8', 'base64');
encryptedPassword += cipher.final('base64');
// Encrypt AES key with RSA
const encryptedAesKey = crypto.publicEncrypt({
key: publicKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
}, aesKey);
return {
encryptedPassword,
encryptedAesKey: encryptedAesKey.toString('base64'),
iv: iv.toString('base64'),
timestamp: new Date().toISOString()
};
}async function submitEncryptedPassword(encryptedData, clientId) {
const response = await fetch('https://uat.services.semify.com/api/v1/accounts/iam/credentials', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
...encryptedData,
clientId: clientId
})
});
return await response.json();
}- Never store private keys in client applications
- Use HTTPS only for all API communications
- Validate certificates to prevent man-in-the-middle attacks
- Implement proper error handling without exposing sensitive information
- Cache public keys for up to 1 hour to reduce API calls
- Implement retry logic with exponential backoff
- Use connection pooling for high-volume applications
- Log encryption attempts (without sensitive data)
- Monitor rate limit usage to avoid service disruption
- Track error rates to identify potential issues
-
Base URL:
https://uat.services.semify.com -
Test Client ID:
test-client-12345 -
Test Password:
TestPassword123!
- Successful encryption/decryption
- Invalid public key handling
- Rate limit enforcement
- Expired timestamp rejection
- Malformed payload handling