:: Re: [Libbitcoin] Encrypting a walle…
Top Page
Delete this message
Reply to this message
Author: Police Terror
Date:  
To: libbitcoin
Subject: Re: [Libbitcoin] Encrypting a wallet with AES
So the ChaCha20-Poly1305 algorithm expects 32 bytes for the key, and the
crypto_pwhash_strbytes generates 128 bytes. Should I simply take the
first 32 bytes of that result for the ChaCha algorithm?

I'm guessing that for the nonce, I can use randombytes_buf() to generate
a random nonce every time I call encrypt(), and then store it cleartext
alongside the encrypted wallet data.

Would that be correct?

Here's what I have so far in Python:

https://github.com/RojavaCrypto/encdec-sodium/blob/master/test.py

Thanks.

William Swanson:
> For what you are trying to do, absolutely do *not* use raw AES. There
> are a thousand little things you need to get right, and messing any of
> them up will destroy the security of the whole system. Instead, you
> want to use something like libsodium, which provides high-level
> wrappers for all the things you need to do. Libsodium is already a
> libbitcoin dependency via ZeroMQ, so it shouldn't expand your code
> footprint either.
>
> For turning your password into a private key, libsodium provides two
> options, scrypt and argon2. The argon2 algorithm is the current
> state-of-the-art in terms of password hashing, but some people prefer
> older, more battle-tested algorithms like scrypt.
>
> Once you have an encryption key, you can use either the AES256-GCM or
> the ChaCha20-Poly1305 algorithm to encrypt the data. These two
> algorithms are called AEAD's, which is short for Authenticated
> Encryption with Additional Data. Not only will they encrypt the data,
> but they will also append a cryptographic checksum to detect
> tampering. This is necessary to avoid padding-oracle attacks and other
> such things.
>
> Besides the key and the raw data, both AES256-GCM and
> ChaCha20-Poly1305 require a nonce, or a "number used once". If you
> *ever* re-use the same nonce with the same key but different data, you
> will disclose the secret key to the attacker. So, never do that! One
> approach is to hash the data before encrypting, then use the hash as
> the nonce. This is probably the safest option for data at rest. For
> data in motion, the general strategy is to negotiate a fresh key for
> each session, and then use a message counter as the nonce.
>
> This should get you on a firm cryptographic footing, at least for
> encrypting the wallet on-disk.
>
> Another option is to use the Airbitz SDK, which is an open-source
> commercial product for this exact job. It has backups, a read-write
> data store, PIN login, password recovery, 2-factor authentication, and
> a bunch of other stuff. It might be an alternative to building
> everything from scratch.
>
> -William
>
> On Fri, Oct 14, 2016 at 12:39 AM, Police Terror <PoliceTerror@???> wrote:
>> Maybe I wasn't clear enough but I want to use the AES functions to
>> encrypt a Bitcoin wallet. I assumed that was their purpose being there
>> (to encrypt the wallet stored on the disk).
>>
>> Forcing the user to use a mnemonic just isn't practical and a passphrase
>> is standard for Bitcoin wallets.
>>
>> Reading here though it says I need to use a "password-based key
>> derivation functions", and I noticed the pkcs5_pbkdf2_hmac_sha512()
>> function.
>>
>> https://stackoverflow.com/questions/19862691/using-sha-1-hash-as-aes-key
>>
>> I noticed from BIP39 that iterations is set by default to 2048, so I'll
>> use that as an iterations value.
>>
>> Have you thought about making that a default argument for that function?
>> Can we do that?
>>
>> Eric Voskuil:
>>> IANAC and this is definitely that requires a rigorous analysis which I personally cannot provide.
>>>
>>> Presumably your intent is to store the secret under a passphrase recovery scheme, using the secret to encrypt a block of private data. So the encrypted passphrase and the block cypher text are both presumed to be accessible to the attacker.
>>>
>>> Key recovery requires a secure environment, otherwise a resident attacker (e.g. key logger) can simply recover the passphrase, or a more sophisticated attacker can monitor process memory (assuming insufficient process-level isolation) to do the same. So I'll assume that your threat model excludes a compromised environment and is instead focused on securing the block plain text against theft of the static environment.
>>>
>>> In this case I would recommend you use the bip39 mechanism for generating the secret. In this case you need not store the encrypted secret, you simply derive it from the passphrase (mnemonic) at each use.
>>>
>>> This offers the substantial benefit of preventing the user from generating a weak passphrase. It does however rely on a trustworthy RNG (again, under the assumption of an uncompromised platform use of the platform RNG is probably fine).
>>>
>>> If on the other hand you must allow the user to select a passphrase (or you must use an existing 256 bit secret) then you would use bip38 key encryption. Key generation is of course subject to the same RNG caveats.
>>>
>>> You could use bip39 to generate both the wallet seed(s) and the AES encryption key, from the same mnemonic.
>>>
>>> To satisfy the threat scenario you also need to consider the possibility (likelihood) of insecure memory usage. The mnemonic, key, or the entire block of clear text may become cached on disk (for example) as a consequence of the platform's virtual memory implementation. This would be vulnerable to static analysis. Use of secure memory primitives for anything that touches a secret is therefore a must.
>>>
>>> e
>>>
>>>> On Oct 13, 2016, at 10:31 AM, Police Terror <PoliceTerror@???> wrote:
>>>>
>>>> So libbitcoin defines the 2 functions aes256_encrypt() and aes256_decrypt().
>>>>
>>>> It uses a 32 byte secret and 16 byte block size.
>>>>
>>>> If I want to encrypt 5000 bytes, then I have encrypt it as 313 blocks
>>>> which is 5008 bytes right?
>>>>
>>>> How can I add a password to this? Can I simply do this?
>>>>
>>>> secret = bitcoin_hash("mypassphrase123")
>>>>
>>>> Or should I use the scrypt function instead? How can I use that?
>>>> _______________________________________________
>>>> Libbitcoin mailing list
>>>> Libbitcoin@???
>>>> https://mailinglists.dyne.org/cgi-bin/mailman/listinfo/libbitcoin
>> _______________________________________________
>> Libbitcoin mailing list
>> Libbitcoin@???
>> https://mailinglists.dyne.org/cgi-bin/mailman/listinfo/libbitcoin