@pulkitsinha007/hybrid-crypto-js 1.4.2 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -117,7 +117,7 @@ const data = await decryptAsymmetric(encryptedData, privateKey);
117
117
  ```
118
118
 
119
119
  ### `getCustomSymmetricKey(inputKey)`
120
- Provides a Crypto Key by taking custom a base string key as the input.
120
+ Provides a Crypto Key by taking a custom base string as the input.
121
121
  - **Parameter**:
122
122
  - `inputKey`: `string` - Base key string supposed to be used for encoding.
123
123
  - `options`: `Object` - Optional Configuration.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pulkitsinha007/hybrid-crypto-js",
3
- "version": "1.4.2",
3
+ "version": "1.5.0",
4
4
  "description": "Hybrid encryption package using native crypto modules for Node and Browser",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/crypto.js CHANGED
@@ -246,7 +246,7 @@ export async function decryptAsymmetric(encryptedData, privateKey) {
246
246
  }
247
247
 
248
248
  /**
249
- * Provides a Crypto Key by taking custom a base string key as the input
249
+ * Provides a Crypto Key by taking a custom base string as the input
250
250
  * @param {string} inputKey - Base key string supposed to be used for encoding
251
251
  * @param {Object} [options] - Optional configuration.
252
252
  * @param {boolean} [options.extractable=false] - Whether the key can be exported.
package/src/index.d.ts CHANGED
@@ -110,10 +110,10 @@ export function encryptAsymmetric(data: string | object, publicKey: string): Pro
110
110
  export function decryptAsymmetric<T = any>(encryptedData: string, privateKey: string): Promise<T>;
111
111
 
112
112
  /**
113
- * Provides a Crypto Key by taking custom a base string key as the input
113
+ * Provides a Crypto Key by taking a custom base string as the input
114
114
  * @param {string} inputKey - Base key string supposed to be used for encoding
115
115
  * @param {Object} [options] - Optional configuration.
116
116
  * @param {boolean} [options.extractable=false] - Whether the key can be exported.
117
117
  * @returns {Promise<CryptoKey>} The extractable AES encrypted Crypto Key
118
118
  */
119
- export async function getCustomSymmetricKey(inputKey: string, options?: {extractable?: boolean}): Promise<CryptoKey>;
119
+ export function getCustomSymmetricKey(inputKey: string, options?: {extractable?: boolean}): Promise<CryptoKey>;
@@ -1,133 +0,0 @@
1
- import http from 'http';
2
- import fs from 'fs';
3
- import path from 'path';
4
- import { fileURLToPath } from 'url';
5
- import {
6
- generateKeyPair,
7
- unwrapKey,
8
- decryptWithSymmetricKey,
9
- encryptWithSymmetricKey
10
- } from '../../../src/index.js';
11
-
12
- const __filename = fileURLToPath(import.meta.url);
13
- const __dirname = path.dirname(__filename);
14
-
15
- const PORT = 3000;
16
-
17
- // Store keys in memory
18
- let publicKey;
19
- let privateKey;
20
-
21
- // Initialize keys
22
- (async () => {
23
- try {
24
- console.log('Generating server keys...');
25
- const keys = await generateKeyPair();
26
- publicKey = keys.publicKey;
27
- privateKey = keys.privateKey;
28
- console.log('Server keys generated.');
29
- } catch (err) {
30
- console.error('Failed to generate keys:', err);
31
- process.exit(1);
32
- }
33
- })();
34
-
35
- const server = http.createServer(async (req, res) => {
36
- // CORS headers for development convenience
37
- res.setHeader('Access-Control-Allow-Origin', '*');
38
- res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
39
- res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
40
-
41
- if (req.method === 'OPTIONS') {
42
- res.writeHead(200);
43
- res.end();
44
- return;
45
- }
46
-
47
- const url = new URL(req.url, `http://${req.headers.host}`);
48
-
49
- // API Endpoints
50
- if (url.pathname === '/api/public-key' && req.method === 'GET') {
51
- res.writeHead(200, { 'Content-Type': 'application/json' });
52
- res.end(JSON.stringify({ publicKey }));
53
- return;
54
- }
55
-
56
- if (url.pathname === '/api/submit' && req.method === 'POST') {
57
- let body = '';
58
- req.on('data', chunk => body += chunk);
59
- req.on('end', async () => {
60
- try {
61
- const { wrappedKey, encryptedPackage } = JSON.parse(body);
62
-
63
- // 1. Unwrap the symmetric key
64
- const sessionKey = await unwrapKey(wrappedKey, privateKey);
65
-
66
- // 2. Decrypt the payload using the session key
67
- const decrypted = await decryptWithSymmetricKey(encryptedPackage, sessionKey);
68
- console.log('Decrypted message from client:', decrypted);
69
-
70
- // 3. Prepare a response
71
- const responsePayload = {
72
- status: 'success',
73
- receivedMessage: decrypted,
74
- serverTimestamp: Date.now(),
75
- secret: "This is a secret response encrypted with your session key!"
76
- };
77
-
78
- // 4. Encrypt the response with the SAME session key
79
- const responsePackage = await encryptWithSymmetricKey(responsePayload, sessionKey);
80
-
81
- res.writeHead(200, { 'Content-Type': 'application/json' });
82
- res.end(JSON.stringify({ encryptedResponse: responsePackage }));
83
-
84
- } catch (err) {
85
- console.error('Processing failed:', err);
86
- res.writeHead(500, { 'Content-Type': 'application/json' });
87
- res.end(JSON.stringify({ error: 'Processing failed' }));
88
- }
89
- });
90
- return;
91
- }
92
-
93
- // Static File Serving
94
- let filePath;
95
- if (url.pathname === '/') {
96
- filePath = path.join(__dirname, '../frontend/index.html');
97
- } else if (url.pathname === '/client.js') {
98
- filePath = path.join(__dirname, '../frontend/client.js');
99
- } else if (url.pathname.startsWith('/src/')) {
100
- // Map /src/xxx to ../../../src/xxx
101
- const relativePath = url.pathname.replace('/src/', '');
102
- filePath = path.join(__dirname, '../../../src', relativePath);
103
- } else {
104
- res.writeHead(404);
105
- res.end('Not Found');
106
- return;
107
- }
108
-
109
- const ext = path.extname(filePath);
110
- let contentType = 'text/html';
111
- if (ext === '.js') contentType = 'application/javascript';
112
-
113
- fs.readFile(filePath, (err, content) => {
114
- if (err) {
115
- if (err.code === 'ENOENT') {
116
- console.log('404 Not Found:', filePath);
117
- res.writeHead(404);
118
- res.end('Not Found');
119
- } else {
120
- console.error('500 Server Error:', err);
121
- res.writeHead(500);
122
- res.end('Server Error');
123
- }
124
- } else {
125
- res.writeHead(200, { 'Content-Type': contentType });
126
- res.end(content);
127
- }
128
- });
129
- });
130
-
131
- server.listen(PORT, () => {
132
- console.log(`Server running at http://localhost:${PORT}/`);
133
- });
@@ -1,92 +0,0 @@
1
- import {
2
- createSymmetricKey,
3
- wrapKey,
4
- encryptWithSymmetricKey,
5
- decryptWithSymmetricKey
6
- } from '/src/index.js';
7
-
8
- let serverPublicKey;
9
-
10
- const statusMain = document.getElementById('status-main');
11
-
12
- async function init() {
13
- try {
14
- // 1. Fetch Server Public Key (Client doesn't need its own RSA key pair anymore)
15
- const res = await fetch('/api/public-key');
16
- const data = await res.json();
17
- serverPublicKey = data.publicKey;
18
- console.log('Server public key fetched.');
19
-
20
- statusMain.textContent = 'Ready. Server Public Key initialized.';
21
- statusMain.style.color = 'green';
22
- } catch (err) {
23
- console.error(err);
24
- statusMain.textContent = 'Error initializing keys. Check console.';
25
- statusMain.style.color = 'red';
26
- }
27
- }
28
-
29
- document.getElementById('btn-send').addEventListener('click', async () => {
30
- const input = document.getElementById('input-message').value;
31
- const resultDiv = document.getElementById('result-send');
32
-
33
- if (!input) {
34
- alert('Please enter a message');
35
- return;
36
- }
37
-
38
- try {
39
- resultDiv.innerHTML = 'Generating Session Key & Encrypting...';
40
-
41
- // 1. Generate a fresh AES Session Key
42
- const sessionKey = await createSymmetricKey();
43
-
44
- // 2. Wrap the session key with Server's Public Key
45
- const wrappedKey = await wrapKey(sessionKey, serverPublicKey);
46
-
47
- // 3. Encrypt the payload with the Session Key
48
- const encryptedPackage = await encryptWithSymmetricKey(input, sessionKey);
49
-
50
- resultDiv.innerHTML += '<br>Sending wrapped key & encrypted package...';
51
-
52
- const res = await fetch('/api/submit', {
53
- method: 'POST',
54
- body: JSON.stringify({
55
- wrappedKey,
56
- encryptedPackage
57
- })
58
- });
59
-
60
- const data = await res.json();
61
-
62
- if (data.error) {
63
- throw new Error(data.error);
64
- }
65
-
66
- const { encryptedResponse } = data;
67
-
68
- resultDiv.innerHTML += '<br>Received encrypted response. Decrypting with Session Key...';
69
-
70
- // 4. Decrypt the response with the SAME Session Key
71
- const decryptedResponse = await decryptWithSymmetricKey(encryptedResponse, sessionKey);
72
-
73
- resultDiv.innerHTML = `
74
- <strong>Status:</strong> Success<br>
75
- <strong>Server Response Decrypted:</strong> <pre>${JSON.stringify(decryptedResponse, null, 2)}</pre>
76
- `;
77
- } catch (err) {
78
- console.error(err);
79
- resultDiv.textContent = 'Error during session: ' + err.message;
80
- }
81
- });
82
-
83
- // Disable the old "Get Secret" button as it's not part of the new flow
84
- const btnGet = document.getElementById('btn-get');
85
- if (btnGet) {
86
- btnGet.disabled = true;
87
- btnGet.textContent = "Deprecated (See Session Flow above)";
88
- const resultGet = document.getElementById('result-get');
89
- if (resultGet) resultGet.textContent = "This feature is replaced by the bidirectional session flow above.";
90
- }
91
-
92
- init();
@@ -1,39 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Hybrid Crypto Full Stack Example</title>
7
- <style>
8
- body { font-family: sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
9
- section { border: 1px solid #ccc; padding: 20px; margin-bottom: 20px; border-radius: 8px; }
10
- textarea { width: 100%; height: 60px; }
11
- button { padding: 10px 20px; cursor: pointer; }
12
- pre { background: #f4f4f4; padding: 10px; overflow-x: auto; }
13
- .status { margin-top: 10px; font-weight: bold; }
14
- </style>
15
- </head>
16
- <body>
17
- <h1>Hybrid Crypto Full Stack Example</h1>
18
-
19
- <div id="status-main" class="status">Initializing Keys...</div>
20
-
21
- <section>
22
- <h2>1. Client -> Server (Secure Submit)</h2>
23
- <p>Encrypt a message with the Server's Public Key. Only the server can decrypt it.</p>
24
- <textarea id="input-message" placeholder="Type a secret message..."></textarea>
25
- <br><br>
26
- <button id="btn-send">Encrypt & Send</button>
27
- <div id="result-send"></div>
28
- </section>
29
-
30
- <section>
31
- <h2>2. Server -> Client (Secure Retrieve)</h2>
32
- <p>Request a secret message from the server. The server will encrypt it with your Client Public Key.</p>
33
- <button id="btn-get">Get Secret Message</button>
34
- <div id="result-get"></div>
35
- </section>
36
-
37
- <script type="module" src="./client.js"></script>
38
- </body>
39
- </html>
@@ -1,43 +0,0 @@
1
- import { test, describe, it } from 'node:test';
2
- import assert from 'node:assert';
3
- import {
4
- generateKeyPair,
5
- encryptAsymmetric,
6
- decryptAsymmetric
7
- } from '../src/index.js';
8
-
9
- describe('Asymmetric Encryption (RSA-OAEP)', () => {
10
- it('should encrypt and decrypt a plain string', async () => {
11
- const { publicKey, privateKey } = await generateKeyPair();
12
- const originalData = "Hello, Asymmetric World!";
13
-
14
- const encryptedData = await encryptAsymmetric(originalData, publicKey);
15
- assert.notStrictEqual(encryptedData, originalData);
16
-
17
- const decryptedData = await decryptAsymmetric(encryptedData, privateKey);
18
- assert.strictEqual(decryptedData, originalData);
19
- });
20
-
21
- it('should encrypt and decrypt a JSON object', async () => {
22
- const { publicKey, privateKey } = await generateKeyPair();
23
- const originalData = { foo: "bar", baz: 123 };
24
-
25
- const encryptedData = await encryptAsymmetric(originalData, publicKey);
26
- const decryptedData = await decryptAsymmetric(encryptedData, privateKey);
27
-
28
- assert.deepStrictEqual(decryptedData, originalData);
29
- });
30
-
31
- it('should fail to decrypt with the wrong private key', async () => {
32
- const keys1 = await generateKeyPair();
33
- const keys2 = await generateKeyPair();
34
-
35
- const originalData = "Secret message";
36
- const encryptedData = await encryptAsymmetric(originalData, keys1.publicKey);
37
-
38
- await assert.rejects(
39
- () => decryptAsymmetric(encryptedData, keys2.privateKey),
40
- /OperationError|DataError/
41
- );
42
- });
43
- });
@@ -1,60 +0,0 @@
1
- import { test, describe, it, before } from 'node:test';
2
- import assert from 'node:assert';
3
- import {
4
- generateKeyPair,
5
- createSymmetricKey,
6
- wrapKey,
7
- unwrapKey,
8
- encryptWithSymmetricKey,
9
- decryptWithSymmetricKey
10
- } from '../src/index.js';
11
-
12
- describe('New Hybrid Flow (Session Based)', () => {
13
- let backendPublicKey;
14
- let backendPrivateKey;
15
-
16
- before(async () => {
17
- // 1. Backend setup: Generate RSA Key Pair
18
- const keys = await generateKeyPair();
19
- backendPublicKey = keys.publicKey;
20
- backendPrivateKey = keys.privateKey;
21
- });
22
-
23
- it('should successfully complete the full session flow', async () => {
24
- const clientPayload = "Request: Give me the secret";
25
- const serverResponsePayload = "Response: Here is the secret [12345]";
26
-
27
- // --- FRONTEND SIDE (Request) ---
28
-
29
- // 2. Client generates AES key
30
- const clientAesKey = await createSymmetricKey();
31
-
32
- // 3. Client wraps AES key with Backend Public Key
33
- const wrappedKey = await wrapKey(clientAesKey, backendPublicKey);
34
-
35
- // 4. Client encrypts payload with AES key
36
- const clientEncryptedPackage = await encryptWithSymmetricKey(clientPayload, clientAesKey);
37
-
38
- // Client sends { wrappedKey, encryptedPayload: ... } to backend
39
-
40
- // --- BACKEND SIDE ---
41
-
42
- // 5. Backend receives package. Unwraps AES key.
43
- const serverAesKey = await unwrapKey(wrappedKey, backendPrivateKey);
44
-
45
- // 6. Backend decrypts payload
46
- const decryptedRequest = await decryptWithSymmetricKey(clientEncryptedPackage, serverAesKey);
47
- assert.strictEqual(decryptedRequest, clientPayload, "Backend failed to decrypt client request");
48
-
49
- // 7. Backend encrypts response with SAME AES key
50
- const serverEncryptedPackage = await encryptWithSymmetricKey(serverResponsePayload, serverAesKey);
51
-
52
- // Backend sends { encryptedResponse: ... } to client
53
-
54
- // --- FRONTEND SIDE (Response) ---
55
-
56
- // 8. Client receives encrypted response. Decrypts with original AES key.
57
- const decryptedResponse = await decryptWithSymmetricKey(serverEncryptedPackage, clientAesKey);
58
- assert.strictEqual(decryptedResponse, serverResponsePayload, "Client failed to decrypt server response");
59
- });
60
- });