James Bachini

Encrypting Private Keys in .env

Encrypting Private Keys

It has become very normalised to store Ethereum private keys in plain text within .env files. While this is convenient, it’s a disaster waiting to happen when working in production with wallets that contain real funds.

Today, I’ll show you a better way to manage your hot wallet keys using AES encryption.

Full code for this is available at: https://github.com/jamesbachini/DotEnv-Encrypted-Private-Keys

The Problem with .env Private Keys

First off, let’s talk about why storing private keys in plain text is a terrible idea:

  1. Git accidents Ever accidentally pushed your .env file to a public repo? Congratulations, you’ve just broadcasted your private key to the world.
  2. Local security If someone gains access to your machine, they’ve got instant access to your funds. This is true if you are using environmental variables too.
  3. Trading When programmatically trading on decentralized exchanges you need wallets with real funds attached to the internet, this is an issue. It is possible to store funds in a contract but this introduces it’s own risks and slows development.

Encrypted Private Keys

To address these issues, we can encrypt our private keys before storing them in our .env file or as an environmental variable. Here’s how it works:

  1. You encrypt your private key with a passphrase.
  2. The encrypted key is stored in your .env file.
  3. When you need to use the key, to deploy a contract for example or fire up a trading bot, you decrypt it using your passphrase from the command line.

Is this perfect? no someone could still install a key logger or something on the system to trace std input but it will save you if you do something silly like share some code and forget to add .env to .gitignore

If someone gets hold of your encrypted private key, they can’t use your private key without the passphrase.

Using the Tool: Generating a New Testnet Wallet

Let’s walk through how to use this tool to generate a new testnet wallet with an encrypted private key:

  1. First, clone the repository:
   git clone https://github.com/jamesbachini/DotEnv-Encrypted-Private-Keys.git
   cd DotEnv-Encrypted-Private-Keys
  1. Install the dependencies:
   npm install
  1. Run the example script:
   node example.js
  1. Choose option 1 to “Encrypt a New Key”.
  2. Enter a strong passphrase when prompted. Bare in mind that someone could try to brute force this if they found your encrypted key.
  3. The tool will generate a new wallet and display its address. It will also give you an ENCRYPTED_PRIVATE_KEY value. Copy this to your .env file.

Voila! You’ve now got a new testnet wallet with an encrypted private key.

ENCRYPTED_PRIVATE_KEY=U2FsdGVkX19F0bnyrH4F7QpzIWXC1wSxM4NHiuq7jxITivwfcNddGLyRaxzLR6F0wauvA2a2/XEcr5iB0XzvlZ/6fBb/ZdN8g0/jXUWRQTWNA3qkRvYqanF2KhcW8/UW

Setting Up Encrypted Private Keys in Hardhat

Now, let’s integrate this into a Hardhat project:

  1. First, ensure you have the required dependencies:
   npm install ethers crypto-js dotenv
  1. Use in your hardhat.config.js file
require("@nomicfoundation/hardhat-toolbox");
const CryptoJS = require("crypto-js");
const readline = require('readline');
require("dotenv").config();

const rl = readline.createInterface({ input: process.stdin, output: process.stdout });

let sepoliaPrivateKey
rl.question('Enter the pass phrase to unlock the private key: ', (passString) => {
    const sepoliaPrivateKey = CryptoJS.AES.decrypt(process.env.ENCRYPTED_PRIVATE_KEY, passString).toString(CryptoJS.enc.Utf8);
});

exports = {
    solidity: "0.8.26",
    networks: {
        sepolia: {
        url: `https://sepolia.infura.io/v3/${process.env.INFURA_PROJECT_ID}`,
        accounts: [sepoliaPrivateKey],
        },
    },
};

Now, when you run Hardhat commands, it will prompt you for your passphrase to decrypt the private key. Sure this will be annoying, infuriating even during tests. You can probably add some checks to only prompt if it’s a certain chain id which might make it more bearable. Ultimately when dealing with critical wallet credentials it might save some funds going missing.

Encryption < Hardware Wallets & Multisigs

By encrypting our private keys, we’ve significantly increased the opsec of our development process. Even if our key credentials are compromised, our funds remain safe behind an additional layer of encryption.

Remember, this method is great for development and testing, but for production environments with significant funds, if possible, consider using hardware wallets. These physical devices, when combined with multisig wallets offer the best in class security.

Stay safe out there, and happy building!

Full code at: https://github.com/jamesbachini/DotEnv-Encrypted-Private-Keys


Get The Blockchain Sector Newsletter, binge the YouTube channel and connect with me on Twitter

The Blockchain Sector newsletter goes out a few times a month when there is breaking news or interesting developments to discuss. All the content I produce is free, if you’d like to help please share this content on social media.

Thank you.

James Bachini

Disclaimer: Not a financial advisor, not financial advice. The content I create is to document my journey and for educational and entertainment purposes only. It is not under any circumstances investment advice. I am not an investment or trading professional and am learning myself while still making plenty of mistakes along the way. Any code published is experimental and not production ready to be used for financial transactions. Do your own research and do not play with funds you do not want to lose.