### 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](http://www-cs-students.stanford.edu/~tjw/jsbn/) by Tom Wu. ## What You'll Learn - **[Getting Started](getting-started/)** - Install and set up JSEncrypt - **[API Reference](api/)** - Complete API documentation - **[Examples](examples/)** - Real-world usage examples - **[Key Management](key-management/)** - Working with RSA keys - **[Security Best Practices](security/)** - Keep your implementations secure ## Quick Navigation
New to JSEncrypt? Start with our [Getting Started Guide](getting-started/). Looking for specific methods? Check the [API Reference](api/). Want to see examples? Browse our [Examples](examples/) section.
--- ## Need Help? - 🐛 **Found a bug?** [Report it on GitHub](https://github.com/travist/jsencrypt/issues) - 💡 **Have a question?** [Start a discussion](https://github.com/travist/jsencrypt/discussions) - 📚 **Want to contribute?** See our [Contributing Guide](https://github.com/travist/jsencrypt/blob/master/CONTRIBUTING.md) --- ### 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 ```bash npm install jsencrypt ``` ### Using yarn ```bash yarn add jsencrypt ``` ### Using CDN Include JSEncrypt directly in your HTML: ```html ``` ## Basic Usage ### 1. Import the Library #### ES6 Modules ```javascript import { JSEncrypt } from 'jsencrypt'; ``` #### CommonJS ```javascript const JSEncrypt = require('jsencrypt'); ``` #### Browser Global ```javascript // 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: ```bash # Generate a 2048-bit private key openssl genrsa -out private.pem 2048 # Extract the public key openssl rsa -pubout -in private.pem -out public.pem ``` ### 3. Basic Encryption/Decryption ```javascript // 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! ```javascript 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: ```bash # Generate a 2048-bit private key (recommended minimum) openssl genrsa -out private.pem 2048 # Generate a 4096-bit private key (higher security) openssl genrsa -out private.pem 4096 # Extract the public key openssl rsa -pubout -in private.pem -out public.pem # View the private key cat private.pem # View the public key cat public.pem ``` **Why 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: ```javascript // 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: ```javascript // 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 ```javascript // 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](../api/)** - Complete method documentation - **[Examples](../examples/)** - Real-world usage patterns - **[Key Management](../key-management/)** - Advanced key handling - **[Security Best Practices](../security/)** - 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](../examples/) for working code 2. Search [existing issues](https://github.com/travist/jsencrypt/issues) on GitHub 3. [Open a new issue](https://github.com/travist/jsencrypt/issues/new) 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 ```javascript // 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 ```javascript // 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 ```javascript 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 ```javascript 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 ```javascript 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 ```javascript // After setting a private key crypt.setPrivateKey(privateKey); const publicKey = crypt.getPublicKey(); // Derived from private key ``` ### `getKey(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 ```javascript // 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 ```javascript 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](../getting-started/#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 ```javascript 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 ```javascript 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 ```javascript 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 ```javascript 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 ```javascript 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: ```javascript 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: ```typescript 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 ```javascript 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 ```javascript 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. ```javascript 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 ```javascript // 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) ```javascript // 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: ```bash # Generate 2048-bit private key (minimum recommended) openssl genrsa -out private.pem 2048 # Generate 4096-bit private key (higher security) openssl genrsa -out private.pem 4096 # Extract public key openssl rsa -pubout -in private.pem -out public.pem # Generate encrypted private key (password protected) openssl genrsa -aes256 -out private_encrypted.pem 2048 ``` ### JSEncrypt Generation (Development/Testing) For development, testing, or client-side applications: ```javascript 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 ```javascript 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 ```javascript // 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 ```javascript 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** ```javascript // 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** ```javascript // 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** ```javascript // 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 ```javascript // 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](../security/) for comprehensive security guidance - Check the [API Reference](../api/) for detailed method documentation - Explore [Examples](../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 ```bash # Secure key generation with OpenSSL openssl genrsa -out private.pem 4096 # Generate 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:** ```javascript // 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:** ```javascript // 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 API ``` ## Data Protection ### Input Validation and Sanitization ```javascript 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 ```javascript 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 ```javascript import { JSEncrypt } from 'jsencrypt'; import { sha256 } from 'crypto-hash'; // Or your preferred hash library class 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 ```javascript // 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 ```javascript // 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 ```javascript // 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 ```javascript // ✅ 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 ```javascript // 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 ```javascript 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 ```javascript // ❌ 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](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html) - [NIST Cryptographic Standards](https://csrc.nist.gov/projects/cryptographic-standards-and-guidelines) - [Key Management Best Practices](../key-management/) - [JSEncrypt API Reference](../api/) ---