@gorbchain-xyz/chaindecode
Version:
GorbchainSDK V1.3+ - Complete Solana development toolkit with advanced cryptography, messaging, and collaboration features. Build secure applications with blockchain, DeFi, and end-to-end encryption.
184 lines (183 loc) • 8.26 kB
JavaScript
/**
* Direct encryption between two parties
* Uses public key cryptography for secure communication
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { bytesToBase58 as encodeBase58, base58ToBytes as decodeBase58 } from '../utils/base58.js';
import { EncryptionMethod } from './types.js';
import { generateRandomBytes, performKeyExchange, encryptAES, decryptAES, stringToBytes, bytesToString, combineBuffers, splitBuffer, deriveKey, IV_SIZE, AUTH_TAG_SIZE, getCurrentTimestamp, compressData, decompressData } from './utils.js';
import { Keypair } from '@solana/web3.js';
/**
* Encrypt data for a specific recipient
*/
export function encryptDirect(data, recipientPublicKey, senderPrivateKey, options) {
return __awaiter(this, void 0, void 0, function* () {
// Convert inputs
let dataBytes = typeof data === 'string' ? stringToBytes(data) : data;
const recipientPubKeyBytes = decodeBase58(recipientPublicKey);
const senderPrivKeyBytes = typeof senderPrivateKey === 'string'
? decodeBase58(senderPrivateKey)
: senderPrivateKey;
// Validate decoded keys
if (!recipientPubKeyBytes || recipientPubKeyBytes.length === 0) {
throw new Error('Invalid recipient public key');
}
if (!senderPrivKeyBytes || senderPrivKeyBytes.length === 0) {
throw new Error('Invalid sender private key');
}
// Get sender's public key
const senderKeypair = Keypair.fromSecretKey(senderPrivKeyBytes);
const senderPublicKey = senderKeypair.publicKey.toBase58();
// Compress if requested
if (options === null || options === void 0 ? void 0 : options.compress) {
dataBytes = yield compressData(dataBytes);
}
// Use recipient's public key directly for key derivation (simpler approach)
// This is secure because we're using their public key + a random salt
const salt = generateRandomBytes(32);
const sharedSecret = deriveKey(recipientPubKeyBytes, salt, 1000);
// Encrypt the data
const { encrypted, iv, authTag } = encryptAES(dataBytes, sharedSecret);
// Combine salt, iv, authTag, and encrypted data
const combined = combineBuffers(salt, iv, authTag, encrypted);
// Create metadata
const metadata = {
senderPublicKey,
recipientPublicKey,
ephemeralPublicKey: encodeBase58(salt), // Store salt instead of ephemeral key
nonce: encodeBase58(iv),
timestamp: getCurrentTimestamp(),
version: '1.0.0'
};
// Add compression flag if used
if (options === null || options === void 0 ? void 0 : options.compress) {
metadata.compressed = true;
}
return {
encryptedData: encodeBase58(combined),
method: EncryptionMethod.DIRECT,
metadata
};
});
}
/**
* Decrypt direct encrypted data
*/
export function decryptDirect(encryptionResult, recipientPrivateKey) {
return __awaiter(this, void 0, void 0, function* () {
if (encryptionResult.method !== EncryptionMethod.DIRECT) {
throw new Error('Invalid encryption method for direct decryption');
}
const metadata = encryptionResult.metadata;
const recipientPrivKeyBytes = typeof recipientPrivateKey === 'string'
? decodeBase58(recipientPrivateKey)
: recipientPrivateKey;
// Decode the combined data
const combined = decodeBase58(encryptionResult.encryptedData);
// Split the combined data
const saltSize = 32;
const [salt, iv, authTag, encrypted] = splitBuffer(combined, saltSize, IV_SIZE, AUTH_TAG_SIZE);
// Get recipient public key to derive the same shared secret
const recipientKeypair = Keypair.fromSecretKey(recipientPrivKeyBytes);
const recipientPubKeyBytes = recipientKeypair.publicKey.toBytes();
// Derive the same shared secret using recipient's public key and salt
const sharedSecret = deriveKey(recipientPubKeyBytes, salt, 1000);
// Decrypt the data
let decrypted = decryptAES(encrypted, sharedSecret, iv, authTag);
// Decompress if needed
if (metadata.compressed) {
decrypted = yield decompressData(decrypted);
}
return decrypted;
});
}
/**
* Decrypt direct encrypted data and return as string
*/
export function decryptDirectString(encryptionResult, recipientPrivateKey) {
return __awaiter(this, void 0, void 0, function* () {
const decrypted = yield decryptDirect(encryptionResult, recipientPrivateKey);
return bytesToString(decrypted);
});
}
/**
* Create a secure channel between two parties
*/
export class SecureChannel {
constructor(localPrivateKey, remotePublicKey) {
this.messageCounter = 0;
const localPrivKeyBytes = typeof localPrivateKey === 'string'
? decodeBase58(localPrivateKey)
: localPrivateKey;
const remotePubKeyBytes = decodeBase58(remotePublicKey);
// Get local public key
const localKeypair = Keypair.fromSecretKey(localPrivKeyBytes);
this.localPublicKey = localKeypair.publicKey.toBase58();
this.remotePublicKey = remotePublicKey;
// Establish shared secret
this.sharedSecret = performKeyExchange(localPrivKeyBytes, remotePubKeyBytes);
}
/**
* Encrypt a message in the channel
*/
encryptMessage(message) {
return __awaiter(this, void 0, void 0, function* () {
const messageBytes = typeof message === 'string' ? stringToBytes(message) : message;
// Add message counter to prevent replay attacks
const counter = Buffer.alloc(8);
counter.writeBigUInt64BE(BigInt(this.messageCounter++));
const dataWithCounter = combineBuffers(counter, messageBytes);
// Encrypt with shared secret
const { encrypted, iv, authTag } = encryptAES(dataWithCounter, this.sharedSecret);
const combined = combineBuffers(iv, authTag, encrypted);
const metadata = {
senderPublicKey: this.localPublicKey,
recipientPublicKey: this.remotePublicKey,
nonce: encodeBase58(iv),
timestamp: getCurrentTimestamp(),
version: '1.0.0'
};
return {
encryptedData: encodeBase58(combined),
method: EncryptionMethod.DIRECT,
metadata
};
});
}
/**
* Decrypt a message in the channel
*/
decryptMessage(encryptionResult) {
return __awaiter(this, void 0, void 0, function* () {
const combined = decodeBase58(encryptionResult.encryptedData);
const [iv, authTag, encrypted] = splitBuffer(combined, IV_SIZE, AUTH_TAG_SIZE);
const decrypted = decryptAES(encrypted, this.sharedSecret, iv, authTag);
// Extract counter and message
const counter = decrypted.slice(0, 8);
const message = decrypted.slice(8);
const counterValue = Buffer.from(counter).readBigUInt64BE();
return {
message,
counter: Number(counterValue)
};
});
}
/**
* Get channel info
*/
getChannelInfo() {
return {
localPublicKey: this.localPublicKey,
remotePublicKey: this.remotePublicKey,
messagesSent: this.messageCounter
};
}
}