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