Browse Source

Secure datatypes now copyable only to similar datatypes.

More restrictions on usage to prevent accidental data leakage.
cl-refactor
Gav Wood 10 years ago
parent
commit
591b4c8c64
  1. 5
      alethzero/DappLoader.cpp
  2. 22
      alethzero/MainWin.cpp
  3. 16
      eth/main.cpp
  4. 24
      ethkey/KeyAux.h
  5. 29
      libdevcore/Common.h
  6. 11
      libdevcore/CommonJS.h
  7. 79
      libdevcore/FixedHash.h
  8. 9
      libdevcore/SHA3.cpp
  9. 19
      libdevcore/SHA3.h
  10. 12
      libdevcore/vector_ref.h
  11. 32
      libdevcrypto/Common.cpp
  12. 32
      libdevcrypto/Common.h
  13. 14
      libdevcrypto/CryptoPP.cpp
  14. 4
      libdevcrypto/CryptoPP.h
  15. 2
      libdevcrypto/ECDHE.cpp
  16. 2
      libdevcrypto/ECDHE.h
  17. 59
      libdevcrypto/SecretStore.cpp
  18. 7
      libdevcrypto/SecretStore.h
  19. 2
      libethcore/BasicAuthority.cpp
  20. 2
      libethcore/CommonJS.h
  21. 16
      libethcore/KeyManager.cpp
  22. 6
      libethcore/KeyManager.h
  23. 2
      libp2p/Host.cpp
  24. 4
      libp2p/RLPxHandshake.cpp
  25. 8
      libwhisper/Message.cpp
  26. 2
      libwhisper/Message.h
  27. 2
      mix/FileIo.cpp
  28. 6
      test/libdevcrypto/AES.cpp
  29. 32
      test/libdevcrypto/SecretStore.cpp
  30. 39
      test/libdevcrypto/crypto.cpp
  31. 14
      test/libethcore/commonjs.cpp

5
alethzero/DappLoader.cpp

