Crypto Project Data Encryption Setup
Most Web3 projects think well about smart contract security and poorly about off-chain infrastructure security. Private keys, API secrets, user data, seed phrases, backup encryption keys — all create attack surface that needs systematic coverage, not "maybe we won't be hacked".
Secret management
No secrets in code
Basic rule violated surprisingly often. Private key, RPC endpoint with API key, Telegram bot token in .env file, hardcoded in repository — this is data leak. GitHub scanning (official, Gitleaks, Trufflehog) regularly finds such cases in public repositories.
# Gitleaks: check repository for secret leaks
gitleaks detect --source . --verbose
# Or as pre-commit hook
gitleaks protect --staged
HashiCorp Vault
For production-level secret management — HashiCorp Vault. Secrets stored encrypted, access via dynamic secrets with TTL, audit log for each access.
# Get secret via Vault CLI
vault kv get -field=private_key secret/blockchain/signer
# In application: dynamic token with short TTL
vault token create -policy="blockchain-signer" -ttl=1h
For Kubernetes applications — Vault Agent Injector or External Secrets Operator. Secret mounted as file in pod, doesn't enter environment variables (which are logged).
AWS Secrets Manager / GCP Secret Manager
For cloud-native infrastructure — cloud-native secret managers. Automatic rotation, IAM integration, encryption via KMS.
import boto3
def get_private_key():
client = boto3.client('secretsmanager', region_name='us-east-1')
response = client.get_secret_value(SecretId='blockchain/signer-key')
return response['SecretString']
Key rotation: for signing keys — rotation via address change in contract (multisig or governance). For API keys — automatic via Secrets Manager rotation lambda.
Encrypting private keys
Hardware Security Modules (HSM)
For production signing keys (multisig participants, oracle operators, bridge operators) — HSM. Key never leaves HSM in plain form, signing performed inside device.
AWS CloudHSM / Google Cloud HSM: cloud HSM with secp256k1 support (not always native — need verification). Hashicorp Vault can also use HSM as backend.
Nitro Enclaves (AWS): virtual isolation for sensitive operations. Enclave has no permanent storage, no network access except special channel. Even root on host machine can't access enclave data.
Keystore encryption
For less critical keys (hot wallets with limits) — EIP-55 keystore format:
// ethers.js: creating encrypted keystore
const wallet = ethers.Wallet.createRandom();
const encrypted = await wallet.encrypt(
process.env.KEYSTORE_PASSWORD!,
{
scrypt: { N: 131072, r: 8, p: 1 } // high cost factor for production
}
);
// Save encrypted JSON, NOT private key
// Decryption on application start
const wallet = await ethers.Wallet.fromEncryptedJson(
keystoreJson,
process.env.KEYSTORE_PASSWORD!
);
Keystore password — also secret. Store in Vault or Secrets Manager, not env file.
User data encryption
KYC and PII data
If project stores KYC data (passports, addresses) — falls under GDPR and analogs. Minimum requirements:
Encryption at rest: AES-256-GCM for database data. In PostgreSQL — pgcrypto or column-level encryption via application. KMS for managing encryption keys.
Encryption in transit: TLS 1.3 everywhere. Cert pinning for mobile apps. HSTS for web.
Data minimization: store only necessary. If KYC verified — store only document hash and status, not document itself.
-- PostgreSQL field encryption via pgcrypto
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- Insert encrypted data
INSERT INTO kyc_data (user_id, encrypted_document_hash, verified_at)
VALUES (
$1,
pgp_sym_encrypt($2, current_setting('app.encryption_key')),
NOW()
);
-- Read
SELECT pgp_sym_decrypt(encrypted_document_hash, current_setting('app.encryption_key'))
FROM kyc_data WHERE user_id = $1;
End-to-end encryption for messaging
If protocol includes messaging (P2P communications, DAO discussions) — E2EE via libsodium or ECIES (Elliptic Curve Integrated Encryption Scheme) with keys derived from Ethereum private keys.
XMTP protocol does exactly this — E2EE messaging between Ethereum addresses. Integration via @xmtp/xmtp-js SDK.
Encrypting IPFS data
IPFS is public network. Everything uploaded accessible to everyone. For private data with IPFS storage — encrypt before upload:
import { create } from 'ipfs-http-client';
import { box, randomBytes } from 'tweetnacl';
import { encodeBase64 } from 'tweetnacl-util';
async function uploadEncrypted(data: Uint8Array, recipientPublicKey: Uint8Array) {
const nonce = randomBytes(box.nonceLength);
const { publicKey, secretKey } = box.keyPair();
// Encrypt for recipient
const encrypted = box(data, nonce, recipientPublicKey, secretKey);
const payload = {
nonce: encodeBase64(nonce),
ephemeralPublicKey: encodeBase64(publicKey),
ciphertext: encodeBase64(encrypted)
};
const ipfs = create({ url: 'https://ipfs.infura.io:5001' });
const result = await ipfs.add(JSON.stringify(payload));
return result.cid.toString();
}
Infrastructure Security
Network isolation
Signing nodes, bridge operators, oracle nodes — shouldn't be publicly accessible. VPC with private subnets, security groups with minimal permissions.
Public subnet: Load Balancer, API gateway
Private subnet: Application servers, RPC nodes
Isolated subnet: Signing services, key management
RPC endpoint security
Public RPC is attack vector. Alchemy/Infura keys need rotation, use allowlists by origin, monitor anomalous requests.
Own RPC node (geth/erigon) in private subnet — better for production. Access only via internal services.
Monitoring and alerting
OpenZeppelin Defender Sentinel: monitor on-chain events, alert on anomalous transactions from privileged addresses.
Forta: decentralized monitoring, community detection agents for known attacks.
Setup takes 1-2 weeks, but provides critical visibility for incident response.
Full encryption setup for production crypto project — 3-6 weeks depending on infrastructure volume and compliance requirements.







