Index
---
layout: default
title: Docs
nav_order: 2
has_children: true
permalink: /docs/
---
Documentation
Welcome to the JSEncrypt documentation! Here you'll find everything you need to integrate RSA encryption into your JavaScript applications.
Overview
JSEncrypt is a JavaScript library that provides a simple interface for RSA encryption and decryption using OpenSSL-compatible key formats. It's built on top of the proven jsbn library by Tom Wu.
What You'll Learn
- Getting Started - Install and set up JSEncrypt
- API Reference - Complete API documentation
- Examples - Real-world usage examples
- Key Management - Working with RSA keys
- Security Best Practices - Keep your implementations secure
Quick Navigation
<div class="code-example" markdown="1">
New to JSEncrypt? Start with our Getting Started Guide.
Looking for specific methods? Check the API Reference.
Want to see examples? Browse our Examples section.
</div>
---
Need Help?
- 🐛 Found a bug? Report it on GitHub
- 💡 Have a question? Start a discussion
- 📚 Want to contribute? See our Contributing Guide
---
Getting Started
---
layout: default
title: Getting Started
parent: Docs
nav_order: 1
permalink: /docs/getting-started/
aliases:
- /docs/getting-started.html
---
Getting Started with JSEncrypt
{: .no_toc }
This guide will help you get up and running with JSEncrypt in just a few minutes.
Table of contents
{: .no_toc .text-delta }
1. TOC
{:toc}
---
Installation
Using npm
npm install jsencryptUsing yarn
yarn add jsencryptUsing CDN
Include JSEncrypt directly in your HTML:
<script src="https://cdn.jsdelivr.net/npm/jsencrypt@latest/bin/jsencrypt.min.js"></script>Basic Usage
1. Import the Library
#### ES6 Modules
import { JSEncrypt } from 'jsencrypt';#### CommonJS
const JSEncrypt = require('jsencrypt');#### Browser Global
// JSEncrypt is available globally when using CDN
const crypt = new JSEncrypt();2. Create RSA Keys
You'll need RSA key pairs to use JSEncrypt. Generate them using OpenSSL:
Generate a 2048-bit private key
openssl genrsa -out private.pem 2048Extract the public key
openssl rsa -pubout -in private.pem -out public.pem3. Basic Encryption/Decryption
// Create JSEncrypt instance
const crypt = new JSEncrypt();// Set your private key (for decryption)
crypt.setPrivateKey(-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA4f5wg5l2hKsTeNem/V41fGnJm6gOdrj8ym3rFkEjWT9u
U38KPhX7l3YXkLMfJj8sE3PUi0EaL6rN6rOUY8dq1fQhPhT1wfI6V8KQtQnq
1FKnNgQCVmQpCxK7qFR7Z+9MRWoJrPb8lZMmT1ELkKL6FBfkp3H3WcTl+BF0
XoZnLK0CfXfKzPJPm9jfKKE7dqnCsRiXYJbBwkNpQ5xo2lRKnNaH8GjPzJ4X
TZ5J7G6hDpXN1F3YzWZNVQRzfDfLB+w9FDaZ5kFhRc2PgB1Y8dNOhgK7RFJF
JDZhqBhSRnQ1YkLkQOnHq4Bz8l7YgRJkJHdIfTOO8l3YXkLMfJj8sE3PUi0E
qL6r9OOCzGJnVgQCVmQpCxK7qFR7Z+9MRWoJrPb8lZMmT1ELkKL6FBfkp3H3
...
-----END RSA PRIVATE KEY-----);
// The public key is automatically derived from the private key
// Or you can set it explicitly:
// crypt.setPublicKey('-----BEGIN PUBLIC KEY-----...');
// Encrypt data
const originalText = 'Hello, World!';
const encrypted = crypt.encrypt(originalText);
// Decrypt data
const decrypted = crypt.decrypt(encrypted);
console.log('Original:', originalText);
console.log('Encrypted:', encrypted);
console.log('Decrypted:', decrypted);
console.log('Match:', originalText === decrypted); // true
Key Concepts
Public vs Private Keys
- Public Key: Used for encryption. Safe to share publicly.
- Private Key: Used for decryption. Keep this secret!
const crypt = new JSEncrypt();// For encryption only (using public key)
crypt.setPublicKey(publicKeyString);
const encrypted = crypt.encrypt('secret message');
// For decryption (requires private key)
crypt.setPrivateKey(privateKeyString);
const decrypted = crypt.decrypt(encrypted);
Key Generation
JSEncrypt supports two approaches for obtaining RSA keys: OpenSSL generation (recommended) and JavaScript generation (convenient but less secure).
Option 1: OpenSSL Key Generation (Recommended)
For production applications and maximum security, generate keys using OpenSSL:
Generate a 2048-bit private key (recommended minimum)
openssl genrsa -out private.pem 2048Generate a 4096-bit private key (higher security)
openssl genrsa -out private.pem 4096Extract the public key
openssl rsa -pubout -in private.pem -out public.pemView the private key
cat private.pemView the public key
cat public.pemWhy OpenSSL is more secure:
- Uses cryptographically secure random number generators
- Better entropy sources from the operating system
- Optimized and audited implementations
- Industry standard for key generation
Option 2: JavaScript Key Generation (Convenience)
JSEncrypt can generate keys directly in JavaScript, which is convenient for testing, demos, or non-critical applications:
// Create JSEncrypt instance
const crypt = new JSEncrypt();// Generate a new key pair (default: 1024-bit)
const privateKey = crypt.getPrivateKey();
const publicKey = crypt.getPublicKey();
console.log('Private Key:', privateKey);
console.log('Public Key:', publicKey);
// You can also specify key size (512, 1024, 2048, 4096)
const crypt2048 = new JSEncrypt({ default_key_size: 2048 });
const strongerPrivateKey = crypt2048.getPrivateKey();
const strongerPublicKey = crypt2048.getPublicKey();
#### Asynchronous Key Generation
For better performance (especially with larger keys), use async generation:
// Asynchronous key generation (recommended for larger keys)
const crypt = new JSEncrypt({ default_key_size: 2048 });crypt.getKey(() => {
const privateKey = crypt.getPrivateKey();
const publicKey = crypt.getPublicKey();
console.log('Generated private key:', privateKey);
console.log('Generated public key:', publicKey);
// Now you can use the keys
const encrypted = crypt.encrypt('Hello, World!');
const decrypted = crypt.decrypt(encrypted);
});
#### Different Key Sizes
// 512-bit (fast but less secure - only for testing)
const crypt512 = new JSEncrypt({ default_key_size: 512 });// 1024-bit (default - basic security)
const crypt1024 = new JSEncrypt({ default_key_size: 1024 });
// 2048-bit (recommended minimum for production)
const crypt2048 = new JSEncrypt({ default_key_size: 2048 });
// 4096-bit (high security but slower)
const crypt4096 = new JSEncrypt({ default_key_size: 4096 });
⚠️ Security Note: JavaScript key generation uses browser/Node.js random number generators which may have less entropy than dedicated cryptographic tools. For production applications handling sensitive data, prefer OpenSSL-generated keys.
💡 Use Cases for JavaScript Generation:
- Rapid prototyping and testing
- Client-side demos and examples
- Educational purposes
- Non-critical applications
- When OpenSSL is not available
Key Size Limitations
RSA encryption has limitations based on key size:
- 1024-bit key: Can encrypt up to 117 bytes
- 2048-bit key: Can encrypt up to 245 bytes
- 4096-bit key: Can encrypt up to 501 bytes
For larger data, use hybrid encryption (RSA + AES).
Next Steps
Now that you have JSEncrypt working, explore these topics:
- API Reference - Complete method documentation
- Examples - Real-world usage patterns
- Key Management - Advanced key handling
- Security Best Practices - Keep your app secure
---
Troubleshooting
Common Issues
"Invalid key" error
: Make sure your key is in PEM format and includes the BEGIN/END headers.
"Message too long" error
: Your message exceeds the key size limit. Use shorter messages or implement hybrid encryption.
Encryption works but decryption fails
: Ensure you're using the correct private key that corresponds to the public key used for encryption.
Getting Help
If you're still having issues:
1. Check our Examples for working code
2. Search existing issues on GitHub
3. Open a new issue with a minimal reproduction case
---
Api
---
layout: default
title: API Reference
parent: Docs
nav_order: 2
permalink: /docs/api/
aliases:
- /docs/api.html
---
API Reference
{: .no_toc }
Complete reference for all JSEncrypt methods and properties.
Table of contents
{: .no_toc .text-delta }
1. TOC
{:toc}
---
Constructor
new JSEncrypt(options?)
Creates a new JSEncrypt instance.
#### Parameters
| Parameter | Type | Default | Description |
|:----------|:-----|:--------|:------------|
| options | Object | {} | Configuration options |
| options.default_key_size | number | 1024 | Default key size for key generation |
#### Example
// Default constructor
const crypt = new JSEncrypt();// With custom key size
const crypt = new JSEncrypt({ default_key_size: 2048 });
---
Key Management
setKey(key)
{: .d-inline-block }
Alias
{: .label .label-yellow }
Sets either a private or public key. This is an alias for both setPrivateKey() and setPublicKey().
#### Parameters
| Parameter | Type | Description |
|:----------|:-----|:------------|
| key | string | PEM-formatted RSA key |
#### Example
// Can be used with either key type
crypt.setKey(privateKeyPem);
crypt.setKey(publicKeyPem);setPrivateKey(key)
Sets the private key for decryption operations.
#### Parameters
| Parameter | Type | Description |
|:----------|:-----|:------------|
| key | string | PEM-formatted RSA private key |
#### Returns
void
#### Example
const privateKey = -----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA4f5wg5l2hKsTeNem/V41fGnJm6gOdrj8ym3rFkEjWT9u
...
-----END RSA PRIVATE KEY-----;crypt.setPrivateKey(privateKey);
setPublicKey(key)
Sets the public key for encryption operations.
#### Parameters
| Parameter | Type | Description |
|:----------|:-----|:------------|
| key | string | PEM-formatted RSA public key |
#### Returns
void
#### Example
const publicKey = -----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNem
...
-----END PUBLIC KEY-----;crypt.setPublicKey(publicKey);
getPrivateKey()
Returns the current private key in PEM format.
#### Returns
string - PEM-formatted private key
#### Example
const privateKey = crypt.getPrivateKey();
console.log(privateKey);getPublicKey()
Returns the current public key in PEM format. If only a private key is set, this will derive and return the corresponding public key.
#### Returns
string - PEM-formatted public key
#### Example
// After setting a private key
crypt.setPrivateKey(privateKey);
const publicKey = crypt.getPublicKey(); // Derived from private keygetKey(callback?)
Generates a new RSA key pair.
#### Parameters
| Parameter | Type | Description |
|:----------|:-----|:------------|
| callback | function | Optional callback for async generation |
#### Returns
- If callback provided: void (result passed to callback)
- If no callback: Object with key property
#### Example
// Synchronous generation
const result = crypt.getKey();
console.log('Generated key');// Asynchronous generation
crypt.getKey(() => {
console.log('Key generated asynchronously');
const privateKey = crypt.getPrivateKey();
const publicKey = crypt.getPublicKey();
});
---
Encryption/Decryption
encrypt(text)
Encrypts the given text using the current public key.
#### Parameters
| Parameter | Type | Description |
|:----------|:-----|:------------|
| text | string | Text to encrypt |
#### Returns
string | false - Base64-encoded encrypted text, or false if encryption fails
#### Example
crypt.setPublicKey(publicKey);
const encrypted = crypt.encrypt('Hello, World!');if (encrypted) {
console.log('Encrypted:', encrypted);
} else {
console.log('Encryption failed');
}
#### Notes
- Requires a public key to be set
- Input length is limited by key size (see Key Size Limitations)
- Returns false if no key is set or encryption fails
decrypt(text)
Decrypts the given encrypted text using the current private key.
#### Parameters
| Parameter | Type | Description |
|:----------|:-----|:------------|
| text | string | Base64-encoded encrypted text |
#### Returns
string | false - Decrypted text, or false if decryption fails
#### Example
crypt.setPrivateKey(privateKey);
const decrypted = crypt.decrypt(encryptedText);if (decrypted) {
console.log('Decrypted:', decrypted);
} else {
console.log('Decryption failed');
}
#### Notes
- Requires a private key to be set
- Returns false if no key is set, wrong key is used, or decryption fails
---
Signing/Verification
sign(text, digestMethod, digestEncoding)
Signs the given text using the private key.
#### Parameters
| Parameter | Type | Default | Description |
|:----------|:-----|:--------|:------------|
| text | string | - | Text to sign |
| digestMethod | string | 'sha256' | Hash algorithm |
| digestEncoding | string | 'base64' | Encoding for the signature |
#### Returns
string | false - Signature, or false if signing fails
#### Example
crypt.setPrivateKey(privateKey);
const signature = crypt.sign('message to sign');
console.log('Signature:', signature);verify(text, signature, digestMethod)
Verifies a signature using the public key.
#### Parameters
| Parameter | Type | Default | Description |
|:----------|:-----|:--------|:------------|
| text | string | - | Original text |
| signature | string | - | Signature to verify |
| digestMethod | string | 'sha256' | Hash algorithm |
#### Returns
boolean - true if signature is valid, false otherwise
#### Example
crypt.setPublicKey(publicKey);
const isValid = crypt.verify('message to sign', signature);
console.log('Signature valid:', isValid);---
Utility Methods
getKeySize()
Returns the size of the current key in bits.
#### Returns
number - Key size in bits
#### Example
crypt.setPrivateKey(privateKey);
const keySize = crypt.getKeySize();
console.log('Key size:', keySize, 'bits');getMaxMessageSize()
Returns the maximum message size that can be encrypted with the current key.
#### Returns
number - Maximum message size in bytes
#### Example
crypt.setPublicKey(publicKey);
const maxSize = crypt.getMaxMessageSize();
console.log('Max message size:', maxSize, 'bytes');---
Error Handling
All methods return false when they fail. Common failure scenarios:
- No key set: Attempting encryption/decryption without setting appropriate keys
- Invalid key format: Malformed PEM keys
- Message too long: Exceeding key size limitations
- Wrong key: Using incorrect key for decryption
- Corruption: Tampered encrypted data
Best Practices
Always check return values:
const encrypted = crypt.encrypt(message);
if (!encrypted) {
throw new Error('Encryption failed');
}const decrypted = crypt.decrypt(encrypted);
if (!decrypted) {
throw new Error('Decryption failed');
}
---
Type Definitions
For TypeScript users, JSEncrypt includes type definitions:
interface JSEncryptOptions {
default_key_size?: number;
}declare class JSEncrypt {
constructor(options?: JSEncryptOptions);
setKey(key: string): void;
setPrivateKey(key: string): void;
setPublicKey(key: string): void;
getPrivateKey(): string;
getPublicKey(): string;
getKey(callback?: () => void): any;
encrypt(text: string): string | false;
decrypt(text: string): string | false;
sign(text: string, digestMethod?: string, digestEncoding?: string): string | false;
verify(text: string, signature: string, digestMethod?: string): boolean;
getKeySize(): number;
getMaxMessageSize(): number;
}
---
Examples
---
layout: default
title: Examples
parent: Docs
nav_order: 3
permalink: /docs/examples/
aliases:
- /docs/examples.html
---
Examples
{: .no_toc }
Real-world examples showing how to use JSEncrypt for common encryption scenarios.
{: .fs-6 .fw-300 }
Table of contents
{: .no_toc .text-delta }
1. TOC
{:toc}
---
Basic Encryption/Decryption
Simple Text Encryption
import { JSEncrypt } from 'jsencrypt';// Initialize JSEncrypt
const crypt = new JSEncrypt();
// Set your RSA key pair
const privateKey = -----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA...
-----END RSA PRIVATE KEY-----;
const publicKey = -----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----;
crypt.setPrivateKey(privateKey);
crypt.setPublicKey(publicKey);
// Encrypt sensitive data
const message = "This is a secret message";
const encrypted = crypt.encrypt(message);
console.log('Encrypted:', encrypted);
// Decrypt the message
const decrypted = crypt.decrypt(encrypted);
console.log('Decrypted:', decrypted); // "This is a secret message"
Encrypting User Credentials
import { JSEncrypt } from 'jsencrypt';function encryptCredentials(username, password, publicKey) {
const crypt = new JSEncrypt();
crypt.setPublicKey(publicKey);
// Create credentials object
const credentials = JSON.stringify({
username: username,
password: password,
timestamp: Date.now()
});
// Encrypt the credentials
const encrypted = crypt.encrypt(credentials);
return encrypted;
}
// Usage
const publicKey = -----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----;
const encryptedCreds = encryptCredentials('john.doe', 'myPassword123', publicKey);
// Send encrypted credentials to server
fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ encryptedCredentials: encryptedCreds })
});
---
SHA-256 Digital Signatures
Using the Convenience Methods
JSEncrypt provides convenient signSha256() and verifySha256() methods that automatically handle SHA-256 hashing for you.
import { JSEncrypt } from 'jsencrypt';// Initialize with your key pair
const crypt = new JSEncrypt();
crypt.setPrivateKey(privateKey);
crypt.setPublicKey(publicKey);
// Simple message signing with SHA-256
const message = "Important data to sign";
const signature = crypt.signSha256(message);
console.log('Signature:', signature);
const isValid = crypt.verifySha256(message, signature);
console.log('Signature valid:', isValid); // true
API Token Validation
/ Detailed source-code truncated for AI context efficiency. /Message Integrity Verification
/ Detailed source-code truncated for AI context efficiency. /Simple JWT Implementation
Here's a straightforward JWT implementation using the signSha256 and verifySha256 methods:
/ Detailed source-code truncated for AI context efficiency. /---
JWT Token Validation with Public Key
Validating JWT Tokens with RSA Signatures / Public Key
/ Detailed source-code truncated for AI context efficiency. /---
Secure API Communication
Client-Server Encrypted Communication
// Client-side encryption
class SecureAPIClient {
constructor(serverPublicKey, clientPrivateKey) {
this.serverPublicKey = serverPublicKey;
this.clientPrivateKey = clientPrivateKey;
this.encryptor = new JSEncrypt();
this.decryptor = new JSEncrypt();
this.encryptor.setPublicKey(serverPublicKey);
this.decryptor.setPrivateKey(clientPrivateKey);
}
async secureRequest(endpoint, data) {
// Encrypt the request data
const encryptedData = this.encryptor.encrypt(JSON.stringify(data));
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Encrypted': 'true'
},
body: JSON.stringify({ encrypted: encryptedData })
});
const result = await response.json();
// Decrypt the response
if (result.encrypted) {
const decryptedResponse = this.decryptor.decrypt(result.encrypted);
return JSON.parse(decryptedResponse);
}
return result;
}
}// Usage
const client = new SecureAPIClient(serverPublicKey, clientPrivateKey);
const userData = await client.secureRequest('/api/user/profile', {
userId: 12345,
fields: ['name', 'email', 'preferences']
});
Server-side Decryption (Node.js)
// Server-side (Node.js with Express)
const express = require('express');
const JSEncrypt = require('jsencrypt');const app = express();
app.use(express.json());
const serverPrivateKey = -----BEGIN RSA PRIVATE KEY-----...-----END RSA PRIVATE KEY-----;
const serverPublicKey = -----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----;
const decryptor = new JSEncrypt();
const encryptor = new JSEncrypt();
decryptor.setPrivateKey(serverPrivateKey);
encryptor.setPublicKey(serverPublicKey);
app.post('/api/user/profile', (req, res) => {
try {
// Decrypt incoming data
const encryptedData = req.body.encrypted;
const decryptedData = decryptor.decrypt(encryptedData);
const requestData = JSON.parse(decryptedData);
// Process the request
const userProfile = getUserProfile(requestData.userId, requestData.fields);
// Encrypt the response
const encryptedResponse = encryptor.encrypt(JSON.stringify(userProfile));
res.json({ encrypted: encryptedResponse });
} catch (error) {
res.status(400).json({ error: 'Decryption failed' });
}
});
---
Digital Document Signing
Document Integrity and Authentication
/ Detailed source-code truncated for AI context efficiency. /---
Secure File Upload
Encrypting Files Before Upload
/ Detailed source-code truncated for AI context efficiency. /---
License Key Generation and Validation
Software License Management
/ Detailed source-code truncated for AI context efficiency. /---
Browser Storage Encryption
Encrypting Sensitive Data in localStorage
/ Detailed source-code truncated for AI context efficiency. /---
Key Generation and Management
Generating RSA Key Pairs
/ Detailed source-code truncated for AI context efficiency. /---
Error Handling and Best Practices
Robust Encryption with Error Handling
/ Detailed source-code truncated for AI context efficiency. /---
Security Considerations
Best Practices for Production Use
/ Detailed source-code truncated for AI context efficiency. /These examples demonstrate practical, real-world applications of the JSEncrypt library. Remember to:
1. Never expose private keys in client-side code
2. Use HTTPS for all communications
3. Validate input data before encryption
4. Handle errors gracefully
5. Keep keys secure and rotate them regularly
6. Consider key size (minimum 2048 bits for RSA)
7. Use proper random number generation for nonces and salts
---
Key Management
---
layout: default
title: Key Management
parent: Docs
nav_order: 5
permalink: /docs/key-management/
---
Key Management
{: .fs-9 }
Comprehensive guide to managing RSA keys with JSEncrypt
{: .fs-6 .fw-300 }
---
Overview
Proper key management is crucial for maintaining the security of your RSA encryption implementation. This guide covers best practices for generating, storing, and using RSA keys with JSEncrypt.
Key Generation Methods
OpenSSL Generation (Recommended)
For production applications, generate keys using OpenSSL for maximum security:
Generate 2048-bit private key (minimum recommended)
openssl genrsa -out private.pem 2048Generate 4096-bit private key (higher security)
openssl genrsa -out private.pem 4096Extract public key
openssl rsa -pubout -in private.pem -out public.pemGenerate encrypted private key (password protected)
openssl genrsa -aes256 -out private_encrypted.pem 2048JSEncrypt Generation (Development/Testing)
For development, testing, or client-side applications:
import { JSEncrypt } from 'jsencrypt';// Generate key pair synchronously
const crypt = new JSEncrypt({ default_key_size: 2048 });
const privateKey = crypt.getPrivateKey();
const publicKey = crypt.getPublicKey();
// Generate key pair asynchronously (recommended for larger keys)
const cryptAsync = new JSEncrypt({ default_key_size: 2048 });
cryptAsync.getKey(() => {
const privateKey = cryptAsync.getPrivateKey();
const publicKey = cryptAsync.getPublicKey();
// Keys are ready to use
});
Key Formats
PEM Format (Standard)
JSEncrypt supports standard PEM-formatted keys:
Private Key (PKCS#1):
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA4f5wg5l2hKsTeNem/V41fGnJm6gOdrj8ym3rFkEjWT9u...
-----END RSA PRIVATE KEY-----Public Key (PKCS#8):
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlOJu6TyygqxfWT7eLtGDw...
-----END PUBLIC KEY-----Key Components
RSA keys contain several mathematical components:
| Component | Description | JSEncrypt Property |
|-----------|-------------|-------------------|
| n | Modulus | getKey().n |
| e | Public exponent | getKey().e |
| d | Private exponent | getKey().d |
| p | Prime factor 1 | getKey().p |
| q | Prime factor 2 | getKey().q |
| dmp1 | d mod (p-1) | getKey().dmp1 |
| dmq1 | d mod (q-1) | getKey().dmq1 |
| coeff | Coefficient | getKey().coeff |
Working with Keys
Loading Existing Keys
import { JSEncrypt } from 'jsencrypt';const crypt = new JSEncrypt();
// Load private key (enables both encryption and decryption)
crypt.setPrivateKey(-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA...
-----END RSA PRIVATE KEY-----);
// Load public key only (encryption only)
crypt.setPublicKey(-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD...
-----END PUBLIC KEY-----);
Extracting Keys
// Get keys as PEM strings
const privateKeyPEM = crypt.getPrivateKey();
const publicKeyPEM = crypt.getPublicKey();// Get keys as base64 (without headers)
const privateKeyB64 = crypt.getPrivateKeyB64();
const publicKeyB64 = crypt.getPublicKeyB64();
// Get key object for advanced operations
const keyObject = crypt.getKey();
console.log('Key size:', keyObject.n.bitLength());
Key Validation
function validateKey(crypt) {
const key = crypt.getKey();
if (!key) {
throw new Error('No key loaded');
}
// Check key size
const keySize = key.n.bitLength();
if (keySize < 1024) {
console.warn(Key size ${keySize} is below recommended minimum (2048));
}
// Test encryption/decryption if private key is available
if (key.d) {
const testMessage = 'test';
const encrypted = crypt.encrypt(testMessage);
const decrypted = crypt.decrypt(encrypted);
if (testMessage !== decrypted) {
throw new Error('Key validation failed: encryption/decryption mismatch');
}
}
return true;
}Troubleshooting
Common Key Issues
1. Invalid Key Format
// Ensure proper PEM headers and line breaks
const invalidKey = "MIIEowIBAAKCAQEA..."; // Missing headers
const validKey = -----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA...
-----END RSA PRIVATE KEY-----;2. Key Size Problems
// Check key size
const keySize = crypt.getKey().n.bitLength();
if (keySize < 2048) {
console.warn('Key size too small for production use');
}3. Mixed Key Types
// Don't mix different key types
// Wrong:
crypt.setPublicKey(somePrivateKey);// Correct:
crypt.setPrivateKey(privateKey); // Sets both private and derives public
// OR
crypt.setPublicKey(publicKey); // Sets only public key
Key Compatibility
// Test key compatibility
function testKeyCompatibility(privateKey, publicKey) {
const sender = new JSEncrypt();
const receiver = new JSEncrypt();
sender.setPublicKey(publicKey);
receiver.setPrivateKey(privateKey);
const testData = 'compatibility test';
const encrypted = sender.encrypt(testData);
const decrypted = receiver.decrypt(encrypted);
return testData === decrypted;
}Security Considerations
- Never expose private keys in client-side code or logs
- Use strong key sizes (minimum 2048-bit for production)
- Implement key rotation for long-running applications
- Validate key integrity before use
- Use encrypted storage for sensitive keys
- Monitor key usage and access patterns
---
Next Steps
- Review Security Best Practices for comprehensive security guidance
- Check the API Reference for detailed method documentation
- Explore Examples for practical implementation patterns
---
Security
---
layout: default
title: Security Best Practices
parent: Docs
nav_order: 6
permalink: /docs/security/
---
Security Best Practices
{: .fs-9 }
Essential security guidelines for implementing RSA encryption with JSEncrypt
{: .fs-6 .fw-300 }
---
Overview
Security is paramount when implementing RSA encryption. This guide provides comprehensive security best practices to ensure your JSEncrypt implementation remains secure against common threats and vulnerabilities.
Key Security Fundamentals
Key Generation Security
✅ Do:
- Use OpenSSL for production key generation
- Generate keys with minimum 2048-bit size (4096-bit preferred)
- Use cryptographically secure random number generators
- Generate keys in secure environments
Secure key generation with OpenSSL
openssl genrsa -out private.pem 4096Generate password-protected keys for additional security
openssl genrsa -aes256 -out private_protected.pem 4096❌ Don't:
- Use JavaScript key generation for production (except specific use cases)
- Generate keys smaller than 2048 bits
- Reuse the same key pair across multiple applications
- Generate keys on untrusted machines
Key Storage Security
✅ Secure Storage Practices:
// Server-side (Node.js)
const fs = require('fs');
const path = require('path');// Store keys outside web root
const KEYS_DIR = process.env.KEYS_DIR || '/secure/keys';
const privateKey = fs.readFileSync(
path.join(KEYS_DIR, 'private.pem'),
{ encoding: 'utf8', mode: 0o600 } // Restrict file permissions
);
// Use environment variables
const keyPath = process.env.PRIVATE_KEY_PATH;
if (!keyPath) {
throw new Error('PRIVATE_KEY_PATH environment variable not set');
}
❌ Insecure Storage:
// Never do this:
const privateKey = "-----BEGIN RSA PRIVATE KEY-----..."; // Hardcoded in source
localStorage.setItem('privateKey', privateKey); // Client-side storage
const key = await fetch('/api/private-key'); // Exposing via APIData Protection
Input Validation and Sanitization
function secureEncrypt(data, crypt) {
// Validate input
if (typeof data !== 'string') {
throw new Error('Data must be a string');
}
// Check data length (RSA has size limits)
const keySize = crypt.getKey().n.bitLength();
const maxLength = Math.floor(keySize / 8) - 11; // PKCS#1 padding overhead
if (data.length > maxLength) {
throw new Error(Data too long. Maximum length: ${maxLength} bytes);
}
// Validate key is loaded
if (!crypt.getKey()) {
throw new Error('No encryption key loaded');
}
return crypt.encrypt(data);
}Secure Data Handling
class SecureDataHandler {
constructor(privateKey) {
this.crypt = new JSEncrypt();
this.crypt.setPrivateKey(privateKey);
}
// Secure encryption with validation
encrypt(plaintext) {
if (!plaintext || typeof plaintext !== 'string') {
throw new Error('Invalid plaintext data');
}
const encrypted = this.crypt.encrypt(plaintext);
if (!encrypted) {
throw new Error('Encryption failed');
}
return encrypted;
}
// Secure decryption with validation
decrypt(ciphertext) {
if (!ciphertext || typeof ciphertext !== 'string') {
throw new Error('Invalid ciphertext data');
}
const decrypted = this.crypt.decrypt(ciphertext);
if (decrypted === false) {
throw new Error('Decryption failed - invalid ciphertext or key');
}
return decrypted;
}
// Clear sensitive data from memory
destroy() {
this.crypt = null;
}
}Authentication and Signatures
Digital Signatures
import { JSEncrypt } from 'jsencrypt';
import { sha256 } from 'crypto-hash'; // Or your preferred hash libraryclass SecureSignature {
constructor(privateKey, publicKey) {
this.signer = new JSEncrypt();
this.verifier = new JSEncrypt();
this.signer.setPrivateKey(privateKey);
this.verifier.setPublicKey(publicKey);
}
// Sign data with SHA-256 hashing
async signData(data) {
// Hash the data first
const hash = await sha256(data);
// Sign the hash
const signature = this.signer.sign(hash, 'sha256');
if (!signature) {
throw new Error('Signature generation failed');
}
return {
data: data,
signature: signature,
algorithm: 'SHA256withRSA',
timestamp: new Date().toISOString()
};
}
// Verify signature
async verifySignature(signedData) {
const { data, signature, algorithm } = signedData;
if (algorithm !== 'SHA256withRSA') {
throw new Error('Unsupported signature algorithm');
}
// Hash the data
const hash = await sha256(data);
// Verify signature
return this.verifier.verify(hash, signature, 'sha256');
}
}
SHA-256 Convenience Methods
// Using JSEncrypt's built-in SHA-256 methods (secure)
const crypt = new JSEncrypt();
crypt.setPrivateKey(privateKey);// Sign with SHA-256
const message = "Important document content";
const signature = crypt.signSha256(message);
// Verify signature
const isValid = crypt.verifySha256(message, signature);
if (!isValid) {
throw new Error('Signature verification failed');
}
Network Security
Secure Communication
// Example: Secure API communication
class SecureAPI {
constructor(publicKey, privateKey) {
this.encryptor = new JSEncrypt();
this.decryptor = new JSEncrypt();
this.encryptor.setPublicKey(publicKey);
this.decryptor.setPrivateKey(privateKey);
}
async sendSecureRequest(endpoint, data) {
// Encrypt sensitive data
const encryptedData = this.encryptor.encrypt(JSON.stringify(data));
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Encryption': 'RSA-OAEP'
},
body: JSON.stringify({ encrypted: encryptedData })
});
if (!response.ok) {
throw new Error(HTTP ${response.status}: ${response.statusText});
}
const result = await response.json();
// Decrypt response if encrypted
if (result.encrypted) {
const decrypted = this.decryptor.decrypt(result.encrypted);
return JSON.parse(decrypted);
}
return result;
}
}HTTPS and Transport Security
// Always use HTTPS in production
const secureEndpoint = 'https://api.example.com/secure';
// Never: const insecureEndpoint = 'http://api.example.com/secure';// Validate SSL certificates
const response = await fetch(secureEndpoint, {
headers: {
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains'
}
});
Error Handling and Logging
Secure Error Handling
/ Detailed source-code truncated for AI context efficiency. /Safe Logging Practices
// ✅ Safe logging
logger.info('Encryption successful', {
operation: 'encrypt',
keySize: crypt.getKey().n.bitLength(),
timestamp: new Date().toISOString()
});// ❌ Dangerous logging
logger.info('Encrypting data', { data: sensitiveData }); // Exposes data
logger.debug('Using key', { privateKey: privateKey }); // Exposes key
Memory and Resource Security
Secure Memory Handling
/ Detailed source-code truncated for AI context efficiency. /Input Validation and Sanitization
Comprehensive Input Validation
/ Detailed source-code truncated for AI context efficiency. /Production Deployment Security
Environment Configuration
// production-config.js
module.exports = {
// Security headers
security: {
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:", "https:"],
},
},
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
},
// Key management
encryption: {
keyRotationInterval: 24 60 60 * 1000, // 24 hours
minKeySize: 2048,
preferredKeySize: 4096,
keyStoragePath: process.env.KEY_STORAGE_PATH,
backupKeyPath: process.env.BACKUP_KEY_PATH
},
// Monitoring
logging: {
level: 'info',
auditEncryption: true,
auditDecryption: true,
auditKeyAccess: true
}
};Security Monitoring
class SecurityMonitor {
constructor(config) {
this.config = config;
this.metrics = {
encryptionCount: 0,
decryptionCount: 0,
failureCount: 0,
keyAccessCount: 0
};
}
logEncryption(success, keySize) {
this.metrics.encryptionCount++;
if (!success) {
this.metrics.failureCount++;
this.alertSecurityTeam('encryption_failure', {
timestamp: new Date().toISOString(),
keySize: keySize
});
}
}
logKeyAccess(keyId, operation) {
this.metrics.keyAccessCount++;
// Log key access for audit
console.log(JSON.stringify({
event: 'key_access',
keyId: keyId,
operation: operation,
timestamp: new Date().toISOString(),
source: this.getRequestSource()
}));
}
alertSecurityTeam(event, details) {
// Implement your security alerting system
console.error('SECURITY ALERT:', event, details);
}
getRequestSource() {
// Implement request source tracking
return process.env.NODE_ENV || 'unknown';
}
getMetrics() {
return { ...this.metrics };
}
}Security Checklist
Pre-Production Checklist
- [ ] Key Generation: Using OpenSSL with 2048+ bit keys
- [ ] Key Storage: Keys stored securely outside web root
- [ ] Environment Variables: Sensitive configuration in env vars
- [ ] Input Validation: All inputs validated and sanitized
- [ ] Error Handling: No sensitive data in error messages
- [ ] Logging: Security events logged, sensitive data excluded
- [ ] HTTPS: All communication over HTTPS in production
- [ ] Memory Management: Sensitive data cleared from memory
- [ ] Key Rotation: Key rotation strategy implemented
- [ ] Monitoring: Security monitoring and alerting in place
Runtime Security Monitoring
- [ ] Failed Decryption Attempts: Monitor and alert on failures
- [ ] Key Access Patterns: Log all key access attempts
- [ ] Performance Anomalies: Monitor for unusual patterns
- [ ] Error Rates: Track encryption/decryption error rates
- [ ] Key Age: Monitor key age and rotation schedules
---
Common Security Pitfalls
What NOT to Do
// ❌ Never hardcode keys
const PRIVATE_KEY = "-----BEGIN RSA PRIVATE KEY-----...";// ❌ Never log sensitive data
console.log('Decrypted data:', decryptedPassword);
// ❌ Never expose keys in client-side code
window.privateKey = getPrivateKey();
// ❌ Never ignore encryption failures
const encrypted = crypt.encrypt(data);
// No check if encryption succeeded
// ❌ Never use weak key sizes
const weakCrypt = new JSEncrypt({ default_key_size: 512 });
---
Additional Resources
- OWASP Cryptographic Storage Cheat Sheet
- NIST Cryptographic Standards
- Key Management Best Practices
- JSEncrypt API Reference
---