@ -130,14 +130,14 @@ void DappLoader::downloadComplete(QNetworkReply* _reply)
h256 expected = m_uriHashes[requestUrl];
bytes package(reinterpret_cast<unsigned char const*>(data.constData()), reinterpret_cast<unsigned char const*>(data.constData() + data.size()));
Secp256k1PP dec;
dec.decrypt(expected, package);
dec.decrypt(Secret(expected), package);
h256 got = sha3(package);
if (got != expected)
{
//try base64
data = QByteArray::fromBase64(data);
package = bytes(reinterpret_cast<unsigned char const*>(data.constData()), reinterpret_cast<unsigned char const*>(data.constData() + data.size()));
dec.decrypt(expected, package);
dec.decrypt(Secret(expected), package);
got = sha3(package);
if (got != expected)
throw dev::Exception() << errinfo_comment("Dapp content hash does not match");
@ -145,6 +145,7 @@ void DappLoader::downloadComplete(QNetworkReply* _reply)
RLP rlp(package);
loadDapp(rlp);
bytesRef(&package).cleanse(); // TODO: replace with bytesSec once the crypto API is up to it.
}
catch (...)
{

22
alethzero/MainWin.cpp

@ -845,29 +845,15 @@ void Main::readSettings(bool _skipGeometry)
restoreGeometry(s.value("geometry").toByteArray());
restoreState(s.value("windowState").toByteArray());
{
QByteArray b = s.value("address").toByteArray();
if (!b.isEmpty())
{
h256 k;
for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i)
{
memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret));
if (!m_keyManager.hasAccount(KeyPair(k).address()))
m_keyManager.import(k, "Imported (UNSAFE) key.");
}
}
}
{
m_myIdentities.clear();
QByteArray b = s.value("identities").toByteArray();
if (!b.isEmpty())
{
h256 k;
Secret k;
for (unsigned i = 0; i < b.size() / sizeof(Secret); ++i)
{
memcpy(&k, b.data() + i * sizeof(Secret), sizeof(Secret));
memcpy(k.writable().data(), b.data() + i * sizeof(Secret), sizeof(Secret));
if (!count(m_myIdentities.begin(), m_myIdentities.end(), KeyPair(k)))
m_myIdentities.append(KeyPair(k));
}
@ -960,7 +946,7 @@ void Main::on_importKey_triggered()
bytes b = fromHex(s.toStdString());
if (b.size() == 32)
{
auto k = KeyPair(h256(b));
auto k = KeyPair(Secret(bytesConstRef(&b)));
if (!m_keyManager.hasAccount(k.address()))
{
QString s = QInputDialog::getText(this, "Import Account Key", "Enter this account's name");
@ -1067,7 +1053,7 @@ void Main::on_exportKey_triggered()
auto hba = ui->ourAccounts->currentItem()->data(Qt::UserRole).toByteArray();
Address h((byte const*)hba.data(), Address::ConstructFromPointer);
Secret s = retrieveSecret(h);
QMessageBox::information(this, "Export Account Key", "Secret key to account " + QString::fromStdString(render(h) + " is:\n" + s.hex()));
QMessageBox::information(this, "Export Account Key", "Secret key to account " + QString::fromStdString(render(h) + " is:\n" + s.makeInsecure().hex()));
}
}

16
eth/main.cpp

@ -526,7 +526,7 @@ void interactiveMode(eth::Client* c, std::shared_ptr<eth::TrivialGasPricer> gasP
{
try
{
Secret secret = h256(fromHex(sechex));
Secret secret(fromHex(sechex));
Address dest = h160(fromHex(hexAddr));
c->submitTransaction(secret, amount, dest, data, gas, gasPrice);
}
@ -594,7 +594,7 @@ void interactiveMode(eth::Client* c, std::shared_ptr<eth::TrivialGasPricer> gasP
{
try
{
Secret secret = h256(fromHex(sechex));
Secret secret(fromHex(sechex));
Address dest = h160(fromHex(hexAddr));
c->submitTransaction(secret, amount, dest, data, gas, gasPrice, nonce);
}
@ -654,7 +654,7 @@ void interactiveMode(eth::Client* c, std::shared_ptr<eth::TrivialGasPricer> gasP
{
try
{
Secret secret = h256(fromHex(sechex));
Secret secret(fromHex(sechex));
cout << " new contract address : " << c->submitTransaction(secret, amount, data, gas, gasPrice) << endl;
}
catch (BadHexCharacter& _e)
@ -1147,12 +1147,6 @@ int main(int argc, char** argv)
if (b.size())
{
RLP config(b);
if (config[0].size() == 32) // secret key - import and forget.
{
Secret s = config[0].toHash<Secret>();
toImport.push_back(s);
}
else // new format - just use it as an address.
signingKey = config[0].toHash<Address>();
beneficiary = config[1].toHash<Address>();
}
@ -1300,13 +1294,13 @@ int main(int argc, char** argv)
else if ((arg == "-s" || arg == "--import-secret") && i + 1 < argc)
{
Secret s(fromHex(argv[++i]));
toImport.push_back(s);
toImport.emplace_back(s);
signingKey = toAddress(s);
}
else if ((arg == "-S" || arg == "--import-session-secret") && i + 1 < argc)
{
Secret s(fromHex(argv[++i]));
toImport.push_back(s);
toImport.emplace_back(s);
sessionKey = toAddress(s);
}
else if ((arg == "--sign-key") && i + 1 < argc)

24
ethkey/KeyAux.h

@ -192,7 +192,7 @@ public:
{
KeyPair k(Secret::random());
while (m_icap && k.address()[0])
k = KeyPair(sha3(k.secret()));
k = KeyPair(Secret(sha3(k.secret().ref())));
return k;
}
@ -352,7 +352,7 @@ public:
if (m_lock.empty())
m_lock = createPassword("Enter a password with which to secure this account: ");
auto k = makeKey();
h128 u = store.importSecret(k.secret().asBytes(), m_lock);
h128 u = store.importSecret(k.secret().ref(), m_lock);
cout << "Created key " << toUUID(u) << endl;
cout << " Address: " << k.address().hex() << endl;
cout << " ICAP: " << ICAP(k.address()).encoded() << endl;
@ -362,12 +362,12 @@ public:
for (string const& input: m_inputs)
{
h128 u;
bytes b;
b = fromHex(input);
bytesSec b;
b.writable() = fromHex(input);
if (b.size() != 32)
{
std::string s = contentsString(input);
b = fromHex(s);
b.writable() = fromHex(s);
if (b.size() != 32)
u = store.importKey(input);
}
@ -386,18 +386,18 @@ public:
if (!contents(i).empty())
{
h128 u = store.readKey(i, false);
bytes s = store.secret(u, [&](){ return getPassword("Enter password for key " + i + ": "); });
bytesSec s = store.secret(u, [&](){ return getPassword("Enter password for key " + i + ": "); });
cout << "Key " << i << ":" << endl;
cout << " UUID: " << toUUID(u) << ":" << endl;
cout << " Address: " << toAddress(Secret(s)).hex() << endl;
cout << " Secret: " << Secret(s).abridged() << endl;
cout << " Secret: " << toHex(s.ref().cropped(0, 8)) << "..." << endl;
}
else if (h128 u = fromUUID(i))
{
bytes s = store.secret(u, [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); });
bytesSec s = store.secret(u, [&](){ return getPassword("Enter password for key " + toUUID(u) + ": "); });
cout << "Key " << i << ":" << endl;
cout << " Address: " << toAddress(Secret(s)).hex() << endl;
cout << " Secret: " << Secret(s).abridged() << endl;
cout << " Secret: " << toHex(s.ref().cropped(0, 8)) << "..." << endl;
}
else
cerr << "Couldn't inspect " << i << "; not found." << endl;
@ -454,12 +454,12 @@ public:
{
string const& i = m_inputs[0];
h128 u;
bytes b;
b = fromHex(i);
bytesSec b;
b.writable() = fromHex(i);
if (b.size() != 32)
{
std::string s = contentsString(i);
b = fromHex(s);
b.writable() = fromHex(s);
if (b.size() != 32)
u = wallet.store().importKey(i);
}

29
libdevcore/Common.h

@ -80,11 +80,34 @@ using bytesRef = vector_ref<byte>;
using bytesConstRef = vector_ref<byte const>;
template <class T>
class secure_vector: public std::vector<T>
class secure_vector
{
public:
template <class ... Args> secure_vector(Args&& ... _args): std::vector<T>(_args ...) {}
~secure_vector() { vector_ref<T>(this).cleanse(); }
secure_vector() {}
secure_vector(secure_vector<T> const& _c) = default;
explicit secure_vector(unsigned _size): m_data(_size) {}
explicit secure_vector(unsigned _size, T _item): m_data(_size, _item) {}
explicit secure_vector(std::vector<T> const& _c): m_data(_c) {}
explicit secure_vector(vector_ref<T> _c): m_data(_c.data(), _c.data() + _c.size()) {}
explicit secure_vector(vector_ref<const T> _c): m_data(_c.data(), _c.data() + _c.size()) {}
~secure_vector() { ref().cleanse(); }
secure_vector<T>& operator=(secure_vector<T> const& _c) { ref().cleanse(); m_data = _c.m_data; return *this; }
std::vector<T>& writable() { clear(); return m_data; }
std::vector<T> const& makeInsecure() const { return m_data; }
void clear() { ref().cleanse(); }
vector_ref<T> ref() { return vector_ref<T>(&m_data); }
vector_ref<T const> ref() const { return vector_ref<T const>(&m_data); }
size_t size() const { return m_data.size(); }
bool empty() const { return m_data.empty(); }
void swap(secure_vector<T>& io_other) { m_data.swap(io_other.m_data); }
private:
std::vector<T> m_data;
};
using bytesSec = secure_vector<byte>;

11
libdevcore/CommonJS.h

@ -51,10 +51,17 @@ inline std::string toJS(bytes const& _n, std::size_t _padding = 0)
return "0x" + toHex(n);
}
template< typename T >std::string toJS( T const& i )
template<unsigned T> std::string toJS(SecureFixedHash<T> const& _i)
{
std::stringstream stream;
stream << "0x" << std::hex << i;
stream << "0x" << _i.makeInsecure().hex();
return stream.str();
}
template<typename T> std::string toJS(T const& _i)
{
std::stringstream stream;
stream << "0x" << std::hex << _i;
return stream.str();
}

79
libdevcore/FixedHash.h

@ -220,6 +220,77 @@ private:
std::array<byte, N> m_data; ///< The binary data.
};
template <unsigned T>
class SecureFixedHash: private FixedHash<T>
{
public:
using ConstructFromHashType = typename FixedHash<T>::ConstructFromHashType;
using ConstructFromStringType = typename FixedHash<T>::ConstructFromStringType;
using ConstructFromPointerType = typename FixedHash<T>::ConstructFromPointerType;
SecureFixedHash() = default;
explicit SecureFixedHash(bytes const& _b, ConstructFromHashType _t = FixedHash<T>::FailIfDifferent): FixedHash<T>(_b, _t) {}
explicit SecureFixedHash(bytesConstRef _b, ConstructFromHashType _t = FixedHash<T>::FailIfDifferent): FixedHash<T>(_b, _t) {}
explicit SecureFixedHash(bytesSec const& _b, ConstructFromHashType _t = FixedHash<T>::FailIfDifferent): FixedHash<T>(_b.ref(), _t) {}
template <unsigned M> explicit SecureFixedHash(FixedHash<M> const& _h, ConstructFromHashType _t = FixedHash<T>::AlignLeft): FixedHash<T>(_h, _t) {}
template <unsigned M> explicit SecureFixedHash(SecureFixedHash<M> const& _h, ConstructFromHashType _t = FixedHash<T>::AlignLeft): FixedHash<T>(_h.makeInsecure(), _t) {}
explicit SecureFixedHash(std::string const& _s, ConstructFromStringType _t = FixedHash<T>::FromHex, ConstructFromHashType _ht = FixedHash<T>::FailIfDifferent): FixedHash<T>(_s, _t, _ht) {}
explicit SecureFixedHash(bytes const* _d, ConstructFromPointerType _t): FixedHash<T>(_d, _t) {}
~SecureFixedHash() { ref().cleanse(); }
SecureFixedHash<T>& operator=(SecureFixedHash<T> const& _c) { ref().cleanse(); FixedHash<T>::operator=(static_cast<FixedHash<T> const&>(_c)); return *this; }
using FixedHash<T>::size;
bytesSec asBytesSec() const { return bytesSec(ref()); }
FixedHash<T> const& makeInsecure() const { return static_cast<FixedHash<T> const&>(*this); }
FixedHash<T>& writable() { clear(); return static_cast<FixedHash<T>&>(*this); }
using FixedHash<T>::operator bool;
// The obvious comparison operators.
bool operator==(SecureFixedHash const& _c) const { return static_cast<FixedHash<T> const&>(*this).operator==(static_cast<FixedHash<T> const&>(_c)); }
bool operator!=(SecureFixedHash const& _c) const { return static_cast<FixedHash<T> const&>(*this).operator!=(static_cast<FixedHash<T> const&>(_c)); }
bool operator<(SecureFixedHash const& _c) const { return static_cast<FixedHash<T> const&>(*this).operator<(static_cast<FixedHash<T> const&>(_c)); }
bool operator>=(SecureFixedHash const& _c) const { return static_cast<FixedHash<T> const&>(*this).operator>=(static_cast<FixedHash<T> const&>(_c)); }
bool operator<=(SecureFixedHash const& _c) const { return static_cast<FixedHash<T> const&>(*this).operator<=(static_cast<FixedHash<T> const&>(_c)); }
bool operator>(SecureFixedHash const& _c) const { return static_cast<FixedHash<T> const&>(*this).operator>(static_cast<FixedHash<T> const&>(_c)); }
using FixedHash<T>::operator==;
using FixedHash<T>::operator!=;
using FixedHash<T>::operator<;
using FixedHash<T>::operator>=;
using FixedHash<T>::operator<=;
using FixedHash<T>::operator>;
// The obvious binary operators.
SecureFixedHash& operator^=(FixedHash<T> const& _c) { static_cast<FixedHash<T>&>(*this).operator^=(_c); return *this; }
SecureFixedHash operator^(FixedHash<T> const& _c) const { return SecureFixedHash(*this) ^= _c; }
SecureFixedHash& operator|=(FixedHash<T> const& _c) { static_cast<FixedHash<T>&>(*this).operator^=(_c); return *this; }
SecureFixedHash operator|(FixedHash<T> const& _c) const { return SecureFixedHash(*this) |= _c; }
SecureFixedHash& operator&=(FixedHash<T> const& _c) { static_cast<FixedHash<T>&>(*this).operator^=(_c); return *this; }
SecureFixedHash operator&(FixedHash<T> const& _c) const { return SecureFixedHash(*this) &= _c; }
SecureFixedHash& operator^=(SecureFixedHash const& _c) { static_cast<FixedHash<T>&>(*this).operator^=(static_cast<FixedHash<T> const&>(_c)); return *this; }
SecureFixedHash operator^(SecureFixedHash const& _c) const { return SecureFixedHash(*this) ^= _c; }
SecureFixedHash& operator|=(SecureFixedHash const& _c) { static_cast<FixedHash<T>&>(*this).operator^=(static_cast<FixedHash<T> const&>(_c)); return *this; }
SecureFixedHash operator|(SecureFixedHash const& _c) const { return SecureFixedHash(*this) |= _c; }
SecureFixedHash& operator&=(SecureFixedHash const& _c) { static_cast<FixedHash<T>&>(*this).operator^=(static_cast<FixedHash<T> const&>(_c)); return *this; }
SecureFixedHash operator&(SecureFixedHash const& _c) const { return SecureFixedHash(*this) &= _c; }
SecureFixedHash operator~() const { ~static_cast<FixedHash<T>&>(*this); return *this; }
using FixedHash<T>::abridged;
using FixedHash<T>::abridgedMiddle;
bytesConstRef ref() const { return FixedHash<T>::ref(); }
byte const* data() const { return FixedHash<T>::data(); }
static SecureFixedHash<T> random() { SecureFixedHash<T> ret; ret.FixedHash<T>::ref().randomize(); return ret; }
using FixedHash<T>::firstBitSet;
void clear() { ref().cleanse(); }
};
/// Fast equality operator for h256.
template<> inline bool FixedHash<32>::operator==(FixedHash<32> const& _other) const
{
@ -246,6 +317,14 @@ inline std::ostream& operator<<(std::ostream& _out, FixedHash<N> const& _h)
return _out;
}
/// Stream I/O for the SecureFixedHash class.
template <unsigned N>
inline std::ostream& operator<<(std::ostream& _out, SecureFixedHash<N> const& _h)
{
_out << "SecureFixedHash#" << std::hex << typename FixedHash<N>::hash()(_h.makeInsecure()) << std::dec;
return _out;
}
// Common types of FixedHash.
using h2048 = FixedHash<256>;
using h1024 = FixedHash<128>;

9
libdevcore/SHA3.cpp

@ -211,13 +211,14 @@ defsha3(512)
}
h256 sha3(bytesConstRef _input)
bool sha3(bytesConstRef _input, bytesRef o_output)
{
// FIXME: What with unaligned memory?
h256 ret;
keccak::sha3_256(ret.data(), 32, _input.data(), _input.size());
if (o_output.size() != 32)
return false;
keccak::sha3_256(o_output.data(), 32, _input.data(), _input.size());
// keccak::keccak(ret.data(), 32, (uint64_t const*)_input.data(), _input.size());
return ret;
return true;
}
}

19
libdevcore/SHA3.h

@ -32,20 +32,31 @@ namespace dev
// SHA-3 convenience routines.
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
h256 sha3(bytesConstRef _input);
/// Calculate SHA3-256 hash of the given input and load it into the given output.
inline void sha3(bytesConstRef _input, bytesRef _output) { sha3(_input).ref().populate(_output); }
/// @returns false if o_output.size() != 32.
bool sha3(bytesConstRef _input, bytesRef o_output);
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
inline h256 sha3(bytesConstRef _input) { h256 ret; sha3(_input, ret.ref()); return ret; }
inline SecureFixedHash<32> sha3Secure(bytesConstRef _input) { SecureFixedHash<32> ret; sha3(_input, ret.writable().ref()); return ret; }
/// Calculate SHA3-256 hash of the given input, returning as a 256-bit hash.
inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef(&_input)); }
inline SecureFixedHash<32> sha3Secure(bytes const& _input) { return sha3Secure(bytesConstRef(&_input)); }
/// Calculate SHA3-256 hash of the given input (presented as a binary-filled string), returning as a 256-bit hash.
inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); }
inline SecureFixedHash<32> sha3Secure(std::string const& _input) { return sha3Secure(bytesConstRef(_input)); }
/// Calculate SHA3-256 hash of the given input (presented as a FixedHash), returns a 256-bit hash.
template<unsigned N> inline h256 sha3(FixedHash<N> const& _input) { return sha3(_input.ref()); }
template<unsigned N> inline SecureFixedHash<32> sha3Secure(FixedHash<N> const& _input) { return sha3Secure(_input.ref()); }
/// Fully secure variants are equivalent for sha3 and sha3Secure.
inline SecureFixedHash<32> sha3(bytesSec const& _input) { return sha3Secure(_input.ref()); }
inline SecureFixedHash<32> sha3Secure(bytesSec const& _input) { return sha3Secure(_input.ref()); }
template<unsigned N> inline SecureFixedHash<32> sha3(SecureFixedHash<N> const& _input) { return sha3Secure(_input.ref()); }
template<unsigned N> inline SecureFixedHash<32> sha3Secure(SecureFixedHash<N> const& _input) { return sha3Secure(_input.ref()); }
/// Calculate SHA3-256 hash of the given input, possibly interpreting it as nibbles, and return the hash as a string filled with binary data.
inline std::string sha3(std::string const& _input, bool _isNibbles) { return asString((_isNibbles ? sha3(fromHex(_input)) : sha3(bytesConstRef(&_input))).asBytes()); }

12
libdevcore/vector_ref.h

@ -5,11 +5,13 @@
#include <type_traits>
#include <vector>
#include <string>
#include <random>
namespace dev
{
static unsigned char s_cleanseCounter = 0;
static std::random_device s_vectorRefEngine;
/**
* A modifiable reference to an existing object or vector in memory.
@ -67,6 +69,16 @@ public:
void copyTo(vector_ref<typename std::remove_const<_T>::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); }
/// Copies the contents of this vector_ref to the contents of @a _t, and zeros further trailing elements in @a _t.
void populate(vector_ref<typename std::remove_const<_T>::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); }
/// Populate with random data.
template <class Engine>
void randomize(Engine& _eng)
{
uint8_t* e = (uint8_t*)end();
for (uint8_t* i = (uint8_t*)begin(); i != e; ++i)
*i = (uint8_t)std::uniform_int_distribution<uint16_t>(0, 255)(_eng);
}
/// @returns a random valued object.
void randomize() { randomize(s_vectorRefEngine); }
/// Securely overwrite the memory.
/// @note adapted from OpenSSL's implementation.
void cleanse()

32
libdevcrypto/Common.cpp

@ -149,7 +149,7 @@ bool dev::decryptSym(Secret const& _k, bytesConstRef _cipher, bytes& o_plain)
return decrypt(_k, _cipher, o_plain);
}
std::pair<bytes, h128> dev::encryptSymNoAuth(h128 const& _k, bytesConstRef _plain)
std::pair<bytes, h128> dev::encryptSymNoAuth(SecureFixedHash<16> const& _k, bytesConstRef _plain)
{
h128 iv(Nonce::get());
return make_pair(encryptSymNoAuth(_k, iv, _plain), iv);
@ -175,23 +175,23 @@ bytes dev::encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _pl
}
}
bytes dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher)
bytesSec dev::decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher)
{
if (_k.size() != 16 && _k.size() != 24 && _k.size() != 32)
return bytes();
return bytesSec();
SecByteBlock key(_k.data(), _k.size());
try
{
CTR_Mode<AES>::Decryption d;
d.SetKeyWithIV(key, key.size(), _iv.data());
bytes ret(_cipher.size());
d.ProcessData(ret.data(), _cipher.data(), _cipher.size());
bytesSec ret(_cipher.size());
d.ProcessData(ret.writable().data(), _cipher.data(), _cipher.size());
return ret;
}
catch (CryptoPP::Exception& _e)
{
cerr << _e.what() << endl;
return bytes();
return bytesSec();
}
}
@ -239,12 +239,12 @@ bool dev::verify(Public const& _p, Signature const& _s, h256 const& _hash)
#endif
}
bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen)
bytesSec dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen)
{
bytes ret(_dkLen);
bytesSec ret(_dkLen);
if (PKCS5_PBKDF2_HMAC<SHA256>().DeriveKey(
ret.data(),
ret.size(),
ret.writable().data(),
_dkLen,
0,
reinterpret_cast<byte const*>(_pass.data()),
_pass.size(),
@ -256,9 +256,9 @@ bytes dev::pbkdf2(string const& _pass, bytes const& _salt, unsigned _iterations,
return ret;
}
bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen)
bytesSec dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen)
{
bytes ret(_dkLen);
bytesSec ret(_dkLen);
if (libscrypt_scrypt(
reinterpret_cast<uint8_t const*>(_pass.data()),
_pass.size(),
@ -267,8 +267,8 @@ bytes dev::scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uin
_n,
_r,
_p,
ret.data(),
ret.size()
ret.writable().data(),
_dkLen
) != 0)
BOOST_THROW_EXCEPTION(CryptoException() << errinfo_comment("Key derivation failed."));
return ret;
@ -285,7 +285,7 @@ KeyPair KeyPair::create()
{
for (int i = 0; i < 100; ++i)
{
KeyPair ret(FixedHash<32>::random());
KeyPair ret(Secret::random());
if (ret.address())
return ret;
}
@ -294,7 +294,7 @@ KeyPair KeyPair::create()
KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _password)
{
return KeyPair(sha3(aesDecrypt(_seed, _password)));
return KeyPair(Secret(sha3(aesDecrypt(_seed, _password))));
}
h256 crypto::kdf(Secret const& _priv, h256 const& _hash)

32
libdevcrypto/Common.h

@ -32,15 +32,7 @@
namespace dev
{
/// A secret key: 32 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
class Secret: public h256
{
public:
template <class ... Args> Secret(Args&& ... _args): h256(_args ...) {}
Secret(bytesSec const& _b): h256(bytesConstRef(&_b)) {}
~Secret() { ref().cleanse(); }
};
using Secret = SecureFixedHash<32>;
/// A public key: 64 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
@ -82,7 +74,7 @@ using Addresses = h160s;
using AddressHash = std::unordered_set<h160>;
/// A vector of secrets.
using Secrets = h256s;
using Secrets = std::vector<Secret>;
/// Convert a secret key into the public key equivalent.
Public toPublic(Secret const& _secret);
@ -116,21 +108,21 @@ void encryptECIES(Public const& _k, bytesConstRef _plain, bytes& o_cipher);
bool decryptECIES(Secret const& _k, bytesConstRef _cipher, bytes& o_plaintext);
/// Encrypts payload with random IV/ctr using AES128-CTR.
std::pair<bytes, h128> encryptSymNoAuth(h128 const& _k, bytesConstRef _plain);
std::pair<bytes, h128> encryptSymNoAuth(SecureFixedHash<16> const& _k, bytesConstRef _plain);
/// Encrypts payload with specified IV/ctr using AES128-CTR.
bytes encryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _plain);
/// Decrypts payload with specified IV/ctr using AES128-CTR.
bytes decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher);
bytesSec decryptAES128CTR(bytesConstRef _k, h128 const& _iv, bytesConstRef _cipher);
/// Encrypts payload with specified IV/ctr using AES128-CTR.
inline bytes encryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); }
inline bytes encryptSymNoAuth(h256 const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); }
inline bytes encryptSymNoAuth(SecureFixedHash<16> const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); }
inline bytes encryptSymNoAuth(SecureFixedHash<32> const& _k, h128 const& _iv, bytesConstRef _plain) { return encryptAES128CTR(_k.ref(), _iv, _plain); }
/// Decrypts payload with specified IV/ctr using AES128-CTR.
inline bytes decryptSymNoAuth(h128 const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); }
inline bytes decryptSymNoAuth(h256 const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); }
inline bytesSec decryptSymNoAuth(SecureFixedHash<16> const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); }
inline bytesSec decryptSymNoAuth(SecureFixedHash<32> const& _k, h128 const& _iv, bytesConstRef _cipher) { return decryptAES128CTR(_k.ref(), _iv, _cipher); }
/// Recovers Public key from signed message hash.
Public recover(Signature const& _sig, h256 const& _hash);
@ -142,10 +134,10 @@ Signature sign(Secret const& _k, h256 const& _hash);
bool verify(Public const& _k, Signature const& _s, h256 const& _hash);
/// Derive key via PBKDF2.
bytes pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32);
bytesSec pbkdf2(std::string const& _pass, bytes const& _salt, unsigned _iterations, unsigned _dkLen = 32);
/// Derive key via Scrypt.
bytes scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen);
bytesSec scrypt(std::string const& _pass, bytes const& _salt, uint64_t _n, uint32_t _r, uint32_t _p, unsigned _dkLen);
/// Simple class that represents a "key pair".
/// All of the data of the class can be regenerated from the secret key (m_secret) alone.
@ -176,8 +168,8 @@ public:
/// Retrieve the associated address of the public key.
Address const& address() const { return m_address; }
bool operator==(KeyPair const& _c) const { return m_secret == _c.m_secret; }
bool operator!=(KeyPair const& _c) const { return m_secret != _c.m_secret; }
bool operator==(KeyPair const& _c) const { return m_public == _c.m_public; }
bool operator!=(KeyPair const& _c) const { return m_public != _c.m_public; }
private:
void populateFromSecret(Secret const& _k);

14
libdevcrypto/CryptoPP.cpp

@ -67,7 +67,7 @@ void Secp256k1PP::encryptECIES(Public const& _k, bytes& io_cipher)
{
// interop w/go ecies implementation
auto r = KeyPair::create();
h256 z;
Secret z;
ecdh::agree(r.sec(), _k, z);
auto key = eciesKDF(z, bytes(), 32);
bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16);
@ -77,7 +77,7 @@ void Secp256k1PP::encryptECIES(Public const& _k, bytes& io_cipher)
bytes mKey(32);
ctx.Final(mKey.data());
bytes cipherText = encryptSymNoAuth(h128(eKey), h128(), bytesConstRef(&io_cipher));
bytes cipherText = encryptSymNoAuth(SecureFixedHash<16>(eKey), h128(), bytesConstRef(&io_cipher));
if (cipherText.empty())
return;
@ -110,7 +110,7 @@ bool Secp256k1PP::decryptECIES(Secret const& _k, bytes& io_text)
// invalid message: length
return false;
h256 z;
Secret z;
ecdh::agree(_k, *(Public*)(io_text.data() + 1), z);
auto key = eciesKDF(z, bytes(), 64);
bytesConstRef eKey = bytesConstRef(&key).cropped(0, 16);
@ -137,7 +137,7 @@ bool Secp256k1PP::decryptECIES(Secret const& _k, bytes& io_text)
if (mac[i] != msgMac[i])
return false;
plain = decryptSymNoAuth(h128(eKey), iv, cipherNoIV);
plain = decryptSymNoAuth(SecureFixedHash<16>(eKey), iv, cipherNoIV).makeInsecure();
io_text.resize(plain.size());
io_text.swap(plain);
@ -222,7 +222,7 @@ Signature Secp256k1PP::sign(Secret const& _key, h256 const& _hash)
Integer kInv = k.InverseMod(m_q);
Integer z(_hash.asBytes().data(), 32);
Integer s = (kInv * (Integer(_key.asBytes().data(), 32) * r + z)) % m_q;
Integer s = (kInv * (Integer(_key.data(), 32) * r + z)) % m_q;
if (r == 0 || s == 0)
BOOST_THROW_EXCEPTION(InvalidState());
@ -310,7 +310,7 @@ bool Secp256k1PP::verifySecret(Secret const& _s, Public& _p)
return true;
}
void Secp256k1PP::agree(Secret const& _s, Public const& _r, h256& o_s)
void Secp256k1PP::agree(Secret const& _s, Public const& _r, Secret& o_s)
{
// TODO: mutex ASN1::secp256k1() singleton
// Creating Domain is non-const for m_oid and m_oid is not thread-safe
@ -318,7 +318,7 @@ void Secp256k1PP::agree(Secret const& _s, Public const& _r, h256& o_s)
assert(d.AgreedValueLength() == sizeof(o_s));
byte remote[65] = {0x04};
memcpy(&remote[1], _r.data(), 64);
d.Agree(o_s.data(), _s.data(), remote);
d.Agree(o_s.writable().data(), _s.data(), remote);
}
void Secp256k1PP::exportPublicKey(CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> const& _k, Public& o_p)

4
libdevcrypto/CryptoPP.h

@ -107,10 +107,10 @@ public:
/// Verifies _s is a valid secret key and returns corresponding public key in o_p.
bool verifySecret(Secret const& _s, Public& o_p);
void agree(Secret const& _s, Public const& _r, h256& o_s);
void agree(Secret const& _s, Public const& _r, Secret& o_s);
protected:
void exportPrivateKey(DL_PrivateKey_EC<ECP> const& _k, Secret& o_s) { _k.GetPrivateExponent().Encode(o_s.data(), Secret::size); }
void exportPrivateKey(DL_PrivateKey_EC<ECP> const& _k, Secret& o_s) { _k.GetPrivateExponent().Encode(o_s.writable().data(), Secret::size); }
void exportPublicKey(DL_PublicKey_EC<ECP> const& _k, Public& o_p);

2
libdevcrypto/ECDHE.cpp

@ -29,7 +29,7 @@ using namespace dev::crypto;
static Secp256k1PP s_secp256k1;
void dev::crypto::ecdh::agree(Secret const& _s, Public const& _r, h256& o_s)
void dev::crypto::ecdh::agree(Secret const& _s, Public const& _r, Secret& o_s)
{
s_secp256k1.agree(_s, _r, o_s);
}

2
libdevcrypto/ECDHE.h

@ -50,7 +50,7 @@ private:
namespace ecdh
{
void agree(Secret const& _s, Public const& _r, h256& o_s);
void agree(Secret const& _s, Public const& _r, Secret& o_s);
}
/**

59
libdevcrypto/SecretStore.cpp

@ -100,17 +100,17 @@ bytesSec SecretStore::secret(h128 const& _uuid, function<string()> const& _pass,
bytesSec key;
if (it != m_keys.end())
{
key = decrypt(it->second.encryptedKey, _pass());
key = bytesSec(decrypt(it->second.encryptedKey, _pass()));
if (!key.empty())
m_cached[_uuid] = key;
}
return key;
}
h128 SecretStore::importSecret(bytes const& _s, string const& _pass)
h128 SecretStore::importSecret(bytesSec const& _s, string const& _pass)
{
h128 r;
EncryptedKey key{encrypt(_s, _pass), string()};
EncryptedKey key{encrypt(_s.ref(), _pass), string()};
r = h128::random();
m_cached[r] = _s;
m_keys[r] = move(key);
@ -118,6 +118,17 @@ h128 SecretStore::importSecret(bytes const& _s, string const& _pass)
return r;
}
h128 SecretStore::importSecret(bytesConstRef _s, string const& _pass)
{
h128 r;
EncryptedKey key{encrypt(_s, _pass), string()};
r = h128::random();
m_cached[r] = bytesSec(_s);
m_keys[r] = move(key);
save();
return r;
}
void SecretStore::kill(h128 const& _uuid)
{
m_cached.erase(_uuid);
@ -188,16 +199,16 @@ h128 SecretStore::readKeyContent(string const& _content, string const& _file)
bool SecretStore::recode(h128 const& _uuid, string const& _newPass, function<string()> const& _pass, KDF _kdf)
{
bytes s = secret(_uuid, _pass, true);
bytesSec s = secret(_uuid, _pass, true);
if (s.empty())
return false;
m_cached.erase(_uuid);
m_keys[_uuid].encryptedKey = encrypt(s, _newPass, _kdf);
m_keys[_uuid].encryptedKey = encrypt(s.ref(), _newPass, _kdf);
save();
return true;
}
static bytes deriveNewKey(string const& _pass, KDF _kdf, js::mObject& o_ret)
static bytesSec deriveNewKey(string const& _pass, KDF _kdf, js::mObject& o_ret)
{
unsigned dklen = 32;
unsigned iterations = 1 << 18;
@ -233,16 +244,16 @@ static bytes deriveNewKey(string const& _pass, KDF _kdf, js::mObject& o_ret)
}
}
string SecretStore::encrypt(bytes const& _v, string const& _pass, KDF _kdf)
string SecretStore::encrypt(bytesConstRef _v, string const& _pass, KDF _kdf)
{
js::mObject ret;
bytes derivedKey = deriveNewKey(_pass, _kdf, ret);
bytesSec derivedKey = deriveNewKey(_pass, _kdf, ret);
if (derivedKey.empty())
BOOST_THROW_EXCEPTION(crypto::CryptoException() << errinfo_comment("Key derivation failed."));
ret["cipher"] = "aes-128-ctr";
h128 key(derivedKey, h128::AlignLeft);
SecureFixedHash<16> key(derivedKey, h128::AlignLeft);
h128 iv = h128::random();
{
js::mObject params;
@ -251,19 +262,19 @@ string SecretStore::encrypt(bytes const& _v, string const& _pass, KDF _kdf)
}
// cipher text
bytes cipherText = encryptSymNoAuth(key, iv, &_v);
bytes cipherText = encryptSymNoAuth(key, iv, _v);
if (cipherText.empty())
BOOST_THROW_EXCEPTION(crypto::CryptoException() << errinfo_comment("Key encryption failed."));
ret["ciphertext"] = toHex(cipherText);
// and mac.
h256 mac = sha3(ref(derivedKey).cropped(16, 16).toBytes() + cipherText);
h256 mac = sha3(derivedKey.ref().cropped(16, 16).toBytes() + cipherText);
ret["mac"] = toHex(mac.ref());
return js::write_string(js::mValue(ret), true);
}
bytes SecretStore::decrypt(string const& _v, string const& _pass)
bytesSec SecretStore::decrypt(string const& _v, string const& _pass)
{
js::mObject o;
{
@ -273,14 +284,14 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass)
}
// derive key
bytes derivedKey;
bytesSec derivedKey;
if (o["kdf"].get_str() == "pbkdf2")
{
auto params = o["kdfparams"].get_obj();
if (params["prf"].get_str() != "hmac-sha256")
{
cwarn << "Unknown PRF for PBKDF2" << params["prf"].get_str() << "not supported.";
return bytes();
return bytesSec();
}
unsigned iterations = params["c"].get_int();
bytes salt = fromHex(params["salt"].get_str());
@ -294,13 +305,13 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass)
else
{
cwarn << "Unknown KDF" << o["kdf"].get_str() << "not supported.";
return bytes();
return bytesSec();
}
if (derivedKey.size() < 32 && !(o.count("compat") && o["compat"].get_str() == "2"))
{
cwarn << "Derived key's length too short (<32 bytes)";
return bytes();
return bytesSec();
}
bytes cipherText = fromHex(o["ciphertext"].get_str());
@ -311,23 +322,23 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass)
h256 mac(o["mac"].get_str());
h256 macExp;
if (o.count("compat") && o["compat"].get_str() == "2")
macExp = sha3(bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
macExp = sha3(derivedKey.ref().cropped(derivedKey.size() - 16).toBytes() + cipherText);
else
macExp = sha3(bytesConstRef(&derivedKey).cropped(16, 16).toBytes() + cipherText);
macExp = sha3(derivedKey.ref().cropped(16, 16).toBytes() + cipherText);
if (mac != macExp)
{
cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac);
return bytes();
return bytesSec();
}
}
else if (o.count("sillymac"))
{
h256 mac(o["sillymac"].get_str());
h256 macExp = sha3(asBytes(o["sillymacjson"].get_str()) + bytesConstRef(&derivedKey).cropped(derivedKey.size() - 16).toBytes() + cipherText);
h256 macExp = sha3(asBytes(o["sillymacjson"].get_str()) + derivedKey.ref().cropped(derivedKey.size() - 16).toBytes() + cipherText);
if (mac != macExp)
{
cwarn << "Invalid key - MAC mismatch; expected" << toString(macExp) << ", got" << toString(mac);
return bytes();
return bytesSec();
}
}
else
@ -340,15 +351,15 @@ bytes SecretStore::decrypt(string const& _v, string const& _pass)
h128 iv(params["iv"].get_str());
if (o.count("compat") && o["compat"].get_str() == "2")
{
h128 key(sha3(h128(derivedKey, h128::AlignRight)), h128::AlignRight);
SecureFixedHash<16> key(sha3Secure(derivedKey.ref().cropped(derivedKey.size() - 16)), h128::AlignRight);
return decryptSymNoAuth(key, iv, &cipherText);
}
else
return decryptSymNoAuth(h128(derivedKey, h128::AlignLeft), iv, &cipherText);
return decryptSymNoAuth(SecureFixedHash<16>(derivedKey, h128::AlignLeft), iv, &cipherText);
}
else
{
cwarn << "Unknown cipher" << o["cipher"].get_str() << "not supported.";
return bytes();
return bytesSec();
}
}

7
libdevcrypto/SecretStore.h

@ -60,7 +60,8 @@ public:
h128 importKeyContent(std::string const& _content) { auto ret = readKeyContent(_content, std::string()); if (ret) save(); return ret; }
/// Imports the decrypted key given by @a _s and stores it, encrypted with
/// (a key derived from) the password @a _pass.
h128 importSecret(bytes const& _s, std::string const& _pass);
h128 importSecret(bytesSec const& _s, std::string const& _pass);
h128 importSecret(bytesConstRef _s, std::string const& _pass);
/// Decrypts and re-encrypts the key identified by @a _uuid.
bool recode(h128 const& _uuid, std::string const& _newPass, std::function<std::string()> const& _pass, KDF _kdf = KDF::Scrypt);
/// Removes the key specified by @a _uuid from both memory and disk.
@ -102,9 +103,9 @@ private:
void load(std::string const& _keysPath);
void load() { load(m_path); }
/// Encrypts @a _v with a key derived from @a _pass or the empty string on error.
static std::string encrypt(bytes const& _v, std::string const& _pass, KDF _kdf = KDF::Scrypt);
static std::string encrypt(bytesConstRef _v, std::string const& _pass, KDF _kdf = KDF::Scrypt);
/// Decrypts @a _v with a key derived from @a _pass or the empty byte array on error.
static bytes decrypt(std::string const& _v, std::string const& _pass);
static bytesSec decrypt(std::string const& _v, std::string const& _pass);
/// Stores decrypted keys by uuid.
mutable std::unordered_map<h128, bytesSec> m_cached;

2
libethcore/BasicAuthority.cpp

@ -101,7 +101,7 @@ private:
if (_name == "authorities")
BasicAuthority::s_authorities = rlp.toUnorderedSet<Address>();
else if (_name == "authority")
m_secret = rlp.toHash<Secret>();
m_secret = Secret(rlp.toHash<h256>());
else
return false;
return true;

2
libethcore/CommonJS.h

@ -40,7 +40,7 @@ Address toAddress(std::string const& _a);
inline Public jsToPublic(std::string const& _s) { return jsToFixed<sizeof(dev::Public)>(_s); }
/// Leniently convert string to Secret (h256). Accepts integers, "0x" prefixing, non-exact length.
inline Secret jsToSecret(std::string const& _s) { return jsToFixed<sizeof(dev::Secret)>(_s); }
inline Secret jsToSecret(std::string const& _s) { h256 d = jsToFixed<sizeof(dev::Secret)>(_s); Secret ret(d); d.ref().cleanse(); return ret; }
/// Leniently convert string to Address (h160). Accepts integers, "0x" prefixing, non-exact length.
inline Address jsToAddress(std::string const& _s) { return jsToFixed<sizeof(dev::Address)>(_s); }

16
libethcore/KeyManager.cpp

@ -81,9 +81,9 @@ bool KeyManager::load(string const& _pass)
{
bytes salt = contents(m_keysFile + ".salt");
bytes encKeys = contents(m_keysFile);
m_keysFileKey = h128(pbkdf2(_pass, salt, 262144, 16));
bytes bs = decryptSymNoAuth(m_keysFileKey, h128(), &encKeys);
RLP s(bs);
m_keysFileKey = SecureFixedHash<16>(pbkdf2(_pass, salt, 262144, 16));
bytesSec bs = decryptSymNoAuth(m_keysFileKey, h128(), &encKeys);
RLP s(bs.ref());
unsigned version = unsigned(s[0]);
if (version == 1)
{
@ -178,7 +178,7 @@ h128 KeyManager::import(Secret const& _s, string const& _accountName, string con
auto passHash = hashPassword(_pass);
cachePassword(_pass);
m_passwordHint[passHash] = _passwordHint;
auto uuid = m_store.importSecret(_s.asBytes(), _pass);
auto uuid = m_store.importSecret(_s.asBytesSec(), _pass);
m_keyInfo[uuid] = KeyInfo{passHash, _accountName};
m_addrLookup[addr] = uuid;
write(m_keysFile);
@ -187,7 +187,7 @@ h128 KeyManager::import(Secret const& _s, string const& _accountName, string con
void KeyManager::importExisting(h128 const& _uuid, string const& _info, string const& _pass, string const& _passwordHint)
{
bytes key = m_store.secret(_uuid, [&](){ return _pass; });
bytesSec key = m_store.secret(_uuid, [&](){ return _pass; });
if (key.empty())
return;
Address a = KeyPair(Secret(key)).address();
@ -258,7 +258,7 @@ string const& KeyManager::passwordHint(Address const& _address) const
h256 KeyManager::hashPassword(string const& _pass) const
{
// TODO SECURITY: store this a bit more securely; Scrypt perhaps?
return h256(pbkdf2(_pass, asBytes(m_defaultPasswordDeprecated), 262144, 32));
return h256(pbkdf2(_pass, asBytes(m_defaultPasswordDeprecated), 262144, 32).makeInsecure());
}
void KeyManager::cachePassword(string const& _password) const
@ -278,14 +278,14 @@ void KeyManager::write(string const& _pass, string const& _keysFile) const
{
bytes salt = h256::random().asBytes();
writeFile(_keysFile + ".salt", salt);
auto key = h128(pbkdf2(_pass, salt, 262144, 16));
auto key = SecureFixedHash<16>(pbkdf2(_pass, salt, 262144, 16));
cachePassword(_pass);
m_master = hashPassword(_pass);
write(key, _keysFile);
}
void KeyManager::write(h128 const& _key, string const& _keysFile) const
void KeyManager::write(SecureFixedHash<16> const& _key, string const& _keysFile) const
{
RLPStream s(4);
s << 1; // version

6
libethcore/KeyManager.h

@ -136,8 +136,8 @@ private:
// @returns false if wasn't previously loaded ok.
bool write() const { return write(m_keysFile); }
bool write(std::string const& _keysFile) const;
void write(std::string const& _pass, std::string const& _keysFile) const;
void write(h128 const& _key, std::string const& _keysFile) const;
void write(std::string const& _pass, std::string const& _keysFile) const; // TODO: all passwords should be a secure string.
void write(SecureFixedHash<16> const& _key, std::string const& _keysFile) const;
// Ethereum keys.
@ -159,7 +159,7 @@ private:
std::string m_defaultPasswordDeprecated;
mutable std::string m_keysFile;
mutable h128 m_keysFileKey;
mutable SecureFixedHash<16> m_keysFileKey;
mutable h256 m_master;
SecretStore m_store;
};

2
libp2p/Host.cpp

@ -809,7 +809,7 @@ bytes Host::saveNetwork() const
// else: TODO: use previous configuration if available
RLPStream ret(3);
ret << dev::p2p::c_protocolVersion << m_alias.secret();
ret << dev::p2p::c_protocolVersion << m_alias.secret().ref();
ret.appendList(count);
if (!!count)
ret.appendRaw(network.out(), count);

4
libp2p/RLPxHandshake.cpp

@ -40,7 +40,7 @@ void RLPXHandshake::writeAuth()
// E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0)
Secret staticShared;
crypto::ecdh::agree(m_host->m_alias.sec(), m_remote, staticShared);
sign(m_ecdhe.seckey(), staticShared ^ m_nonce).ref().copyTo(sig);
sign(m_ecdhe.seckey(), staticShared.makeInsecure() ^ m_nonce).ref().copyTo(sig);
sha3(m_ecdhe.pubkey().ref(), hepubk);
m_host->m_alias.pub().ref().copyTo(pubk);
m_nonce.ref().copyTo(nonce);
@ -92,7 +92,7 @@ void RLPXHandshake::readAuth()
Secret sharedSecret;
crypto::ecdh::agree(m_host->m_alias.sec(), m_remote, sharedSecret);
m_remoteEphemeral = recover(*(Signature*)sig.data(), sharedSecret ^ m_remoteNonce);
m_remoteEphemeral = recover(*(Signature*)sig.data(), sharedSecret.makeInsecure() ^ m_remoteNonce);
if (sha3(m_remoteEphemeral) != *(h256*)hepubk.data())
clog(NetP2PConnect) << "p2p.connect.ingress auth failed (invalid: hash mismatch) for" << m_socket->remoteEndpoint();

8
libwhisper/Message.cpp

@ -60,7 +60,7 @@ bool Message::openBroadcastEnvelope(Envelope const& _e, Topics const& _fk, bytes
for (unsigned i = 0; i < _e.topic().size(); ++i)
if (_e.topic()[i] == knownTopic[ti])
{
topicSecret = _fk[ti];
topicSecret = Secret(_fk[ti]);
topicIndex = i;
break;
}
@ -69,9 +69,9 @@ bool Message::openBroadcastEnvelope(Envelope const& _e, Topics const& _fk, bytes
return false;
unsigned index = topicIndex * 2;
h256 encryptedKey = h256(bytesConstRef(&(_e.data())).cropped(h256::size * index, h256::size));
Secret encryptedKey(bytesConstRef(&(_e.data())).cropped(h256::size * index, h256::size));
h256 salt = h256(bytesConstRef(&(_e.data())).cropped(h256::size * ++index, h256::size));
h256 key = generateGamma(topicSecret, salt) ^ encryptedKey;
Secret key = Secret(generateGamma(topicSecret, salt).makeInsecure() ^ encryptedKey.makeInsecure());
bytesConstRef cipherText = bytesConstRef(&(_e.data())).cropped(h256::size * 2 * _e.topic().size());
return decryptSym(key, cipherText, o_b);
}
@ -125,7 +125,7 @@ Envelope Message::seal(Secret const& _from, Topics const& _fullTopics, unsigned
for (h256 const& t: _fullTopics)
{
h256 salt = h256::random();
ret.m_data += (generateGamma(t, salt) ^ s).asBytes();
ret.m_data += (generateGamma(Secret(t), salt).makeInsecure() ^ s.makeInsecure()).ref().toBytes();
ret.m_data += salt.asBytes();
}

2
libwhisper/Message.h

@ -127,7 +127,7 @@ public:
private:
bool populate(bytes const& _data);
bool openBroadcastEnvelope(Envelope const& _e, Topics const& _t, bytes& o_b);
h256 generateGamma(h256 const& _key, h256 const& _salt) const { return sha3(_key ^ _salt); }
Secret generateGamma(Secret const& _key, h256 const& _salt) const { return sha3(_key ^ _salt); }
Public m_from;
Public m_to;

2
mix/FileIo.cpp

@ -187,7 +187,7 @@ QStringList FileIo::makePackage(QString const& _deploymentFolder)
bytes dapp = rlpStr.out();
dev::h256 dappHash = dev::sha3(dapp);
//encrypt
KeyPair key(dappHash);
KeyPair key((Secret(dappHash)));
Secp256k1PP enc;
enc.encrypt(key.pub(), dapp);

6
test/libdevcrypto/AES.cpp

@ -35,7 +35,7 @@ BOOST_AUTO_TEST_CASE(AesDecrypt)
{
cout << "AesDecrypt" << endl;
bytes seed = fromHex("2dbaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621");
KeyPair kp(sha3(aesDecrypt(&seed, "test")));
KeyPair kp(sha3Secure(aesDecrypt(&seed, "test")));
BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") == kp.address());
}
@ -43,7 +43,7 @@ BOOST_AUTO_TEST_CASE(AesDecryptWrongSeed)
{
cout << "AesDecryptWrongSeed" << endl;
bytes seed = fromHex("badaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621");
KeyPair kp(sha3(aesDecrypt(&seed, "test")));
KeyPair kp(sha3Secure(aesDecrypt(&seed, "test")));
BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") != kp.address());
}
@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE(AesDecryptWrongPassword)
{
cout << "AesDecryptWrongPassword" << endl;
bytes seed = fromHex("2dbaead416c20cfd00c2fc9f1788ff9f965a2000799c96a624767cb0e1e90d2d7191efdd92349226742fdc73d1d87e2d597536c4641098b9a89836c94f58a2ab4c525c27c4cb848b3e22ea245b2bc5c8c7beaa900b0c479253fc96fce7ffc621");
KeyPair kp(sha3(aesDecrypt(&seed, "badtest")));
KeyPair kp(sha3Secure(aesDecrypt(&seed, "badtest")));
BOOST_CHECK(Address("07746f871de684297923f933279555dda418f8a2") != kp.address());
}

32
test/libdevcrypto/SecretStore.cpp

@ -61,9 +61,9 @@ BOOST_AUTO_TEST_CASE(basic_tests)
SecretStore store(tmpDir.path());
h128 u = store.readKeyContent(js::write_string(o["json"], false));
cdebug << "read uuid" << u;
bytes s = store.secret(u, [&](){ return o["password"].get_str(); });
cdebug << "got secret" << toHex(s);
BOOST_REQUIRE_EQUAL(toHex(s), o["priv"].get_str());
bytesSec s = store.secret(u, [&](){ return o["password"].get_str(); });
cdebug << "got secret" << toHex(s.makeInsecure());
BOOST_REQUIRE_EQUAL(toHex(s.makeInsecure()), o["priv"].get_str());
}
}
@ -98,7 +98,7 @@ BOOST_AUTO_TEST_CASE(import_key_from_file)
uuid = store.importKey(importFile);
BOOST_CHECK(!!uuid);
BOOST_CHECK(contentsString(importFile) == keyData);
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; })));
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure()));
BOOST_CHECK_EQUAL(store.keys().size(), 1);
}
fs::remove(importFile);
@ -106,7 +106,7 @@ BOOST_AUTO_TEST_CASE(import_key_from_file)
{
SecretStore store(storeDir.path());
BOOST_CHECK_EQUAL(store.keys().size(), 1);
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; })));
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure()));
}
}
@ -121,15 +121,15 @@ BOOST_AUTO_TEST_CASE(import_secret)
{
SecretStore store(storeDir.path());
BOOST_CHECK_EQUAL(store.keys().size(), 0);
uuid = store.importSecret(fromHex(priv), password);
uuid = store.importSecret(bytesSec(fromHex(priv)), password);
BOOST_CHECK(!!uuid);
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; })));
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure()));
BOOST_CHECK_EQUAL(store.keys().size(), 1);
}
{
SecretStore store(storeDir.path());
BOOST_CHECK_EQUAL(store.keys().size(), 1);
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; })));
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure()));
}
}
}
@ -145,12 +145,12 @@ BOOST_AUTO_TEST_CASE(wrong_password)
{
SecretStore store(storeDir.path());
BOOST_CHECK_EQUAL(store.keys().size(), 0);
uuid = store.importSecret(fromHex(priv), password);
uuid = store.importSecret(bytesSec(fromHex(priv)), password);
BOOST_CHECK(!!uuid);
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; })));
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure()));
BOOST_CHECK_EQUAL(store.keys().size(), 1);
// password will not be queried
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return "abcdefg"; })));
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return "abcdefg"; }).makeInsecure()));
}
{
SecretStore store(storeDir.path());
@ -171,9 +171,9 @@ BOOST_AUTO_TEST_CASE(recode)
{
SecretStore store(storeDir.path());
BOOST_CHECK_EQUAL(store.keys().size(), 0);
uuid = store.importSecret(fromHex(priv), password);
uuid = store.importSecret(bytesSec(fromHex(priv)), password);
BOOST_CHECK(!!uuid);
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; })));
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return password; }).makeInsecure()));
BOOST_CHECK_EQUAL(store.keys().size(), 1);
}
{
@ -182,16 +182,16 @@ BOOST_AUTO_TEST_CASE(recode)
BOOST_CHECK(store.secret(uuid, [&](){ return "abcdefg"; }).empty());
BOOST_CHECK(store.recode(uuid, changedPassword, [&](){ return password; }));
BOOST_CHECK_EQUAL(store.keys().size(), 1);
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; })));
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }).makeInsecure()));
store.clearCache();
BOOST_CHECK(store.secret(uuid, [&](){ return password; }).empty());
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; })));
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }).makeInsecure()));
}
{
SecretStore store(storeDir.path());
BOOST_CHECK_EQUAL(store.keys().size(), 1);
BOOST_CHECK(store.secret(uuid, [&](){ return password; }).empty());
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; })));
BOOST_CHECK_EQUAL(priv, toHex(store.secret(uuid, [&](){ return changedPassword; }).makeInsecure()));
}
}

39
test/libdevcrypto/crypto.cpp

@ -87,7 +87,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_patch)
BOOST_AUTO_TEST_CASE(verify_secert)
{
h256 empty;
Secret empty;
KeyPair kNot(empty);
BOOST_REQUIRE(!kNot.address());
KeyPair k(sha3(empty));
@ -128,7 +128,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport)
bytes e(fromHex("0x01"));
e.resize(32);
int tests = 2;
while (sha3(&e, &e), secret = sha3(secret.asBytes()), tests--)
while (sha3(&e, &e), secret = sha3(secret), tests--)
{
KeyPair key(secret);
Public pkey = key.pub();
@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport)
Integer r = s_params.ConvertElementToInteger(rp);
Integer kInv = kInt.InverseMod(q);
Integer s = (kInv * (Integer(secret.asBytes().data(), 32)*r + heInt)) % q;
Integer s = (kInv * (Integer(secret.data(), 32) * r + heInt)) % q;
BOOST_REQUIRE(!!r && !!s);
Signature sig;
@ -311,7 +311,7 @@ BOOST_AUTO_TEST_CASE(ecies_kdf)
BOOST_REQUIRE(eKey1.toBytes() == eKey2.toBytes());
BOOST_REQUIRE(mKey1.toBytes() == mKey2.toBytes());
BOOST_REQUIRE((u256)h256(z1) > 0);
BOOST_REQUIRE(!!z1);
BOOST_REQUIRE(z1 == z2);
BOOST_REQUIRE(key1.size() > 0 && ((u512)h512(key1)) > 0);
@ -395,7 +395,7 @@ BOOST_AUTO_TEST_CASE(ecdh)
ECDH<ECP>::Domain dhA(s_curveOID);
Secret shared;
BOOST_REQUIRE(dhA.Agree(shared.data(), a.sec().data(), pubb));
BOOST_REQUIRE(dhA.Agree(shared.writable().data(), a.sec().data(), pubb));
BOOST_REQUIRE(shared);
}
@ -453,7 +453,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew)
bytesRef nonce(&auth[Signature::size + h256::size + Public::size], h256::size);
crypto::ecdh::agree(nodeA.sec(), nodeB.pub(), ssA);
sign(eA.seckey(), ssA ^ nonceA).ref().copyTo(sig);
sign(eA.seckey(), (ssA ^ nonceA).makeInsecure()).ref().copyTo(sig);
sha3(eA.pubkey().ref(), hepubk);
nodeA.pub().ref().copyTo(pubk);
nonceA.ref().copyTo(nonce);
@ -520,21 +520,21 @@ BOOST_AUTO_TEST_CASE(handshakeNew)
ess.ref().copyTo(keyMaterial.cropped(0, h256::size));
ssA.ref().copyTo(keyMaterial.cropped(h256::size, h256::size));
// auto token = sha3(ssA);
aEncryptK = sha3(keyMaterial);
aEncryptK = sha3Secure(keyMaterial);
aEncryptK.ref().copyTo(keyMaterial.cropped(h256::size, h256::size));
aMacK = sha3(keyMaterial);
aMacK = sha3Secure(keyMaterial);
keyMaterialBytes.resize(h256::size + authcipher.size());
keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size());
(aMacK ^ nonceBAck).ref().copyTo(keyMaterial);
bytesConstRef(&authcipher).copyTo(keyMaterial.cropped(h256::size, authcipher.size()));
aEgressMac = sha3(keyMaterial);
aEgressMac = sha3Secure(keyMaterial);
keyMaterialBytes.resize(h256::size + ackcipher.size());
keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size());
(aMacK ^ nonceA).ref().copyTo(keyMaterial);
bytesConstRef(&ackcipher).copyTo(keyMaterial.cropped(h256::size, ackcipher.size()));
aIngressMac = sha3(keyMaterial);
aIngressMac = sha3Secure(keyMaterial);
}
@ -573,7 +573,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew)
Secret ss;
s_secp256k1.agree(nodeB.sec(), nodeAAuth, ss);
eAAuth = recover(sigAuth, ss ^ nonceAAuth);
eAAuth = recover(sigAuth, (ss ^ nonceAAuth).makeInsecure());
// todo: test when this fails; means remote is bad or packet bits were flipped
BOOST_REQUIRE_EQUAL(heA, sha3(eAAuth));
BOOST_REQUIRE_EQUAL(eAAuth, eA.pubkey());
@ -588,22 +588,22 @@ BOOST_AUTO_TEST_CASE(handshakeNew)
ess.ref().copyTo(keyMaterial.cropped(0, h256::size));
ssB.ref().copyTo(keyMaterial.cropped(h256::size, h256::size));
// auto token = sha3(ssA);
bEncryptK = sha3(keyMaterial);
bEncryptK = sha3Secure(keyMaterial);
bEncryptK.ref().copyTo(keyMaterial.cropped(h256::size, h256::size));
bMacK = sha3(keyMaterial);
bMacK = sha3Secure(keyMaterial);
// todo: replace nonceB with decrypted nonceB
keyMaterialBytes.resize(h256::size + ackcipher.size());
keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size());
(bMacK ^ nonceAAuth).ref().copyTo(keyMaterial);
bytesConstRef(&ackcipher).copyTo(keyMaterial.cropped(h256::size, ackcipher.size()));
bEgressMac = sha3(keyMaterial);
bEgressMac = sha3Secure(keyMaterial);
keyMaterialBytes.resize(h256::size + authcipher.size());
keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size());
(bMacK ^ nonceB).ref().copyTo(keyMaterial);
bytesConstRef(&authcipher).copyTo(keyMaterial.cropped(h256::size, authcipher.size()));
bIngressMac = sha3(keyMaterial);
bIngressMac = sha3Secure(keyMaterial);
}
BOOST_REQUIRE_EQUAL(aEncryptK, bEncryptK);
@ -617,7 +617,7 @@ BOOST_AUTO_TEST_CASE(handshakeNew)
BOOST_AUTO_TEST_CASE(ecies_aes128_ctr_unaligned)
{
h128 encryptK(sha3("..."), h128::AlignLeft);
SecureFixedHash<16> encryptK(sha3("..."), h128::AlignLeft);
h256 egressMac(sha3("+++"));
// TESTING: send encrypt magic sequence
bytes magic {0x22,0x40,0x08,0x91};
@ -629,16 +629,17 @@ BOOST_AUTO_TEST_CASE(ecies_aes128_ctr_unaligned)
egressMac.ref().copyTo(bytesRef(&magicCipherAndMac).cropped(magicCipherAndMac.size() - 32, 32));
bytesConstRef cipher(&magicCipherAndMac[0], magicCipherAndMac.size() - 32);
bytes plaintext = decryptSymNoAuth(encryptK, h128(), cipher);
bytes plaintext = decryptSymNoAuth(encryptK, h128(), cipher).makeInsecure();
plaintext.resize(magic.size());
// @alex @subtly TODO: FIX: this check is pointless with the above line.
BOOST_REQUIRE(plaintext.size() > 0);
BOOST_REQUIRE(magic == plaintext);
}
BOOST_AUTO_TEST_CASE(ecies_aes128_ctr)
{
h128 k(sha3("0xAAAA"), h128::AlignLeft);
SecureFixedHash<16> k(sha3("0xAAAA"), h128::AlignLeft);
string m = "AAAAAAAAAAAAAAAA";
bytesConstRef msg((byte*)m.data(), m.size());
@ -646,7 +647,7 @@ BOOST_AUTO_TEST_CASE(ecies_aes128_ctr)
h128 iv;
tie(ciphertext, iv) = encryptSymNoAuth(k, msg);
bytes plaintext = decryptSymNoAuth(k, iv, &ciphertext);
bytes plaintext = decryptSymNoAuth(k, iv, &ciphertext).makeInsecure();
BOOST_REQUIRE_EQUAL(asString(plaintext), m);
}

14
test/libethcore/commonjs.cpp

@ -32,8 +32,8 @@ BOOST_AUTO_TEST_CASE(jsToPublic)
{
cnote << "Testing jsToPublic...";
KeyPair kp = KeyPair::create();
string string = toJS(kp.pub());
Public pub = dev::jsToPublic(string);
string s = toJS(kp.pub());
Public pub = dev::jsToPublic(s);
BOOST_CHECK_EQUAL(kp.pub(), pub);
}
@ -41,8 +41,8 @@ BOOST_AUTO_TEST_CASE(jsToAddress)
{
cnote << "Testing jsToPublic...";
KeyPair kp = KeyPair::create();
string string = toJS(kp.address());
Address address = dev::jsToAddress(string);
string s = toJS(kp.address());
Address address = dev::jsToAddress(s);
BOOST_CHECK_EQUAL(kp.address(), address);
}
@ -50,9 +50,9 @@ BOOST_AUTO_TEST_CASE(jsToSecret)
{
cnote << "Testing jsToPublic...";
KeyPair kp = KeyPair::create();
string string = toJS(kp.secret());
Secret secret = dev::jsToSecret(string);
BOOST_CHECK_EQUAL(kp.secret(), secret);
string s = toJS(kp.secret().makeInsecure());
Secret secret = dev::jsToSecret(s);
BOOST_CHECK_EQUAL(kp.secret().makeInsecure(), secret.makeInsecure());
}
BOOST_AUTO_TEST_SUITE_END()

Loading…
Cancel
Save