I am using the Ethereum keystore file format to encrypt any other data such a plain text or JSON.

Here is an example of pseudocode of the implementation:

MY_PASSWORD = "VeryDifficultPasword432131!@!#%"
MY_TEXT = "This is my secret text"

iv = randomBytes(16)
kdfparams = {
    dklen: 32,
    n: 262144,
    r: 1,
    p: 8,
    salt: randomBytes(32)
key = scrypt(MY_PASSWORD, kdfparams)
ciphertext = encryptCipheriv("aes-128-ctr", MY_TEXT, key, iv)
mac = sha3(key[16:32], ciphertext)

With this code I can generate the keystore file that looks like this:

    "crypto" : {
        "cipher" : "aes-128-ctr",
        "cipherparams" : {
            "iv" : "83dbcc02d8ccb40e466191a123791e0e"
        "ciphertext" : "d172bf743a674da9cdad04534d56926ef8358534d458fffccd4e6ad2fbde479c",
        "kdf" : "scrypt",
        "kdfparams" : {
            "dklen" : 32,
            "n" : 262144,
            "r" : 1,
            "p" : 8,
            "salt" : "ab0c7876052600dd703518d6fc3fe8984592145b591fc8fb5c6d43190334ba19"
        "mac": "102aedfe8c308c735a76295f9908d9b7de40fb1c07f2f71e05de7a0b2f323a12"

This is the standard file that store millions of dollars of people in Ethers.


  • Is this secure?
  • If not, why?
  • If yes, is also secure encrypting plain text or JSON (no hexadecimal format)?
  • Is secure to set a smaller kdfparams.n?

Edit: To clarify why I'm asking this is because another person said this:

This is not secure at all. This implementation contains many basic errors. One example is using an insecure random number generator, which utterly destroys the security of the encryption. Another is using AES-128-CTR without authentication.

  • $\begingroup$ First, define "secure". But by any reasonable definition of that, with a password in the same league as '1234', and plaintext that large and redundant, nothing usable is secure. $\endgroup$
    – fgrieu
    Jan 25, 2018 at 15:39
  • $\begingroup$ Secure in terms of very very difficult to break even if is a good cryptographer. Let me edit to clarify that would be a very strong password. $\endgroup$
    – Enzo
    Jan 25, 2018 at 15:45
  • 1
    $\begingroup$ Now, define "break". Is that finding the original password? Guessing the plaintext from one ciphertext? Guessing some of the plaintext from many ciphertext sharing that some? Guessing one plaintext from many ciphertext and all the other plaintext? Can we get help from an executable running on the same machine (and if yes, exactly what CPU with what microcode patch? is AES-NI used?). Can we use EMI as a side channel? A keylogger, hardware or sotfare? Indeed, what's the implementation of randomBytes, which has an influence? $\endgroup$
    – fgrieu
    Jan 25, 2018 at 16:13
  • 4
    $\begingroup$ You cannot answer this question by looking at psuedocode. The actual implementation can contain all sorts of vulnerabilities and side channels. Security is also not a binary, it's a matter of how far you're willing to go to protect against ever more exotic attacks. $\endgroup$
    – Ella Rose
    Jan 25, 2018 at 16:15
  • $\begingroup$ @ fgrieu sorry, the only question I can answer is: nodejs.org/api/… @EllaRose I assume that the libraries I am using do not have vulnerabilities. So my pseudocode above is just an implementation of those libraries functions, such a randomBytes. $\endgroup$
    – Enzo
    Jan 25, 2018 at 16:33

2 Answers 2


The worst purely cryptographic weakness is the password (1). The worst (and much worse) practical weaknesses are likely to be in the implementation (6) (7), and those (4) (5) that cryptographers dismiss as out of scope of encryption (the question's only stated objective).

Candidates for weaknesses, from cryptographic (but still to consider) to implementation:

  1. The password: it is hard to remember a password with over about 48 bits of entropy (that's about equivalent to a 16-digit number, like 3141592653589793 or 2718281828459045, and more than envisioned by the obligatory XKCD). Using N=262144=218, r=1, p=8=23, buys at the very least 18+3+1=22 bits (see this) compared to a straight SHA-256 hash followed by AES-128, I guess about 32 bits stronger, thus the key might be about 80-bit good, which is not entirely unbreakable by brute force but still quite secure.
  2. AES-128: this has a 128-bit key, no known purely cryptanalytic attack better than brute force, and is thus much better than the password.
  3. CTR mode: with AES's 128-bit block, the only way key-stream reuse could kick in would be a bad random number generator for the IV (see 6)
  4. The size of the plaintext can be effortlessly deduced from the size of the ciphertext. This is explicitly not a theoretical weakness of encryption, since length is excluded from what a cipher is supposed to hide about plaintext. However, that can be a practical weakness. Say analysis of ciphertext concludes that it is 17267095423 octets; and there exists, somewhere in the prosecution's exhibits a file with exactly that size, demonstrably predating search and seizure of the ciphertext, and which mere detention is illegal.
  5. Lack of detection of (intentional or accidental) ciphertext alterations, corresponding to predictable alteration in the plaintext: again this is explicitly not a theoretical weakness of encryption, but can allow some attacks if the adversary can alter the ciphertext (example: if the plaintext is an executable or PDF with a known fraction, that can allow changing what the executable does to about anything, or make the PDF display as about anything). Authenticated encryption (AES-GCM..) solves that.
  6. Random number generator: if this is bad, or worse gets more or less stuck (obligatory XKCD and Dilbert which turn to reality all too often), that would enable recovering plaintext in many scenarios, including repeatedly enciphering different English text or email addresses with the same password.
  7. A side channel, that is broadly speaking unforeseen or unmitigated leak of information in the implementation or usage context. There are so many:
    1. Password recovery from the password holder by exploiting a procedural goof (password on a postit note, master password list), rubber-hose cryptanalysis (obligatory XKCD), legal variants (involving use of expressions on the tune of contempt of court), bribery, chemical impregnation..
    2. Password recovery by shoulder surfing, key logger (software or hardware), camera, microphone (a good audio capture of the sound of keys when entering a password leaks a lot of info about the password, especially when correlated with known keyboard entry by same operator under same conditions)..
    3. Straight compromise of plaintext as shown on screen (with TEMPEST variants of that), printed, while transmitted to a printer or remotely accessed by a network, or just "temporarily" stored..
    4. Straight compromise of the OS of the machine doing encryption or decryption (getting temporary root access is enough, means in 7.7 are game to the attacker).
    5. Cryptanalytic side channel at a distance, including DPA and electromagnetic variant DEMA, and hypothetically timing if the machine doing the encryption/decryption is accessed by a network and does not use AES instructions.
    6. Cryptanalytic side channel from a process running on the same hardware (including another VM), including cache-based targeting for AES when not using AES instructions, or more general ones (Meltdown, Spectre) which are all the rage these days.
    7. Exploitation of various software bugs; that's huge.
  • $\begingroup$ It would be more useful if I hash the password before the encryption? Like using sha or md5? key = scrypt(sha(MY_PASSWORD), kdfparams) $\endgroup$
    – Enzo
    Jan 30, 2018 at 8:48
  • 1
    $\begingroup$ @EnZo: Hashing password before entry in scrypt does not change much the difficulty of attack of the password (point 1). To improve on that one needs a better password, a better parametrization fo scrypt, or a better password-based key derivation scheme (Argon? Balloon?) $\endgroup$
    – fgrieu
    Jan 30, 2018 at 10:42

The main security element that can be attacked in the above scheme is - of course - the pass phrase. Now the salt is important to avoid rainbow table attacks but otherwise it doesn't add that much security. If the salt and password are reasonably unique then the key is unique as well. In that case the IV is not that important.

So although using an insecure random number generator is bad it probably won't have all that much influence on the practical security. However, it does indicate that bad practices were indeed deployed. What if the passphrase was generated using that same insecure random generator? What if other implementation errors surface?

Using non-authenticated ciphertext is more of a problem, as it would allow the adversary to change the plaintext for each bit. The adversary can simply invert any ciphertext bit and the plaintext bit at the same position will also flip. This would mean that you would get an error or a problem when using the wallet. The confidentiality of the contents of the wallet is likely not lost but using authenticated encryption is certainly best practice.

  • $\begingroup$ Thank you! Could you explain barely how to achieve authenticated ciphertext with this mode? I am gonna edit the examples above because I think is related with the original mac property that I removed from the original keystore file. $\endgroup$
    – Enzo
    Jan 25, 2018 at 20:49
  • 1
    $\begingroup$ CTR mode is the underlying mode of CCM, GCM, EAX, SIV and a whole bunch of other authenticated ciphers. However, a combination of CTR mode with a (H)MAC can certainly also be secure. Both produce an authentication tag with roughly the same size/security. CCM and EAX are little more than specific combinations of CTR and a MAC where the same key can be used for the cipher and MAC. $\endgroup$
    – Maarten Bodewes
    Jan 25, 2018 at 20:54
  • 1
    $\begingroup$ Note that I've answered this question to the best of my ability, using generic knowledge of ciphers (not so much Ethereum). Ella Rose is correct that we cannot conclude the security of the system from the info given to us in the question. So I've focussed solely on the use of CTR. $\endgroup$
    – Maarten Bodewes
    Jan 25, 2018 at 20:58
  • 1
    $\begingroup$ Well, the random seems to rely - in the end - on the system random. Often system random sources are relatively secure and the term CSPRNG is indeed mentioned by the source. So the claim that it is not random is wrong, unless the system random is not well implemented or seeded. $\endgroup$
    – Maarten Bodewes
    Jan 25, 2018 at 21:17
  • 1
    $\begingroup$ Creating a MAC from SHA-3 directly is not recommended, KMAC should have been used instead (it probably simply wasn't specified yet at the time). But I cannot think of any situation where the use over the concatenation of the key and the ciphertext would ever pose a problem. $\endgroup$
    – Maarten Bodewes
    Jan 25, 2018 at 21:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.