UNPKG

@kya-os/mcp-i

Version:

The TypeScript MCP framework with identity features built-in

152 lines (151 loc) 5.76 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SimpleEncryption = exports.AudienceKeyEncryption = void 0; const crypto_1 = require("crypto"); /** * Audience-key encryption for ktaEncrypted mode * Uses X25519 key exchange + ChaCha20-Poly1305 AEAD */ class AudienceKeyEncryption { /** * Generate a new key pair for encryption */ static async generateKeyPair() { const keyPair = await crypto_1.webcrypto.subtle.generateKey({ name: "X25519", }, true, // extractable ["deriveKey"]); // Type assertion since we know X25519 returns a CryptoKeyPair return keyPair; } /** * Encrypt data for a specific audience public key */ static async encrypt(data, audiencePublicKey) { // Generate ephemeral key pair const ephemeralKeyPair = await this.generateKeyPair(); // Import audience public key const audiencePubKey = await this.importPublicKey(audiencePublicKey); // Derive shared secret const sharedSecret = await crypto_1.webcrypto.subtle.deriveKey({ name: "X25519", public: audiencePubKey, }, ephemeralKeyPair.privateKey, { name: "ChaCha20-Poly1305", length: 256, }, false, // not extractable ["encrypt"]); // Generate random nonce const nonce = crypto_1.webcrypto.getRandomValues(new Uint8Array(12)); // Encrypt the data const encoder = new TextEncoder(); const dataBytes = encoder.encode(data); const ciphertext = await crypto_1.webcrypto.subtle.encrypt({ name: "ChaCha20-Poly1305", iv: nonce, }, sharedSecret, dataBytes); // Export ephemeral public key const ephemeralPublicKey = await this.exportPublicKey(ephemeralKeyPair.publicKey); return { ciphertext: Buffer.from(ciphertext).toString("base64"), nonce: Buffer.from(nonce).toString("base64"), publicKey: ephemeralPublicKey, }; } /** * Decrypt data using private key */ static async decrypt(params) { // Import keys const ephemeralPublicKey = await this.importPublicKey(params.publicKey); const privateKey = await this.importPrivateKey(params.privateKey); // Derive shared secret const sharedSecret = await crypto_1.webcrypto.subtle.deriveKey({ name: "X25519", public: ephemeralPublicKey, }, privateKey, { name: "ChaCha20-Poly1305", length: 256, }, false, // not extractable ["decrypt"]); // Decrypt the data const ciphertext = Buffer.from(params.ciphertext, "base64"); const nonce = Buffer.from(params.nonce, "base64"); const decrypted = await crypto_1.webcrypto.subtle.decrypt({ name: "ChaCha20-Poly1305", iv: nonce, }, sharedSecret, ciphertext); const decoder = new TextDecoder(); return decoder.decode(decrypted); } /** * Import public key from base64 string */ static async importPublicKey(publicKey) { const keyBytes = Buffer.from(publicKey, "base64"); return await crypto_1.webcrypto.subtle.importKey("raw", keyBytes, { name: "X25519", }, false, []); } /** * Import private key from base64 string */ static async importPrivateKey(privateKey) { const keyBytes = Buffer.from(privateKey, "base64"); return await crypto_1.webcrypto.subtle.importKey("raw", keyBytes, { name: "X25519", }, false, ["deriveKey"]); } /** * Export public key to base64 string */ static async exportPublicKey(publicKey) { const keyBytes = await crypto_1.webcrypto.subtle.exportKey("raw", publicKey); return Buffer.from(keyBytes).toString("base64"); } /** * Export private key to base64 string */ static async exportPrivateKey(privateKey) { const keyBytes = await crypto_1.webcrypto.subtle.exportKey("raw", privateKey); return Buffer.from(keyBytes).toString("base64"); } } exports.AudienceKeyEncryption = AudienceKeyEncryption; /** * Simple symmetric encryption for testing */ class SimpleEncryption { /** * Encrypt data with a password (for testing only) */ static async encrypt(data, password) { // This is a simple implementation for testing // In production, use proper key derivation and authenticated encryption const encoder = new TextEncoder(); const dataBytes = encoder.encode(data); const passwordBytes = encoder.encode(password); // Simple XOR encryption (NOT secure, for testing only) const encrypted = new Uint8Array(dataBytes.length); for (let i = 0; i < dataBytes.length; i++) { encrypted[i] = dataBytes[i] ^ passwordBytes[i % passwordBytes.length]; } return Buffer.from(encrypted).toString("base64"); } /** * Decrypt data with a password (for testing only) */ static async decrypt(encryptedData, password) { const encrypted = Buffer.from(encryptedData, "base64"); const encoder = new TextEncoder(); const passwordBytes = encoder.encode(password); // Simple XOR decryption (NOT secure, for testing only) const decrypted = new Uint8Array(encrypted.length); for (let i = 0; i < encrypted.length; i++) { decrypted[i] = encrypted[i] ^ passwordBytes[i % passwordBytes.length]; } const decoder = new TextDecoder(); return decoder.decode(decrypted); } } exports.SimpleEncryption = SimpleEncryption;