New Beta V2.1 Release!
Check out the latest version of the app. If you still want to use the legacy version, log in at app.chaingateway.io. Read more in our latest blog post.
Blog Post
Read our latest blog posts and stay updated with the latest trends and insights in the blockchain industry.
Explore a wide range of topics and discover valuable information that can help you enhance your knowledge and skills.
By Chaingateway
Oct 18, 2024
Ethereum, Binance Smart Chain (BSC), and other EVM-compatible networks use keystore files to protect users’ private keys. A keystore file is a JSON file that contains an encrypted private key, secured with a password. For security reasons, applications often store only the keystore file, not the plain private key.
In this blog post, we’ll demonstrate how you can recover the private key from a keystore file using PHP. This is particularly useful when you need to export or recover your private key for use in another application.
Handling private keys directly can be risky if not done securely. Always ensure that your environment is secure and avoid exposing your private key unnecessarily.
A typical keystore file is a JSON object that contains encrypted information about the private key. Here’s an overview of the key sections in the file:
crypto
: Contains encryption-related information. ciphertext
: The encrypted private key.cipher
: The cipher algorithm used for encryption.cipherparams
: Contains the initialization vector (iv
) used in the encryption process.kdf
: Key Derivation Function (KDF), either pbkdf2
or scrypt
, used to derive the encryption key from your password.kdfparams
: Parameters for the KDF, such as salt, iterations (c
), and key length (dklen
).mac
: Message Authentication Code, used to verify that the key derivation was successful.To extract a private key from a keystore file, you’ll need the following PHP extensions:
scrypt
KDF. Read more about it here Install these extensions using:
sudo apt-get install php-json php-openssl
sudo pecl install scrypt
You’ll also need:
Start by loading the keystore file’s content into a PHP array and defining the password that will be used to decrypt the private key:
// Load keystore JSON file
$keystore = file_get_contents('/path/to/keystore-file.json');
$keystore_json = json_decode($keystore, true);
// Define the password
$password = "YOUR_PASSWORD";
The encryption data is stored under the crypto
section of the keystore JSON. You will need to extract the relevant fields to use them in the decryption process.
$crypto = $keystore_json['crypto'];
$ciphertext = $crypto['ciphertext'];
$iv = $crypto['cipherparams']['iv'];
$salt = $crypto['kdfparams']['salt'];
$kdf = $crypto['kdf'];
$kdfparams = $crypto['kdfparams'];
$mac = $crypto['mac'];
Next, derive the key from the password using the specified KDF (pbkdf2
or scrypt
). Ethereum keystores commonly use either of these two KDFs.
if ($kdf === 'pbkdf2') {
$derivedKey = hash_pbkdf2(
'sha256',
$password,
hex2bin($salt),
$kdfparams['c'], // iterations
$kdfparams['dklen'] * 2,
false
);
}
If the keystore uses the scrypt
KDF, you’ll need to have the libsodium PHP extension installed:
if ($kdf === 'scrypt') {
$N = $kdfparams['n'];
$r = $kdfparams['r'];
$p = $kdfparams['p'];
$dklen = $kdfparams['dklen'];
// Derive the key using sodium
$derivedKey = sodium_crypto_pwhash(
$dklen,
$password,
hex2bin($salt),
$N,
$r * 128, // CPU/memory cost factor
$p,
SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13 // Modern alternative to scrypt
);
}
Before decrypting the private key, verify that the MAC (Message Authentication Code) matches. This ensures that the key derivation was successful.
$derivedKeyPart = substr($derivedKey, 0, 32);
$calculatedMac = hash('sha3-256', hex2bin(substr($derivedKey, 32)) . hex2bin($ciphertext));
if ($calculatedMac !== $mac) {
die('MAC verification failed. The password may be incorrect or the keystore may be corrupted.');
}
If the MAC matches, you can decrypt the private key using the derived key. The private key is encrypted with the AES-128-CTR cipher in Ethereum keystores.
$privateKey = openssl_decrypt(
hex2bin($ciphertext),
'aes-128-ctr',
hex2bin($derivedKeyPart),
OPENSSL_RAW_DATA,
hex2bin($iv)
);
if (!$privateKey) {
die('Failed to decrypt the private key.');
}
echo 'Private key: ' . bin2hex($privateKey);
At this point, you should have successfully decrypted and printed the private key.
We’ve walked through the steps to extract a private key from a keystore file using PHP. By loading the keystore, deriving the encryption key, verifying the MAC, and decrypting the private key, we can recover the private key in a secure manner. Below is the full code example summarizing the entire process.
<?php
// Step 1: Load keystore JSON file
$keystore = file_get_contents('/path/to/keystore-file.json');
$keystore_json = json_decode($keystore, true);
// Step 2: Define the password
$password = "YOUR_PASSWORD";
// Step 3: Extract relevant data from the keystore
$crypto = $keystore_json['crypto'];
$ciphertext = $crypto['ciphertext'];
$iv = $crypto['cipherparams']['iv'];
$salt = $crypto['kdfparams']['salt'];
$kdf = $crypto['kdf'];
$kdfparams = $crypto['kdfparams'];
$mac = $crypto['mac'];
// Step 4: Derive the key based on the KDF used (pbkdf2 or scrypt)
if ($kdf === 'pbkdf2') {
// PBKDF2 key derivation
$derivedKey = hash_pbkdf2(
'sha256',
$password,
hex2bin($salt),
$kdfparams['c'], // iterations
$kdfparams['dklen'] * 2,
false
);
} elseif ($kdf === 'scrypt') {
// Scrypt key derivation (requires libsodium)
$N = $kdfparams['n'];
$r = $kdfparams['r'];
$p = $kdfparams['p'];
$dklen = $kdfparams['dklen'];
$derivedKey = sodium_crypto_pwhash(
$dklen,
$password,
hex2bin($salt),
$N,
$r * 128,
$p,
SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13 // Modern alternative to scrypt
);
} else {
die('Unsupported KDF method.');
}
// Step 5: Verify the MAC
$derivedKeyPart = substr($derivedKey, 0, 32);
$calculatedMac = hash('sha3-256', hex2bin(substr($derivedKey, 32)) . hex2bin($ciphertext));
if ($calculatedMac !== $mac) {
die('MAC verification failed. Wrong password or corrupted keystore.');
}
// Step 6: Decrypt the private key
$privateKey = openssl_decrypt(
hex2bin($ciphertext),
'aes-128-ctr',
hex2bin($derivedKeyPart),
OPENSSL_RAW_DATA,
hex2bin($iv)
);
if (!$privateKey) {
die('Failed to decrypt the private key.');
}
// Output the private key in hexadecimal format
echo 'Private key: ' . bin2hex($privateKey);
If you’re looking for an easy and fully offline way to decrypt keystore files, check out our free tool available at our Keystore Decryptor Tool.
This tool works completely offline, giving you the confidence to handle your sensitive private key data without any connection to the internet. To ensure absolute security, you can disconnect your computer from the internet while using the tool, guaranteeing that no sensitive information is exposed.
You can also download it on our Github Repository
Enter your email to receive our latest newsletter.
Don't worry, we don't spam
chaingateway
chaingateway
Calculate Tron fees easily with our free TRX Calculator. Optimize costs for transactions and smart contracts, and save up to 60% with our Tron Paymaster API.
Learn how to set up an Ethereum node to validate transactions. Follow our guide to configure your node and access Ethereum RPC endpoints effectively.
Learn how to set up a Binance Smart Chain node for transaction authentication. Follow our guide to configure your BSC node and access BSC RPC endpoints.
We use cookies to enhance your experience. By continuing to visit this site, you agree to our use of cookies.