@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
JavaScript
/**
* 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))
};
}
}