Skip to content

Commit 718210a

Browse files
authored
multi-master-key decryption and explicit memory clearing
more robust and secure with the multi-master-key decryption and explicit memory clearing
1 parent d1661ef commit 718210a

File tree

1 file changed

+47
-12
lines changed

1 file changed

+47
-12
lines changed

index.js

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,26 @@ const __dirname = path.dirname(__filename);
1818
const ALGO = "aes-256-gcm";
1919
const IV_LENGTH = 12;
2020

21+
// --- Master Keys ---
22+
const MASTER_KEY = process.env.MASTER_KEY;
23+
const BACKUP_KEYS = (process.env.BACKUP_KEYS || "")
24+
.split(",")
25+
.map(k => k.trim())
26+
.filter(Boolean);
27+
28+
if (!MASTER_KEY) {
29+
console.error(chalk.bgRed.white.bold("❌ MASTER_KEY environment variable is not set!"));
30+
process.exit(1);
31+
}
32+
33+
const ALL_MASTER_KEYS = [MASTER_KEY, ...BACKUP_KEYS];
34+
35+
// --- Session Salt for Stronger Key Derivation ---
36+
const sessionSalt = crypto.randomBytes(16);
37+
function deriveKey(masterKey) {
38+
return crypto.scryptSync(masterKey, sessionSalt, 32);
39+
}
40+
2141
/**
2242
* Encrypts a private key using a master key.
2343
* @param {string} privateKey - The private key to encrypt.
@@ -26,7 +46,7 @@ const IV_LENGTH = 12;
2646
*/
2747
function encryptPrivateKey(privateKey, masterKey) {
2848
const iv = crypto.randomBytes(IV_LENGTH);
29-
const derivedKey = crypto.scryptSync(masterKey, 'salt', 32);
49+
const derivedKey = deriveKey(masterKey);
3050
const cipher = crypto.createCipheriv(ALGO, derivedKey, iv);
3151

3252
let encrypted = cipher.update(privateKey, "utf8", "hex");
@@ -46,7 +66,7 @@ function decryptPrivateKey(encrypted, masterKey) {
4666
const [ivHex, authTagHex, data] = encrypted.split(":");
4767
const iv = Buffer.from(ivHex, "hex");
4868
const authTag = Buffer.from(authTagHex, "hex");
49-
const derivedKey = crypto.scryptSync(masterKey, 'salt', 32);
69+
const derivedKey = deriveKey(masterKey);
5070
const decipher = crypto.createDecipheriv(ALGO, derivedKey, iv);
5171
decipher.setAuthTag(authTag);
5272

@@ -56,9 +76,27 @@ function decryptPrivateKey(encrypted, masterKey) {
5676
return decrypted;
5777
}
5878

79+
/**
80+
* Attempts to decrypt an encrypted key with any of the available master keys.
81+
* @param {string} encrypted - The encrypted key string.
82+
* @returns {string} The decrypted private key.
83+
* @throws {Error} If decryption fails with all keys.
84+
*/
85+
function decryptWithAnyKey(encrypted) {
86+
for (const key of ALL_MASTER_KEYS) {
87+
try {
88+
return decryptPrivateKey(encrypted, key);
89+
} catch {
90+
continue;
91+
}
92+
}
93+
throw new Error("❌ Failed to decrypt private key with all available master keys");
94+
}
95+
5996
// === CONFIG ===
6097
// List of public RPCs for Celo.
6198
const RPCS = [
99+
"https://celo-mainnet.infura.io/v3/f0c6b3797dd54dc2aa91cd4a463bcc57",
62100
"https://rpc.ankr.com/celo",
63101
"https://celo.drpc.org",
64102
"https://forno.celo.org",
@@ -73,13 +111,6 @@ let lastKey = null;
73111
let ENCRYPTED_KEYS = [];
74112
let ALL_WALLETS = [];
75113

76-
// === NEW: Master Key from Environment ===
77-
const MASTER_KEY = process.env.MASTER_KEY;
78-
if (!MASTER_KEY) {
79-
console.error(chalk.bgRed.white.bold("❌ MASTER_KEY environment variable is not set!"));
80-
process.exit(1);
81-
}
82-
83114
// normalize to 0x-prefixed hex string
84115
function normalizeKey(k) {
85116
if (!k) return null;
@@ -252,7 +283,7 @@ setInterval(flushTxLog, FLUSH_INTERVAL);
252283
function pickRandomKey() {
253284
const idx = Math.floor(Math.random() * ENCRYPTED_KEYS.length);
254285
const encrypted = ENCRYPTED_KEYS[idx];
255-
const privateKey = decryptPrivateKey(encrypted, MASTER_KEY);
286+
const privateKey = decryptWithAnyKey(encrypted);
256287
return privateKey;
257288
}
258289

@@ -538,8 +569,8 @@ async function main() {
538569
// === END NEW LOGIC ===
539570

540571
// Get the decrypted private key and create a new wallet instance for the transaction
541-
const key = pickRandomKey();
542-
const wallet = new ethers.Wallet(key, provider);
572+
let key = pickRandomKey();
573+
let wallet = new ethers.Wallet(key, provider);
543574
const profile = ensurePersona(wallet);
544575

545576
// === NEW: Main loop modification ===
@@ -551,6 +582,10 @@ async function main() {
551582
// Execute the transaction logic, including retries
552583
await safeSendTx(wallet, provider, profile, url);
553584

585+
// Explicit memory wipe after use
586+
key = null;
587+
wallet = null;
588+
554589
// NEW LOGIC: Use persona's avgWait for the wait loop
555590
let waitSec = Math.floor(profile.avgWait * (0.8 + Math.random() * 0.4));
556591

0 commit comments

Comments
 (0)