Keystore generation, encryption and decryption for Ethereum key files using the Web3 Secret Storage definition, https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition
$ dotnet add package Nethereum.KeyStorePassword-encrypted private key storage using the Web3 Secret Storage Definition standard.
Nethereum.KeyStore implements the Web3 Secret Storage Definition for encrypting and storing Ethereum private keys. This is a standard format for encrypted key storage used across the Ethereum ecosystem.
Key Features:
Use Cases:
dotnet add package Nethereum.KeyStore
Nethereum:
External:
using Nethereum.KeyStore;
using Nethereum.Signer;
using Nethereum.Hex.HexConvertors.Extensions;
// Generate a new key
var ecKey = EthECKey.GenerateKey();
// Encrypt and generate keystore JSON
var service = new KeyStoreScryptService();
string password = "testPassword";
string json = service.EncryptAndGenerateKeyStoreAsJson(
password,
ecKey.GetPrivateKeyAsBytes(),
ecKey.GetPublicAddress()
);
// Decrypt later
byte[] privateKey = service.DecryptKeyStoreFromJson(password, json);
using Nethereum.KeyStore;
using Nethereum.Signer;
using Nethereum.Hex.HexConvertors.Extensions;
var ecKey = EthECKey.GenerateKey();
var keyStoreScryptService = new KeyStoreScryptService();
string password = "testPassword";
// Encrypt and serialize to JSON
string json = keyStoreScryptService.EncryptAndGenerateKeyStoreAsJson(
password,
ecKey.GetPrivateKeyAsBytes(),
ecKey.GetPublicAddress()
);
// Save to file
File.WriteAllText($"keystore-{ecKey.GetPublicAddress()}.json", json);
// Decrypt to verify
byte[] key = keyStoreScryptService.DecryptKeyStoreFromJson(password, json);
Assert.Equal(ecKey.GetPrivateKey(), key.ToHex(true));
using Nethereum.KeyStore;
using Nethereum.KeyStore.Model;
using Nethereum.Signer;
using Nethereum.Hex.HexConvertors.Extensions;
var keyStoreService = new KeyStoreScryptService();
// Lower N for faster encryption (WASM, mobile, testing)
// Default: N=262144, R=1, P=8, Dklen=32
var scryptParams = new ScryptParams { Dklen = 32, N = 32, R = 1, P = 8 };
var ecKey = EthECKey.GenerateKey();
string password = "testPassword";
// Encrypt with custom parameters
var keyStore = keyStoreService.EncryptAndGenerateKeyStore(
password,
ecKey.GetPrivateKeyAsBytes(),
scryptParams.N,
scryptParams.R,
scryptParams.P,
null // salt (null = auto-generate)
);
// Serialize to JSON
string json = keyStoreService.SerializeKeyStoreToJson(keyStore);
// Decrypt
byte[] decryptedKey = keyStoreService.DecryptKeyStoreFromJson(password, json);using Nethereum.KeyStore;
using Nethereum.Hex.HexConvertors.Extensions;
var scryptKeyStoreJson = @"{
""crypto"" : {
""cipher"" : ""aes-128-ctr"",
""cipherparams"" : {
""iv"" : ""83dbcc02d8ccb40e466191a123791e0e""
},
""ciphertext"" : ""d172bf743a674da9cdad04534d56926ef8358534d458fffccd4e6ad2fbde479c"",
""kdf"" : ""scrypt"",
""kdfparams"" : {
""dklen"" : 32,
""n"" : 262144,
""r"" : 1,
""p"" : 8,
""salt"" : ""ab0c7876052600dd703518d6fc3fe8984592145b591fc8fb5c6d43190334ba19""
},
""mac"" : ""2103ac29920d71da29f15d75b4a16dbe95cfd7ff8faea1056c33131d846e3097""
},
""id"" : ""3198bc9c-6672-5ab3-d995-4942343ae5b6"",
""version"" : 3
}";
string password = "testpassword";
var keyStoreScryptService = new KeyStoreScryptService();
// Deserialize and decrypt
var keyStore = keyStoreScryptService.DeserializeKeyStoreFromJson(scryptKeyStoreJson);
byte[] privateKey = keyStoreScryptService.DecryptKeyStore(password, keyStore);
Console.WriteLine($"Private Key: {privateKey.ToHex()}");
// Output: 7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9dusing Nethereum.KeyStore;
using Nethereum.Signer;
using Nethereum.Hex.HexConvertors.Extensions;
var ecKey = EthECKey.GenerateKey();
var keyStorePbkdf2Service = new KeyStorePbkdf2Service();
string password = "testPassword";
// Encrypt with PBKDF2 (faster but less secure than Scrypt)
string json = keyStorePbkdf2Service.EncryptAndGenerateKeyStoreAsJson(
password,
ecKey.GetPrivateKeyAsBytes(),
ecKey.GetPublicAddress()
);
// Decrypt
byte[] key = keyStorePbkdf2Service.DecryptKeyStoreFromJson(password, json);
Assert.Equal(ecKey.GetPrivateKey(), key.ToHex(true));using Nethereum.KeyStore;
string keystoreJson = File.ReadAllText("wallet.json");
var keyStoreKdfChecker = new KeyStoreKdfChecker();
var kdfType = keyStoreKdfChecker.GetKeyStoreKdfType(keystoreJson);
if (kdfType == KeyStoreKdfChecker.KdfType.scrypt)
{
var service = new KeyStoreScryptService();
byte[] privateKey = service.DecryptKeyStoreFromJson(password, keystoreJson);
}
else if (kdfType == KeyStoreKdfChecker.KdfType.pbkdf2)
{
var service = new KeyStorePbkdf2Service();
byte[] privateKey = service.DecryptKeyStoreFromJson(password, keystoreJson);
}using Nethereum.KeyStore;
using Nethereum.Signer;
using Nethereum.Hex.HexConvertors.Extensions;
var ecKey = EthECKey.GenerateKey();
var keyStoreService = new KeyStoreService();
string password = "testPassword";
// Uses default Scrypt parameters
string json = keyStoreService.EncryptAndGenerateDefaultKeyStoreAsJson(
password,
ecKey.GetPrivateKeyAsBytes(),
ecKey.GetPublicAddress()
);
byte[] key = keyStoreService.DecryptKeyStoreFromJson(password, json);
Assert.Equal(ecKey.GetPrivateKey(), key.ToHex(true));Scrypt-based keystore encryption (recommended).
public class KeyStoreScryptService
{
// Encrypt and generate JSON (default parameters)
public string EncryptAndGenerateKeyStoreAsJson(string password, byte[] privateKey, string address);
// Encrypt with custom Scrypt parameters
public KeyStore<ScryptParams> EncryptAndGenerateKeyStore(
string password,
byte[] privateKey,
int n, int r, int p,
byte[] salt = null
);
// Serialize keystore to JSON
public string SerializeKeyStoreToJson(KeyStore<ScryptParams> keyStore);
// Deserialize JSON to keystore
public KeyStore<ScryptParams> DeserializeKeyStoreFromJson(string json);
// Decrypt from JSON
public byte[] DecryptKeyStoreFromJson(string password, string json);
// Decrypt from keystore object
public byte[] DecryptKeyStore(string password, KeyStore<ScryptParams> keyStore);
}Default Scrypt Parameters:
N = 262144 // CPU/memory cost (2^18)
R = 1 // Block size
P = 8 // Parallelization
Dklen = 32 // Derived key lengthPBKDF2-based keystore encryption (legacy).
public class KeyStorePbkdf2Service
{
// Same methods as KeyStoreScryptService but using PBKDF2
public string EncryptAndGenerateKeyStoreAsJson(string password, byte[] privateKey, string address);
public KeyStore<Pbkdf2Params> DeserializeKeyStoreFromJson(string json);
public byte[] DecryptKeyStoreFromJson(string password, string json);
public byte[] DecryptKeyStore(string password, KeyStore<Pbkdf2Params> keyStore);
}Unified service with default encryption.
public class KeyStoreService
{
// Encrypt with default Scrypt parameters
public string EncryptAndGenerateDefaultKeyStoreAsJson(string password, byte[] privateKey, string address);
// Decrypt (auto-detects KDF type)
public byte[] DecryptKeyStoreFromJson(string password, string json);
}Detect KDF type from JSON.
public class KeyStoreKdfChecker
{
public enum KdfType { scrypt, pbkdf2 }
public KdfType GetKeyStoreKdfType(string json);
public bool IsScryptKdf(string json);
public bool IsPbkdf2Kdf(string json);
}public class ScryptParams
{
public int Dklen { get; set; } // Derived key length (32)
public int N { get; set; } // CPU/memory cost (262144)
public int R { get; set; } // Block size (1)
public int P { get; set; } // Parallelization (8)
public string Salt { get; set; } // Random salt (hex)
}
public class Pbkdf2Params
{
public int Dklen { get; set; } // Derived key length (32)
public int C { get; set; } // Iteration count (262144)
public string Prf { get; set; } // PRF algorithm (hmac-sha256)
public string Salt { get; set; } // Random salt (hex)
}
public class KeyStore<TKdfParams>
{
public CryptoInfo<TKdfParams> Crypto { get; set; }
public string Id { get; set; } // UUID
public int Version { get; set; } // Always 3
public string Address { get; set; } // Ethereum address (optional)
}N = 262144 // 2^18 - Strong security, ~100ms encryption
R = 1
P = 8Use for: Desktop applications, servers, production wallets
N = 32 // 2^5 - Fast encryption, weaker security
R = 1
P = 8Use for: Browser WASM, mobile apps, development/testing
N = 1048576 // 2^20 - Very strong security, ~3s encryption
R = 8
P = 1Use for: Cold storage, high-value accounts, paranoid security
| Parameter | Effect | Security Impact | Performance Impact |
|---|---|---|---|
| N | CPU/memory cost | Exponential | Exponential |
| R | Block size | Linear | Linear |
| P | Parallelization | Linear | Linear (if parallel) |
N dominates: Doubling N doubles time and memory. N=262144 uses ~256MB RAM.
Keystore JSON structure:
{
"crypto": {
"cipher": "aes-128-ctr",
"cipherparams": { "iv": "..." },
"ciphertext": "...",
"kdf": "scrypt",
"kdfparams": {
"dklen": 32,
"n": 262144,
"r": 1,
"p": 8,
"salt": "..."
},
"mac": "..."
},
"id": "3198bc9c-6672-5ab3-d995-4942343ae5b6",
"version": 3
}Fields:
aes-128-ctrscrypt or pbkdf23| Feature | Scrypt | PBKDF2 |
|---|---|---|
| Security | Memory-hard, ASIC-resistant | CPU-only, ASIC-vulnerable |
| Speed | Slower (~100ms default) | Faster (~50ms) |
| Recommendation | Use this | Legacy only |
Use Scrypt unless you need compatibility with very old systems.
Standard naming convention used across Ethereum tools:
UTC--<created_at UTC ISO8601>--<address hex>
Example:
UTC--2024-01-15T10-30-45.123Z--0x12890d2cce102216644c59dae5baed380d84830c