This is a version of #5949 with a constant-time, slow and simple AES implementation.
Performance on modern systems should be around 2-10 Mbyte/s (for short to larger messages), which is plenty for the needs of our wallet.
28@@ -29,13 +29,12 @@ $(LIBLEVELDB) $(LIBMEMENV):
29 endif
30
31 BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config
32-BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
33+BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
--disable-wallet
non BDB compile option? Its probably empty if BDB was not found.
421+ int round = 0;
422+ /* The number of the word being generated, modulo nkeywords */
423+ int pos = 0;
424+
425+ /* The first nkeywords round key words are just taken from the key directly */
426+ for (int i = 0; i < nkeywords; i++) {
Tested ACK (52e05be371551a4529ec9248afebcca67fae6181).
Verified test vectors, run tests on different platforms and setups.
Tested this PR with encrypted wallet.dat
from master (and vice versa).
NOT tested/verified constant time behavior.
Concept NACK
I don’t think we should be using low-level crypto primitives code developed by us that has ~zero chance of being reviewed or used by anyone other than us. I don’t care how good we think we are, thats just not a good practice.
Maybe stick this in libsecp256k1 instead?
I agree with @petertodd that ideally the code should be published separately from bitcoin as well.
This doesn’t need to be a generic library. We’d like this code to be self-contained (and have a special requirement here) so using OpenSSL et al is not an option, and maintaining a new generic library is a lot of work and responsibility too.
But I can understand that some people would find a specific implementation of AES just for bitcoin core as risky. (And even though it’s not used in consensus, nor anything network-facing, a bug in the wallet encryption would be a big deal.)
Did anyone check by comparing their code line by line with an alternate implementation?
Yes, people have done so.
Maybe stick this in libsecp256k1 instead?
Please no, that’s scope creep for libsecp256k1. You’re not trying to turn secp256k1 into a generic crypto library are you?
I think we should ask the question separately from where the code is, though:
Can we get any (independent, skilled) cryptographers to review this code? At least reviewing crypto code is a mostly one-time deal, after which it will (hardly) ever change.
I have had this code running on 104 cores for several days, running a test that feeds random input through encode and decode with random keys and compares it to AES-NI.
The current maximum long term rate for the wallet application of this code in the current network is roughly 7 decrypts per second of roughly 48 bytes. At the current speed of my test harness it means that I have tested the equivalent of the network’s maximum rate for thirty one thousand years without finding a fault.
Mutation testing showed very very high error correlation, meaning that any error manually introduced in the software made every execution (or nearly every execution) wrong. (So far I have not found any candidate error that didn’t have this effect though automated searching, though I wouldn’t be totally shocked if there were one– it’s still the case that this codebase has very high error correlation).
Pieter has a new version which is a straightforward port to plain C89 with some minor cleanup and some size reductions I contributed (the code size is still larger than the smallest AES implementations I can find (which aren’t constant time), but not enormously so). I’ll soon update my testing harness to that code and continue. I’ve also now reviewed the C89 version pretty extensively.
The constant time AES core code is now factored out to a new repository; for now, it’s available at http://github.com/sipa/ctaes/
The pull request here has been updated to use a subtree of that project, with C++ wrappers around it.
The build code is very simple: ctaes does not have any configuration or own build system, so Bitcoin Core just builds it as part of its own process. I have not included ctaes’s tests here for simplicity; the relevant AES C++ wrapper code does have its own tests though.
git-subtree-dir: src/crypto/ctaes
git-subtree-split: cd3c3ac31fac41cc253bf5780b55ecd8d7368545
Updated to latest ctaes (which includes a link to the review work by Ayo Akinyele), and rebased.
I now get this error:
0/usr/bin/ld: crypto/libbitcoin_crypto.a(crypto_libbitcoin_crypto_a-ctaes.o): relocation R_X86_64_PC32 against undefined symbol `__stack_chk_fail@@GLIBC_2.4' can not be used when making a shared object; recompile with -fPIC
@theuni Did I screw up the rebase?
@sipa: ctaes.c doesn’t get cxxflags (it gets cflags since it builds with gcc). Introducing a c source throws a wrench in our assumptions that we’re building c++(11) sources. We could come up with a common set of flags shared between them, but by far the easiest fix here is just to ctaes.c –> ctaes.cpp.
If that drives you crazy, I can work on it.
The output should always match openssl's, even for failed operations. Even for
a decrypt with broken padding, the output is always deterministic (and attemtps
to be constant-time).
AES IV's are 16bytes, not 32. This was harmless but confusing.
Add WALLET_CRYPTO_IV_SIZE to make its usage explicit.
This makes CCrypter easier to pass aroundf for tests
BytesToKeySHA512AES should be functionally identical to EVP_BytesToKey, but
drops the dependency on openssl.
Wallet must come before crypto, otherwise linking fails on some platforms.
Includes a tangentially-related general cleanup rather than making the Makefile
sloppier.
Verify that results correct (match known values), consistent (encrypt->decrypt
matches the original), and compatible with the previous openssl implementation.
Also check that failed encrypts/decrypts fail the exact same way as openssl.
I didn’t see any tests that explicit test for failure with invalid padding, except perhaps in the test that makes sure it behaves the same as OpenSSL. Perhaps if the CBC mode is ported to C in a later PR that could be addressed.
utACK. Good work sipa and cfields.
62+ AES256_init(&ctx, key);
63+}
64+
65+AES256Decrypt::~AES256Decrypt()
66+{
67+ memset(&ctx, 0, sizeof(ctx));
@sipa Please grab a quick build change: https://github.com/theuni/bitcoin/commit/723779c6504453cfb5ccdacf864e7e2f09bb6c32
After that: ACK