UNPKG

@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.

170 lines (169 loc) 7.49 kB
/** * Personal encryption using private keys * For encrypting data that only the key owner can decrypt */ 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, deriveKey, encryptAES, decryptAES, stringToBytes, bytesToString, combineBuffers, splitBuffer, SALT_SIZE, IV_SIZE, AUTH_TAG_SIZE, getCurrentTimestamp, compressData, decompressData } from './utils.js'; /** * Encrypt data using a private key (personal encryption) * Only the private key owner can decrypt this data */ export function encryptPersonal(data, privateKey, options) { return __awaiter(this, void 0, void 0, function* () { // Convert inputs let dataBytes = typeof data === 'string' ? stringToBytes(data) : data; // Validate and convert private key let privateKeyBytes; if (typeof privateKey === 'string') { try { if (!privateKey || privateKey.length < 32) { throw new Error('Invalid private key format'); } privateKeyBytes = decodeBase58(privateKey); } catch (error) { throw new Error('Invalid private key: unable to decode base58'); } } else { privateKeyBytes = privateKey; } // Validate private key length (should be 32 or 64 bytes for ed25519) if (!privateKeyBytes || (privateKeyBytes.length !== 32 && privateKeyBytes.length !== 64)) { throw new Error('Invalid private key: must be 32 or 64 bytes'); } // Check for invalid key patterns (all zeros, etc.) const isAllZeros = privateKeyBytes.every(byte => byte === 0); const isAllOnes = privateKeyBytes.every(byte => byte === 255); if (isAllZeros || isAllOnes) { throw new Error('Invalid private key: key cannot be all zeros or all ones'); } // Compress if requested if (options === null || options === void 0 ? void 0 : options.compress) { dataBytes = yield compressData(dataBytes); } // Generate salt for key derivation const salt = generateRandomBytes(SALT_SIZE); // Derive encryption key from private key const encryptionKey = deriveKey(privateKeyBytes, salt); // Encrypt the data const { encrypted, iv, authTag } = encryptAES(dataBytes, encryptionKey); // Combine salt, iv, authTag, and encrypted data const combined = combineBuffers(salt, iv, authTag, encrypted); // Create metadata const metadata = Object.assign({ salt: encodeBase58(salt), nonce: encodeBase58(iv), timestamp: getCurrentTimestamp(), version: '1.0.0' }, options === null || options === void 0 ? void 0 : options.customMetadata // Spread custom metadata ); // Add compression flag to metadata if used if (options === null || options === void 0 ? void 0 : options.compress) { metadata.compressed = true; } return { encryptedData: encodeBase58(combined), method: EncryptionMethod.PERSONAL, metadata }; }); } /** * Decrypt personal encrypted data */ export function decryptPersonal(encryptionResult, privateKey) { return __awaiter(this, void 0, void 0, function* () { if (encryptionResult.method !== EncryptionMethod.PERSONAL) { throw new Error('Invalid encryption method for personal decryption'); } const metadata = encryptionResult.metadata; const privateKeyBytes = typeof privateKey === 'string' ? decodeBase58(privateKey) : privateKey; // Decode the combined data const combined = decodeBase58(encryptionResult.encryptedData); // Split the combined data const [salt, iv, authTag, encrypted] = splitBuffer(combined, SALT_SIZE, IV_SIZE, AUTH_TAG_SIZE); // Validate metadata integrity - nonce should match IV if (metadata.nonce !== encodeBase58(iv)) { throw new Error('Metadata tampering detected: nonce mismatch'); } // Validate metadata integrity - salt should match if (metadata.salt !== encodeBase58(salt)) { throw new Error('Metadata tampering detected: salt mismatch'); } // Validate version - should be a known version const supportedVersions = ['1.0.0']; if (!supportedVersions.includes(metadata.version)) { throw new Error('Metadata tampering detected: unsupported or invalid version'); } // Derive the same encryption key const decryptionKey = deriveKey(privateKeyBytes, salt); // Decrypt the data let decrypted = decryptAES(encrypted, decryptionKey, iv, authTag); // Decompress if needed if (metadata.compressed) { decrypted = yield decompressData(decrypted); } return decrypted; }); } /** * Decrypt personal encrypted data and return as string */ export function decryptPersonalString(encryptionResult, privateKey) { return __awaiter(this, void 0, void 0, function* () { const decrypted = yield decryptPersonal(encryptionResult, privateKey); return bytesToString(decrypted); }); } /** * Create a personal encryption session for multiple operations */ export class PersonalEncryptionSession { constructor(privateKey) { const privateKeyBytes = typeof privateKey === 'string' ? decodeBase58(privateKey) : privateKey; // Generate a session salt this.salt = generateRandomBytes(SALT_SIZE); // Derive session key this.encryptionKey = deriveKey(privateKeyBytes, this.salt); } /** * Encrypt data in this session */ encrypt(data) { return __awaiter(this, void 0, void 0, function* () { const dataBytes = typeof data === 'string' ? stringToBytes(data) : data; const { encrypted, iv, authTag } = encryptAES(dataBytes, this.encryptionKey); const combined = combineBuffers(this.salt, iv, authTag, encrypted); const metadata = { salt: encodeBase58(this.salt), nonce: encodeBase58(iv), timestamp: getCurrentTimestamp(), version: '1.0.0' }; return { encryptedData: encodeBase58(combined), method: EncryptionMethod.PERSONAL, metadata }; }); } /** * Get session info */ getSessionInfo() { return { salt: encodeBase58(this.salt), keyId: encodeBase58(this.encryptionKey.slice(0, 8)) }; } }