feat(chat): Upgrade to hybrid encryption with AES-256-GCM and RSA-OAEP

- Replace pure RSA encryption with hybrid encryption scheme for better performance
- Implement AES-256-GCM for fast message encryption without size limitations
- Use RSA-OAEP for secure AES key exchange between chat participants
- Add EncryptedPayload interface to structure encrypted data (key, IV, ciphertext, auth tag)
- Update encryptMessage() to generate random AES key and IV, encrypt with AES-GCM, then wrap AES key with RSA
- Update decryptMessage() to unwrap AES key with RSA, then decrypt message with AES-GCM
- Include GCM authentication tag for message integrity verification
- Encode all binary components as base64 strings in JSON payload for transport
- Improves encryption performance while maintaining security for end-to-end swarm messaging
This commit is contained in:
Christomatt
2026-01-27 01:42:17 +01:00
parent eb63194c56
commit 8e7c6353f3
+57 -9
View File
@@ -1,27 +1,58 @@
/**
* Swarm Chat Cryptography
*
* End-to-end encryption for chat messages using public key cryptography.
* End-to-end encryption for chat messages using hybrid encryption:
* - AES-256-GCM for message encryption (fast, no size limit)
* - RSA-OAEP for encrypting the AES key (secure key exchange)
*/
import crypto from 'crypto';
interface EncryptedPayload {
encryptedKey: string; // RSA-encrypted AES key (base64)
iv: string; // AES initialization vector (base64)
ciphertext: string; // AES-encrypted message (base64)
authTag: string; // GCM authentication tag (base64)
}
/**
* Encrypt a message using the recipient's public key
* Encrypt a message using hybrid encryption (AES + RSA)
*/
export function encryptMessage(message: string, recipientPublicKey: string): string {
try {
// Use RSA-OAEP for encryption
const encrypted = crypto.publicEncrypt(
// Generate a random AES-256 key
const aesKey = crypto.randomBytes(32);
// Generate a random IV for AES-GCM
const iv = crypto.randomBytes(12);
// Encrypt the message with AES-256-GCM
const cipher = crypto.createCipheriv('aes-256-gcm', aesKey, iv);
const encrypted = Buffer.concat([
cipher.update(message, 'utf8'),
cipher.final()
]);
const authTag = cipher.getAuthTag();
// Encrypt the AES key with RSA-OAEP
const encryptedKey = crypto.publicEncrypt(
{
key: recipientPublicKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: 'sha256',
},
Buffer.from(message, 'utf8')
aesKey
);
return encrypted.toString('base64');
// Package everything together
const payload: EncryptedPayload = {
encryptedKey: encryptedKey.toString('base64'),
iv: iv.toString('base64'),
ciphertext: encrypted.toString('base64'),
authTag: authTag.toString('base64'),
};
return JSON.stringify(payload);
} catch (error) {
console.error('Failed to encrypt message:', error);
throw new Error('Encryption failed');
@@ -29,19 +60,36 @@ export function encryptMessage(message: string, recipientPublicKey: string): str
}
/**
* Decrypt a message using the recipient's private key
* Decrypt a message using hybrid encryption (AES + RSA)
*/
export function decryptMessage(encryptedMessage: string, privateKey: string): string {
try {
const decrypted = crypto.privateDecrypt(
// Parse the encrypted payload
const payload: EncryptedPayload = JSON.parse(encryptedMessage);
// Decrypt the AES key with RSA
const aesKey = crypto.privateDecrypt(
{
key: privateKey,
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: 'sha256',
},
Buffer.from(encryptedMessage, 'base64')
Buffer.from(payload.encryptedKey, 'base64')
);
// Decrypt the message with AES-256-GCM
const decipher = crypto.createDecipheriv(
'aes-256-gcm',
aesKey,
Buffer.from(payload.iv, 'base64')
);
decipher.setAuthTag(Buffer.from(payload.authTag, 'base64'));
const decrypted = Buffer.concat([
decipher.update(Buffer.from(payload.ciphertext, 'base64')),
decipher.final()
]);
return decrypted.toString('utf8');
} catch (error) {
console.error('Failed to decrypt message:', error);