Keystore¶
Note
If you or your users are storing significant amounts of values in an Aergo account, be advised that the only really secure way of storing private keys is using dedicated, offline hardware like a hardware wallet. This article is not a operations security guide. Please do your own research about private key security.
Securing private keys is the responsibility of client software, but Aergo has a recommended storage format for increased portability. This storage format is also used internally when storing accounts in aergocli or aergosvr.
This so-called Keystore format defines a file format (json) and encryption scheme.
File format¶
Filename: {address}__keystore.txt
{
"aergo_address": "Amdxxxx",
"ks_version": "1",
"kdf": {
"algorithm": "algorithm_name",
"params": {
"some_param": "some_value"
},
"mac": "mesasge_authentication_code"
},
"cipher": {
"algorithm": "algorithm_name",
"params": {
"some_param": "some_value"
},
"ciphertext": "dxxxx",
}
}
Rules
- Version field is for choosing cipher algorithm. If version updates, cipher algorithm would be updated (also format can change).
- Every file has its own algorithm and parameters per version. If any of the parameters break, an error should be thrown.
- File name is ‘{address}__keystore.txt’ or ‘{alias}__keystore.txt’
- File name is used to identify keystore file. Duplicates are not allowed.
- For the alias file, you can have same keystore file representing same account using different alias. That’s fine.
- Address must be a valid base58-check encoded address. Alias must be form of
[a-zA-Z0-9]+
Version 1 encryption scheme¶
Example implementations: Javascript
Encrypt
encryptionKey = Scrypt(rawPassword, scryptParams)
cipherText = AES_CTR.encrypt(rawPrivateKey, encryptionKey[0:16], nonce)
mac = Sha256(encryptionKey[16:32] + cipherText)
keystore = {
"aergo_address": "Amdxxxx",
"ks_version": "1",
"kdf": {
"algorithm": "scrypt",
"params": scryptParams,
"mac": mac
},
"cipher": {
"algorithm": "aes-128-ctr",
"params": {
"iv": nonce
},
"ciphertext": cipherText
}
}
Decrypt
encryptionKey = Scrypt(rawPassword, keystore.kdf.params)
mac = Sha256(encryptionKey[16:32] + json.cipher.ciphertext)
if keystore.kdf.mac != mac {
throw "invalid mac"
}
rawPrivateKey = AES_CTR.decrypt(json.cipher.ciphertext, encryptionKey[0:16], json.cipher.params.iv)
Recommended parameters
{
kdfAlgorithm: 'scrypt',
cipherAlgorithm: 'aes-128-ctr',
kdfParams: {
dklen: 32,
n: 1 << 18,
p: 1,
r: 8,
},
}