Skip to content

Commit f4d1fc2

Browse files
committed
wallet: Get rid of LockObject and UnlockObject calls in key.h
Replace these with vectors allocated from the secure allocator. This avoids mlock syscall churn on stack pages, as well as makes it possible to get rid of these functions. Please review this commit and the previous one carefully that no `sizeof(vectortype)` remains in the memcpys and memcmps usage (ick!), and `.data()` or `&vec[x]` is used as appropriate instead of &vec.
1 parent 999e4c9 commit f4d1fc2

File tree

3 files changed

+23
-55
lines changed

3 files changed

+23
-55
lines changed

src/key.cpp

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ bool CKey::Check(const unsigned char *vch) {
125125

126126
void CKey::MakeNewKey(bool fCompressedIn) {
127127
do {
128-
GetStrongRandBytes(vch, sizeof(vch));
129-
} while (!Check(vch));
128+
GetStrongRandBytes(keydata.data(), keydata.size());
129+
} while (!Check(keydata.data()));
130130
fValid = true;
131131
fCompressed = fCompressedIn;
132132
}
@@ -224,20 +224,18 @@ bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) {
224224
bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const {
225225
assert(IsValid());
226226
assert(IsCompressed());
227-
unsigned char out[64];
228-
LockObject(out);
227+
std::vector<unsigned char, secure_allocator<unsigned char>> vout(64);
229228
if ((nChild >> 31) == 0) {
230229
CPubKey pubkey = GetPubKey();
231230
assert(pubkey.begin() + 33 == pubkey.end());
232-
BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin()+1, out);
231+
BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin()+1, vout.data());
233232
} else {
234233
assert(begin() + 32 == end());
235-
BIP32Hash(cc, nChild, 0, begin(), out);
234+
BIP32Hash(cc, nChild, 0, begin(), vout.data());
236235
}
237-
memcpy(ccChild.begin(), out+32, 32);
236+
memcpy(ccChild.begin(), vout.data()+32, 32);
238237
memcpy((unsigned char*)keyChild.begin(), begin(), 32);
239-
bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context_sign, (unsigned char*)keyChild.begin(), out);
240-
UnlockObject(out);
238+
bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context_sign, (unsigned char*)keyChild.begin(), vout.data());
241239
keyChild.fCompressed = true;
242240
keyChild.fValid = ret;
243241
return ret;
@@ -253,12 +251,10 @@ bool CExtKey::Derive(CExtKey &out, unsigned int _nChild) const {
253251

254252
void CExtKey::SetMaster(const unsigned char *seed, unsigned int nSeedLen) {
255253
static const unsigned char hashkey[] = {'B','i','t','c','o','i','n',' ','s','e','e','d'};
256-
unsigned char out[64];
257-
LockObject(out);
258-
CHMAC_SHA512(hashkey, sizeof(hashkey)).Write(seed, nSeedLen).Finalize(out);
259-
key.Set(&out[0], &out[32], true);
260-
memcpy(chaincode.begin(), &out[32], 32);
261-
UnlockObject(out);
254+
std::vector<unsigned char, secure_allocator<unsigned char>> vout(64);
255+
CHMAC_SHA512(hashkey, sizeof(hashkey)).Write(seed, nSeedLen).Finalize(vout.data());
256+
key.Set(&vout[0], &vout[32], true);
257+
memcpy(chaincode.begin(), &vout[32], 32);
262258
nDepth = 0;
263259
nChild = 0;
264260
memset(vchFingerprint, 0, sizeof(vchFingerprint));
@@ -308,12 +304,10 @@ void ECC_Start() {
308304

309305
{
310306
// Pass in a random blinding seed to the secp256k1 context.
311-
unsigned char seed[32];
312-
LockObject(seed);
313-
GetRandBytes(seed, 32);
314-
bool ret = secp256k1_context_randomize(ctx, seed);
307+
std::vector<unsigned char, secure_allocator<unsigned char>> vseed(32);
308+
GetRandBytes(vseed.data(), 32);
309+
bool ret = secp256k1_context_randomize(ctx, vseed.data());
315310
assert(ret);
316-
UnlockObject(seed);
317311
}
318312

319313
secp256k1_context_sign = ctx;

src/key.h

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,7 @@ class CKey
4343
bool fCompressed;
4444

4545
//! The actual byte data
46-
unsigned char vch[32];
47-
48-
static_assert(sizeof(vch) == 32, "vch must be 32 bytes in length to not break serialization");
46+
std::vector<unsigned char, secure_allocator<unsigned char> > keydata;
4947

5048
//! Check whether the 32-byte array pointed to be vch is valid keydata.
5149
bool static Check(const unsigned char* vch);
@@ -54,37 +52,30 @@ class CKey
5452
//! Construct an invalid private key.
5553
CKey() : fValid(false), fCompressed(false)
5654
{
57-
LockObject(vch);
58-
}
59-
60-
//! Copy constructor. This is necessary because of memlocking.
61-
CKey(const CKey& secret) : fValid(secret.fValid), fCompressed(secret.fCompressed)
62-
{
63-
LockObject(vch);
64-
memcpy(vch, secret.vch, sizeof(vch));
55+
// Important: vch must be 32 bytes in length to not break serialization
56+
keydata.resize(32);
6557
}
6658

6759
//! Destructor (again necessary because of memlocking).
6860
~CKey()
6961
{
70-
UnlockObject(vch);
7162
}
7263

7364
friend bool operator==(const CKey& a, const CKey& b)
7465
{
7566
return a.fCompressed == b.fCompressed &&
7667
a.size() == b.size() &&
77-
memcmp(&a.vch[0], &b.vch[0], a.size()) == 0;
68+
memcmp(a.keydata.data(), b.keydata.data(), a.size()) == 0;
7869
}
7970

8071
//! Initialize using begin and end iterators to byte data.
8172
template <typename T>
8273
void Set(const T pbegin, const T pend, bool fCompressedIn)
8374
{
84-
if (pend - pbegin != sizeof(vch)) {
75+
if (size_t(pend - pbegin) != keydata.size()) {
8576
fValid = false;
8677
} else if (Check(&pbegin[0])) {
87-
memcpy(vch, (unsigned char*)&pbegin[0], sizeof(vch));
78+
memcpy(keydata.data(), (unsigned char*)&pbegin[0], keydata.size());
8879
fValid = true;
8980
fCompressed = fCompressedIn;
9081
} else {
@@ -93,9 +84,9 @@ class CKey
9384
}
9485

9586
//! Simple read-only vector-like interface.
96-
unsigned int size() const { return (fValid ? sizeof(vch) : 0); }
97-
const unsigned char* begin() const { return vch; }
98-
const unsigned char* end() const { return vch + size(); }
87+
unsigned int size() const { return (fValid ? keydata.size() : 0); }
88+
const unsigned char* begin() const { return keydata.data(); }
89+
const unsigned char* end() const { return keydata.data() + size(); }
9990

10091
//! Check whether this private key is valid.
10192
bool IsValid() const { return fValid; }

src/support/pagelocker.h

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -157,21 +157,4 @@ class LockedPageManager : public LockedPageManagerBase<MemoryPageLocker>
157157
static boost::once_flag init_flag;
158158
};
159159

160-
//
161-
// Functions for directly locking/unlocking memory objects.
162-
// Intended for non-dynamically allocated structures.
163-
//
164-
template <typename T>
165-
void LockObject(const T& t)
166-
{
167-
LockedPageManager::Instance().LockRange((void*)(&t), sizeof(T));
168-
}
169-
170-
template <typename T>
171-
void UnlockObject(const T& t)
172-
{
173-
memory_cleanse((void*)(&t), sizeof(T));
174-
LockedPageManager::Instance().UnlockRange((void*)(&t), sizeof(T));
175-
}
176-
177160
#endif // BITCOIN_SUPPORT_PAGELOCKER_H

0 commit comments

Comments
 (0)